xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/val/validate_logicals.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/opcode.h"
18 #include "source/val/instruction.h"
19 #include "source/val/validate.h"
20 #include "source/val/validation_state.h"
21 
22 namespace spvtools {
23 namespace val {
24 
25 // Validates correctness of logical instructions.
LogicalsPass(ValidationState_t & _,const Instruction * inst)26 spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) {
27   const spv::Op opcode = inst->opcode();
28   const uint32_t result_type = inst->type_id();
29 
30   switch (opcode) {
31     case spv::Op::OpAny:
32     case spv::Op::OpAll: {
33       if (!_.IsBoolScalarType(result_type))
34         return _.diag(SPV_ERROR_INVALID_DATA, inst)
35                << "Expected bool scalar type as Result Type: "
36                << spvOpcodeString(opcode);
37 
38       const uint32_t vector_type = _.GetOperandTypeId(inst, 2);
39       if (!vector_type || !_.IsBoolVectorType(vector_type))
40         return _.diag(SPV_ERROR_INVALID_DATA, inst)
41                << "Expected operand to be vector bool: "
42                << spvOpcodeString(opcode);
43 
44       break;
45     }
46 
47     case spv::Op::OpIsNan:
48     case spv::Op::OpIsInf:
49     case spv::Op::OpIsFinite:
50     case spv::Op::OpIsNormal:
51     case spv::Op::OpSignBitSet: {
52       if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
53         return _.diag(SPV_ERROR_INVALID_DATA, inst)
54                << "Expected bool scalar or vector type as Result Type: "
55                << spvOpcodeString(opcode);
56 
57       const uint32_t operand_type = _.GetOperandTypeId(inst, 2);
58       if (!operand_type || (!_.IsFloatScalarType(operand_type) &&
59                             !_.IsFloatVectorType(operand_type)))
60         return _.diag(SPV_ERROR_INVALID_DATA, inst)
61                << "Expected operand to be scalar or vector float: "
62                << spvOpcodeString(opcode);
63 
64       if (_.GetDimension(result_type) != _.GetDimension(operand_type))
65         return _.diag(SPV_ERROR_INVALID_DATA, inst)
66                << "Expected vector sizes of Result Type and the operand to be "
67                   "equal: "
68                << spvOpcodeString(opcode);
69 
70       break;
71     }
72 
73     case spv::Op::OpFOrdEqual:
74     case spv::Op::OpFUnordEqual:
75     case spv::Op::OpFOrdNotEqual:
76     case spv::Op::OpFUnordNotEqual:
77     case spv::Op::OpFOrdLessThan:
78     case spv::Op::OpFUnordLessThan:
79     case spv::Op::OpFOrdGreaterThan:
80     case spv::Op::OpFUnordGreaterThan:
81     case spv::Op::OpFOrdLessThanEqual:
82     case spv::Op::OpFUnordLessThanEqual:
83     case spv::Op::OpFOrdGreaterThanEqual:
84     case spv::Op::OpFUnordGreaterThanEqual:
85     case spv::Op::OpLessOrGreater:
86     case spv::Op::OpOrdered:
87     case spv::Op::OpUnordered: {
88       if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
89         return _.diag(SPV_ERROR_INVALID_DATA, inst)
90                << "Expected bool scalar or vector type as Result Type: "
91                << spvOpcodeString(opcode);
92 
93       const uint32_t left_operand_type = _.GetOperandTypeId(inst, 2);
94       if (!left_operand_type || (!_.IsFloatScalarType(left_operand_type) &&
95                                  !_.IsFloatVectorType(left_operand_type)))
96         return _.diag(SPV_ERROR_INVALID_DATA, inst)
97                << "Expected operands to be scalar or vector float: "
98                << spvOpcodeString(opcode);
99 
100       if (_.GetDimension(result_type) != _.GetDimension(left_operand_type))
101         return _.diag(SPV_ERROR_INVALID_DATA, inst)
102                << "Expected vector sizes of Result Type and the operands to be "
103                   "equal: "
104                << spvOpcodeString(opcode);
105 
106       if (left_operand_type != _.GetOperandTypeId(inst, 3))
107         return _.diag(SPV_ERROR_INVALID_DATA, inst)
108                << "Expected left and right operands to have the same type: "
109                << spvOpcodeString(opcode);
110 
111       break;
112     }
113 
114     case spv::Op::OpLogicalEqual:
115     case spv::Op::OpLogicalNotEqual:
116     case spv::Op::OpLogicalOr:
117     case spv::Op::OpLogicalAnd: {
118       if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
119         return _.diag(SPV_ERROR_INVALID_DATA, inst)
120                << "Expected bool scalar or vector type as Result Type: "
121                << spvOpcodeString(opcode);
122 
123       if (result_type != _.GetOperandTypeId(inst, 2) ||
124           result_type != _.GetOperandTypeId(inst, 3))
125         return _.diag(SPV_ERROR_INVALID_DATA, inst)
126                << "Expected both operands to be of Result Type: "
127                << spvOpcodeString(opcode);
128 
129       break;
130     }
131 
132     case spv::Op::OpLogicalNot: {
133       if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
134         return _.diag(SPV_ERROR_INVALID_DATA, inst)
135                << "Expected bool scalar or vector type as Result Type: "
136                << spvOpcodeString(opcode);
137 
138       if (result_type != _.GetOperandTypeId(inst, 2))
139         return _.diag(SPV_ERROR_INVALID_DATA, inst)
140                << "Expected operand to be of Result Type: "
141                << spvOpcodeString(opcode);
142 
143       break;
144     }
145 
146     case spv::Op::OpSelect: {
147       uint32_t dimension = 1;
148       {
149         const Instruction* type_inst = _.FindDef(result_type);
150         assert(type_inst);
151 
152         const auto composites = _.features().select_between_composites;
153         auto fail = [&_, composites, inst, opcode]() -> spv_result_t {
154           return _.diag(SPV_ERROR_INVALID_DATA, inst)
155                  << "Expected scalar or "
156                  << (composites ? "composite" : "vector")
157                  << " type as Result Type: " << spvOpcodeString(opcode);
158         };
159 
160         const spv::Op type_opcode = type_inst->opcode();
161         switch (type_opcode) {
162           case spv::Op::OpTypeUntypedPointerKHR:
163           case spv::Op::OpTypePointer: {
164             if (_.addressing_model() == spv::AddressingModel::Logical &&
165                 !_.HasCapability(
166                     spv::Capability::VariablePointersStorageBuffer))
167               return _.diag(SPV_ERROR_INVALID_DATA, inst)
168                      << "Using pointers with OpSelect requires capability "
169                      << "VariablePointers or VariablePointersStorageBuffer";
170             break;
171           }
172 
173           case spv::Op::OpTypeSampledImage:
174           case spv::Op::OpTypeImage:
175           case spv::Op::OpTypeSampler: {
176             if (!_.HasCapability(spv::Capability::BindlessTextureNV))
177               return _.diag(SPV_ERROR_INVALID_DATA, inst)
178                      << "Using image/sampler with OpSelect requires capability "
179                      << "BindlessTextureNV";
180             break;
181           }
182 
183           case spv::Op::OpTypeVector: {
184             dimension = type_inst->word(3);
185             break;
186           }
187 
188           case spv::Op::OpTypeBool:
189           case spv::Op::OpTypeInt:
190           case spv::Op::OpTypeFloat: {
191             break;
192           }
193 
194           // Not RuntimeArray because of other rules.
195           case spv::Op::OpTypeArray:
196           case spv::Op::OpTypeMatrix:
197           case spv::Op::OpTypeStruct: {
198             if (!composites) return fail();
199             break;
200           }
201 
202           default:
203             return fail();
204         }
205 
206         const uint32_t condition_type = _.GetOperandTypeId(inst, 2);
207         const uint32_t left_type = _.GetOperandTypeId(inst, 3);
208         const uint32_t right_type = _.GetOperandTypeId(inst, 4);
209 
210         if (!condition_type || (!_.IsBoolScalarType(condition_type) &&
211                                 !_.IsBoolVectorType(condition_type)))
212           return _.diag(SPV_ERROR_INVALID_DATA, inst)
213                  << "Expected bool scalar or vector type as condition: "
214                  << spvOpcodeString(opcode);
215 
216         if (_.GetDimension(condition_type) != dimension) {
217           // If the condition is a vector type, then the result must also be a
218           // vector with matching dimensions. In SPIR-V 1.4, a scalar condition
219           // can be used to select between vector types. |composites| is a
220           // proxy for SPIR-V 1.4 functionality.
221           if (!composites || _.IsBoolVectorType(condition_type)) {
222             return _.diag(SPV_ERROR_INVALID_DATA, inst)
223                    << "Expected vector sizes of Result Type and the condition "
224                       "to be equal: "
225                    << spvOpcodeString(opcode);
226           }
227         }
228 
229         if (result_type != left_type || result_type != right_type)
230           return _.diag(SPV_ERROR_INVALID_DATA, inst)
231                  << "Expected both objects to be of Result Type: "
232                  << spvOpcodeString(opcode);
233 
234         break;
235       }
236     }
237 
238     case spv::Op::OpIEqual:
239     case spv::Op::OpINotEqual:
240     case spv::Op::OpUGreaterThan:
241     case spv::Op::OpUGreaterThanEqual:
242     case spv::Op::OpULessThan:
243     case spv::Op::OpULessThanEqual:
244     case spv::Op::OpSGreaterThan:
245     case spv::Op::OpSGreaterThanEqual:
246     case spv::Op::OpSLessThan:
247     case spv::Op::OpSLessThanEqual: {
248       if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
249         return _.diag(SPV_ERROR_INVALID_DATA, inst)
250                << "Expected bool scalar or vector type as Result Type: "
251                << spvOpcodeString(opcode);
252 
253       const uint32_t left_type = _.GetOperandTypeId(inst, 2);
254       const uint32_t right_type = _.GetOperandTypeId(inst, 3);
255 
256       if (!left_type ||
257           (!_.IsIntScalarType(left_type) && !_.IsIntVectorType(left_type)))
258         return _.diag(SPV_ERROR_INVALID_DATA, inst)
259                << "Expected operands to be scalar or vector int: "
260                << spvOpcodeString(opcode);
261 
262       if (_.GetDimension(result_type) != _.GetDimension(left_type))
263         return _.diag(SPV_ERROR_INVALID_DATA, inst)
264                << "Expected vector sizes of Result Type and the operands to be"
265                << " equal: " << spvOpcodeString(opcode);
266 
267       if (!right_type ||
268           (!_.IsIntScalarType(right_type) && !_.IsIntVectorType(right_type)))
269         return _.diag(SPV_ERROR_INVALID_DATA, inst)
270                << "Expected operands to be scalar or vector int: "
271                << spvOpcodeString(opcode);
272 
273       if (_.GetDimension(result_type) != _.GetDimension(right_type))
274         return _.diag(SPV_ERROR_INVALID_DATA, inst)
275                << "Expected vector sizes of Result Type and the operands to be"
276                << " equal: " << spvOpcodeString(opcode);
277 
278       if (_.GetBitWidth(left_type) != _.GetBitWidth(right_type))
279         return _.diag(SPV_ERROR_INVALID_DATA, inst)
280                << "Expected both operands to have the same component bit "
281                   "width: "
282                << spvOpcodeString(opcode);
283 
284       break;
285     }
286 
287     default:
288       break;
289   }
290 
291   return SPV_SUCCESS;
292 }
293 
294 }  // namespace val
295 }  // namespace spvtools
296