Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 1 | // Copyright (c) 2017 Google Inc. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | // Validates correctness of bitwise instructions. |
| 16 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 17 | #include "source/diagnostic.h" |
| 18 | #include "source/opcode.h" |
Nicolas Capens | 4d6c93d | 2022-03-28 15:58:15 -0400 | [diff] [blame^] | 19 | #include "source/spirv_target_env.h" |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 20 | #include "source/val/instruction.h" |
Nicolas Capens | 4d6c93d | 2022-03-28 15:58:15 -0400 | [diff] [blame^] | 21 | #include "source/val/validate.h" |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 22 | #include "source/val/validation_state.h" |
| 23 | |
| 24 | namespace spvtools { |
| 25 | namespace val { |
| 26 | |
Nicolas Capens | 4d6c93d | 2022-03-28 15:58:15 -0400 | [diff] [blame^] | 27 | // Validates when base and result need to be the same type |
| 28 | spv_result_t ValidateBaseType(ValidationState_t& _, const Instruction* inst, |
| 29 | const uint32_t base_type) { |
| 30 | const SpvOp opcode = inst->opcode(); |
| 31 | |
| 32 | if (!_.IsIntScalarType(base_type) && !_.IsIntVectorType(base_type)) { |
| 33 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 34 | << _.VkErrorID(4781) |
| 35 | << "Expected int scalar or vector type for Base operand: " |
| 36 | << spvOpcodeString(opcode); |
| 37 | } |
| 38 | |
| 39 | // Vulkan has a restriction to 32 bit for base |
| 40 | if (spvIsVulkanEnv(_.context()->target_env)) { |
| 41 | if (_.GetBitWidth(base_type) != 32) { |
| 42 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 43 | << _.VkErrorID(4781) |
| 44 | << "Expected 32-bit int type for Base operand: " |
| 45 | << spvOpcodeString(opcode); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | // OpBitCount just needs same number of components |
| 50 | if (base_type != inst->type_id() && opcode != SpvOpBitCount) { |
| 51 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 52 | << "Expected Base Type to be equal to Result Type: " |
| 53 | << spvOpcodeString(opcode); |
| 54 | } |
| 55 | |
| 56 | return SPV_SUCCESS; |
| 57 | } |
| 58 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 59 | // Validates correctness of bitwise instructions. |
| 60 | spv_result_t BitwisePass(ValidationState_t& _, const Instruction* inst) { |
| 61 | const SpvOp opcode = inst->opcode(); |
| 62 | const uint32_t result_type = inst->type_id(); |
| 63 | |
| 64 | switch (opcode) { |
| 65 | case SpvOpShiftRightLogical: |
| 66 | case SpvOpShiftRightArithmetic: |
| 67 | case SpvOpShiftLeftLogical: { |
| 68 | if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type)) |
| 69 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 70 | << "Expected int scalar or vector type as Result Type: " |
| 71 | << spvOpcodeString(opcode); |
| 72 | |
| 73 | const uint32_t result_dimension = _.GetDimension(result_type); |
| 74 | const uint32_t base_type = _.GetOperandTypeId(inst, 2); |
| 75 | const uint32_t shift_type = _.GetOperandTypeId(inst, 3); |
| 76 | |
| 77 | if (!base_type || |
| 78 | (!_.IsIntScalarType(base_type) && !_.IsIntVectorType(base_type))) |
| 79 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 80 | << "Expected Base to be int scalar or vector: " |
| 81 | << spvOpcodeString(opcode); |
| 82 | |
| 83 | if (_.GetDimension(base_type) != result_dimension) |
| 84 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 85 | << "Expected Base to have the same dimension " |
| 86 | << "as Result Type: " << spvOpcodeString(opcode); |
| 87 | |
| 88 | if (_.GetBitWidth(base_type) != _.GetBitWidth(result_type)) |
| 89 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 90 | << "Expected Base to have the same bit width " |
| 91 | << "as Result Type: " << spvOpcodeString(opcode); |
| 92 | |
| 93 | if (!shift_type || |
| 94 | (!_.IsIntScalarType(shift_type) && !_.IsIntVectorType(shift_type))) |
| 95 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 96 | << "Expected Shift to be int scalar or vector: " |
| 97 | << spvOpcodeString(opcode); |
| 98 | |
| 99 | if (_.GetDimension(shift_type) != result_dimension) |
| 100 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 101 | << "Expected Shift to have the same dimension " |
| 102 | << "as Result Type: " << spvOpcodeString(opcode); |
| 103 | break; |
| 104 | } |
| 105 | |
| 106 | case SpvOpBitwiseOr: |
| 107 | case SpvOpBitwiseXor: |
| 108 | case SpvOpBitwiseAnd: |
| 109 | case SpvOpNot: { |
| 110 | if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type)) |
| 111 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 112 | << "Expected int scalar or vector type as Result Type: " |
| 113 | << spvOpcodeString(opcode); |
| 114 | |
| 115 | const uint32_t result_dimension = _.GetDimension(result_type); |
| 116 | const uint32_t result_bit_width = _.GetBitWidth(result_type); |
| 117 | |
| 118 | for (size_t operand_index = 2; operand_index < inst->operands().size(); |
| 119 | ++operand_index) { |
| 120 | const uint32_t type_id = _.GetOperandTypeId(inst, operand_index); |
| 121 | if (!type_id || |
| 122 | (!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id))) |
| 123 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 124 | << "Expected int scalar or vector as operand: " |
| 125 | << spvOpcodeString(opcode) << " operand index " |
| 126 | << operand_index; |
| 127 | |
| 128 | if (_.GetDimension(type_id) != result_dimension) |
| 129 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 130 | << "Expected operands to have the same dimension " |
| 131 | << "as Result Type: " << spvOpcodeString(opcode) |
| 132 | << " operand index " << operand_index; |
| 133 | |
| 134 | if (_.GetBitWidth(type_id) != result_bit_width) |
| 135 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 136 | << "Expected operands to have the same bit width " |
| 137 | << "as Result Type: " << spvOpcodeString(opcode) |
| 138 | << " operand index " << operand_index; |
| 139 | } |
| 140 | break; |
| 141 | } |
| 142 | |
| 143 | case SpvOpBitFieldInsert: { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 144 | const uint32_t base_type = _.GetOperandTypeId(inst, 2); |
| 145 | const uint32_t insert_type = _.GetOperandTypeId(inst, 3); |
| 146 | const uint32_t offset_type = _.GetOperandTypeId(inst, 4); |
| 147 | const uint32_t count_type = _.GetOperandTypeId(inst, 5); |
| 148 | |
Nicolas Capens | 4d6c93d | 2022-03-28 15:58:15 -0400 | [diff] [blame^] | 149 | if (spv_result_t error = ValidateBaseType(_, inst, base_type)) { |
| 150 | return error; |
| 151 | } |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 152 | |
| 153 | if (insert_type != result_type) |
| 154 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 155 | << "Expected Insert Type to be equal to Result Type: " |
| 156 | << spvOpcodeString(opcode); |
| 157 | |
| 158 | if (!offset_type || !_.IsIntScalarType(offset_type)) |
| 159 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 160 | << "Expected Offset Type to be int scalar: " |
| 161 | << spvOpcodeString(opcode); |
| 162 | |
| 163 | if (!count_type || !_.IsIntScalarType(count_type)) |
| 164 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 165 | << "Expected Count Type to be int scalar: " |
| 166 | << spvOpcodeString(opcode); |
| 167 | break; |
| 168 | } |
| 169 | |
| 170 | case SpvOpBitFieldSExtract: |
| 171 | case SpvOpBitFieldUExtract: { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 172 | const uint32_t base_type = _.GetOperandTypeId(inst, 2); |
| 173 | const uint32_t offset_type = _.GetOperandTypeId(inst, 3); |
| 174 | const uint32_t count_type = _.GetOperandTypeId(inst, 4); |
| 175 | |
Nicolas Capens | 4d6c93d | 2022-03-28 15:58:15 -0400 | [diff] [blame^] | 176 | if (spv_result_t error = ValidateBaseType(_, inst, base_type)) { |
| 177 | return error; |
| 178 | } |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 179 | |
| 180 | if (!offset_type || !_.IsIntScalarType(offset_type)) |
| 181 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 182 | << "Expected Offset Type to be int scalar: " |
| 183 | << spvOpcodeString(opcode); |
| 184 | |
| 185 | if (!count_type || !_.IsIntScalarType(count_type)) |
| 186 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 187 | << "Expected Count Type to be int scalar: " |
| 188 | << spvOpcodeString(opcode); |
| 189 | break; |
| 190 | } |
| 191 | |
| 192 | case SpvOpBitReverse: { |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 193 | const uint32_t base_type = _.GetOperandTypeId(inst, 2); |
| 194 | |
Nicolas Capens | 4d6c93d | 2022-03-28 15:58:15 -0400 | [diff] [blame^] | 195 | if (spv_result_t error = ValidateBaseType(_, inst, base_type)) { |
| 196 | return error; |
| 197 | } |
| 198 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 199 | break; |
| 200 | } |
| 201 | |
| 202 | case SpvOpBitCount: { |
| 203 | if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type)) |
| 204 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 205 | << "Expected int scalar or vector type as Result Type: " |
| 206 | << spvOpcodeString(opcode); |
| 207 | |
| 208 | const uint32_t base_type = _.GetOperandTypeId(inst, 2); |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 209 | const uint32_t base_dimension = _.GetDimension(base_type); |
| 210 | const uint32_t result_dimension = _.GetDimension(result_type); |
| 211 | |
Nicolas Capens | 4d6c93d | 2022-03-28 15:58:15 -0400 | [diff] [blame^] | 212 | if (spv_result_t error = ValidateBaseType(_, inst, base_type)) { |
| 213 | return error; |
| 214 | } |
| 215 | |
Chris Forbes | cc5697f | 2019-01-30 11:54:08 -0800 | [diff] [blame] | 216 | if (base_dimension != result_dimension) |
| 217 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
| 218 | << "Expected Base dimension to be equal to Result Type " |
| 219 | "dimension: " |
| 220 | << spvOpcodeString(opcode); |
| 221 | break; |
| 222 | } |
| 223 | |
| 224 | default: |
| 225 | break; |
| 226 | } |
| 227 | |
| 228 | return SPV_SUCCESS; |
| 229 | } |
| 230 | |
| 231 | } // namespace val |
| 232 | } // namespace spvtools |