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 logical SPIR-V instructions. |
16 | |
17 | #include "source/val/validate.h" |
18 | |
19 | #include "source/diagnostic.h" |
20 | #include "source/opcode.h" |
21 | #include "source/val/instruction.h" |
22 | #include "source/val/validation_state.h" |
23 | |
24 | namespace spvtools { |
25 | namespace val { |
26 | |
27 | // Validates correctness of logical instructions. |
28 | spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) { |
29 | const SpvOp opcode = inst->opcode(); |
30 | const uint32_t result_type = inst->type_id(); |
31 | |
32 | switch (opcode) { |
33 | case SpvOpAny: |
34 | case SpvOpAll: { |
35 | if (!_.IsBoolScalarType(result_type)) |
36 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
37 | << "Expected bool scalar type as Result Type: " |
38 | << spvOpcodeString(opcode); |
39 | |
40 | const uint32_t vector_type = _.GetOperandTypeId(inst, 2); |
41 | if (!vector_type || !_.IsBoolVectorType(vector_type)) |
42 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
43 | << "Expected operand to be vector bool: " |
44 | << spvOpcodeString(opcode); |
45 | |
46 | break; |
47 | } |
48 | |
49 | case SpvOpIsNan: |
50 | case SpvOpIsInf: |
51 | case SpvOpIsFinite: |
52 | case SpvOpIsNormal: |
53 | case SpvOpSignBitSet: { |
54 | if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type)) |
55 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
56 | << "Expected bool scalar or vector type as Result Type: " |
57 | << spvOpcodeString(opcode); |
58 | |
59 | const uint32_t operand_type = _.GetOperandTypeId(inst, 2); |
60 | if (!operand_type || (!_.IsFloatScalarType(operand_type) && |
61 | !_.IsFloatVectorType(operand_type))) |
62 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
63 | << "Expected operand to be scalar or vector float: " |
64 | << spvOpcodeString(opcode); |
65 | |
66 | if (_.GetDimension(result_type) != _.GetDimension(operand_type)) |
67 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
68 | << "Expected vector sizes of Result Type and the operand to be " |
69 | "equal: " |
70 | << spvOpcodeString(opcode); |
71 | |
72 | break; |
73 | } |
74 | |
75 | case SpvOpFOrdEqual: |
76 | case SpvOpFUnordEqual: |
77 | case SpvOpFOrdNotEqual: |
78 | case SpvOpFUnordNotEqual: |
79 | case SpvOpFOrdLessThan: |
80 | case SpvOpFUnordLessThan: |
81 | case SpvOpFOrdGreaterThan: |
82 | case SpvOpFUnordGreaterThan: |
83 | case SpvOpFOrdLessThanEqual: |
84 | case SpvOpFUnordLessThanEqual: |
85 | case SpvOpFOrdGreaterThanEqual: |
86 | case SpvOpFUnordGreaterThanEqual: |
87 | case SpvOpLessOrGreater: |
88 | case SpvOpOrdered: |
89 | case SpvOpUnordered: { |
90 | if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type)) |
91 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
92 | << "Expected bool scalar or vector type as Result Type: " |
93 | << spvOpcodeString(opcode); |
94 | |
95 | const uint32_t left_operand_type = _.GetOperandTypeId(inst, 2); |
96 | if (!left_operand_type || (!_.IsFloatScalarType(left_operand_type) && |
97 | !_.IsFloatVectorType(left_operand_type))) |
98 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
99 | << "Expected operands to be scalar or vector float: " |
100 | << spvOpcodeString(opcode); |
101 | |
102 | if (_.GetDimension(result_type) != _.GetDimension(left_operand_type)) |
103 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
104 | << "Expected vector sizes of Result Type and the operands to be " |
105 | "equal: " |
106 | << spvOpcodeString(opcode); |
107 | |
108 | if (left_operand_type != _.GetOperandTypeId(inst, 3)) |
109 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
110 | << "Expected left and right operands to have the same type: " |
111 | << spvOpcodeString(opcode); |
112 | |
113 | break; |
114 | } |
115 | |
116 | case SpvOpLogicalEqual: |
117 | case SpvOpLogicalNotEqual: |
118 | case SpvOpLogicalOr: |
119 | case SpvOpLogicalAnd: { |
120 | if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type)) |
121 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
122 | << "Expected bool scalar or vector type as Result Type: " |
123 | << spvOpcodeString(opcode); |
124 | |
125 | if (result_type != _.GetOperandTypeId(inst, 2) || |
126 | result_type != _.GetOperandTypeId(inst, 3)) |
127 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
128 | << "Expected both operands to be of Result Type: " |
129 | << spvOpcodeString(opcode); |
130 | |
131 | break; |
132 | } |
133 | |
134 | case SpvOpLogicalNot: { |
135 | if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type)) |
136 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
137 | << "Expected bool scalar or vector type as Result Type: " |
138 | << spvOpcodeString(opcode); |
139 | |
140 | if (result_type != _.GetOperandTypeId(inst, 2)) |
141 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
142 | << "Expected operand to be of Result Type: " |
143 | << spvOpcodeString(opcode); |
144 | |
145 | break; |
146 | } |
147 | |
148 | case SpvOpSelect: { |
149 | uint32_t dimension = 1; |
150 | { |
151 | const Instruction* type_inst = _.FindDef(result_type); |
152 | assert(type_inst); |
153 | |
154 | const auto composites = _.features().select_between_composites; |
155 | auto fail = [&_, composites, inst, opcode]() -> spv_result_t { |
156 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
157 | << "Expected scalar or " |
158 | << (composites ? "composite" : "vector" ) |
159 | << " type as Result Type: " << spvOpcodeString(opcode); |
160 | }; |
161 | |
162 | const SpvOp type_opcode = type_inst->opcode(); |
163 | switch (type_opcode) { |
164 | case SpvOpTypePointer: { |
165 | if (_.addressing_model() == SpvAddressingModelLogical && |
166 | !_.features().variable_pointers && |
167 | !_.features().variable_pointers_storage_buffer) |
168 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
169 | << "Using pointers with OpSelect requires capability " |
170 | << "VariablePointers or VariablePointersStorageBuffer" ; |
171 | break; |
172 | } |
173 | |
174 | case SpvOpTypeVector: { |
175 | dimension = type_inst->word(3); |
176 | break; |
177 | } |
178 | |
179 | case SpvOpTypeBool: |
180 | case SpvOpTypeInt: |
181 | case SpvOpTypeFloat: { |
182 | break; |
183 | } |
184 | |
185 | // Not RuntimeArray because of other rules. |
186 | case SpvOpTypeArray: |
187 | case SpvOpTypeMatrix: |
188 | case SpvOpTypeStruct: { |
189 | if (!composites) return fail(); |
190 | break; |
191 | }; |
192 | |
193 | default: |
194 | return fail(); |
195 | } |
196 | |
197 | const uint32_t condition_type = _.GetOperandTypeId(inst, 2); |
198 | const uint32_t left_type = _.GetOperandTypeId(inst, 3); |
199 | const uint32_t right_type = _.GetOperandTypeId(inst, 4); |
200 | |
201 | if (!condition_type || (!_.IsBoolScalarType(condition_type) && |
202 | !_.IsBoolVectorType(condition_type))) |
203 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
204 | << "Expected bool scalar or vector type as condition: " |
205 | << spvOpcodeString(opcode); |
206 | |
207 | if (_.GetDimension(condition_type) != dimension) { |
208 | // If the condition is a vector type, then the result must also be a |
209 | // vector with matching dimensions. In SPIR-V 1.4, a scalar condition |
210 | // can be used to select between vector types. |composites| is a |
211 | // proxy for SPIR-V 1.4 functionality. |
212 | if (!composites || _.IsBoolVectorType(condition_type)) { |
213 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
214 | << "Expected vector sizes of Result Type and the condition " |
215 | "to be equal: " |
216 | << spvOpcodeString(opcode); |
217 | } |
218 | } |
219 | |
220 | if (result_type != left_type || result_type != right_type) |
221 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
222 | << "Expected both objects to be of Result Type: " |
223 | << spvOpcodeString(opcode); |
224 | |
225 | break; |
226 | } |
227 | } |
228 | |
229 | case SpvOpIEqual: |
230 | case SpvOpINotEqual: |
231 | case SpvOpUGreaterThan: |
232 | case SpvOpUGreaterThanEqual: |
233 | case SpvOpULessThan: |
234 | case SpvOpULessThanEqual: |
235 | case SpvOpSGreaterThan: |
236 | case SpvOpSGreaterThanEqual: |
237 | case SpvOpSLessThan: |
238 | case SpvOpSLessThanEqual: { |
239 | if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type)) |
240 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
241 | << "Expected bool scalar or vector type as Result Type: " |
242 | << spvOpcodeString(opcode); |
243 | |
244 | const uint32_t left_type = _.GetOperandTypeId(inst, 2); |
245 | const uint32_t right_type = _.GetOperandTypeId(inst, 3); |
246 | |
247 | if (!left_type || |
248 | (!_.IsIntScalarType(left_type) && !_.IsIntVectorType(left_type))) |
249 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
250 | << "Expected operands to be scalar or vector int: " |
251 | << spvOpcodeString(opcode); |
252 | |
253 | if (_.GetDimension(result_type) != _.GetDimension(left_type)) |
254 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
255 | << "Expected vector sizes of Result Type and the operands to be" |
256 | << " equal: " << spvOpcodeString(opcode); |
257 | |
258 | if (!right_type || |
259 | (!_.IsIntScalarType(right_type) && !_.IsIntVectorType(right_type))) |
260 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
261 | << "Expected operands to be scalar or vector int: " |
262 | << spvOpcodeString(opcode); |
263 | |
264 | if (_.GetDimension(result_type) != _.GetDimension(right_type)) |
265 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
266 | << "Expected vector sizes of Result Type and the operands to be" |
267 | << " equal: " << spvOpcodeString(opcode); |
268 | |
269 | if (_.GetBitWidth(left_type) != _.GetBitWidth(right_type)) |
270 | return _.diag(SPV_ERROR_INVALID_DATA, inst) |
271 | << "Expected both operands to have the same component bit " |
272 | "width: " |
273 | << spvOpcodeString(opcode); |
274 | |
275 | break; |
276 | } |
277 | |
278 | default: |
279 | break; |
280 | } |
281 | |
282 | return SPV_SUCCESS; |
283 | } |
284 | |
285 | } // namespace val |
286 | } // namespace spvtools |
287 | |