• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::OpTypePointer: {
163             if (_.addressing_model() == spv::AddressingModel::Logical &&
164                 !_.features().variable_pointers)
165               return _.diag(SPV_ERROR_INVALID_DATA, inst)
166                      << "Using pointers with OpSelect requires capability "
167                      << "VariablePointers or VariablePointersStorageBuffer";
168             break;
169           }
170 
171           case spv::Op::OpTypeSampledImage:
172           case spv::Op::OpTypeImage:
173           case spv::Op::OpTypeSampler: {
174             if (!_.HasCapability(spv::Capability::BindlessTextureNV))
175               return _.diag(SPV_ERROR_INVALID_DATA, inst)
176                      << "Using image/sampler with OpSelect requires capability "
177                      << "BindlessTextureNV";
178             break;
179           }
180 
181           case spv::Op::OpTypeVector: {
182             dimension = type_inst->word(3);
183             break;
184           }
185 
186           case spv::Op::OpTypeBool:
187           case spv::Op::OpTypeInt:
188           case spv::Op::OpTypeFloat: {
189             break;
190           }
191 
192           // Not RuntimeArray because of other rules.
193           case spv::Op::OpTypeArray:
194           case spv::Op::OpTypeMatrix:
195           case spv::Op::OpTypeStruct: {
196             if (!composites) return fail();
197             break;
198           }
199 
200           default:
201             return fail();
202         }
203 
204         const uint32_t condition_type = _.GetOperandTypeId(inst, 2);
205         const uint32_t left_type = _.GetOperandTypeId(inst, 3);
206         const uint32_t right_type = _.GetOperandTypeId(inst, 4);
207 
208         if (!condition_type || (!_.IsBoolScalarType(condition_type) &&
209                                 !_.IsBoolVectorType(condition_type)))
210           return _.diag(SPV_ERROR_INVALID_DATA, inst)
211                  << "Expected bool scalar or vector type as condition: "
212                  << spvOpcodeString(opcode);
213 
214         if (_.GetDimension(condition_type) != dimension) {
215           // If the condition is a vector type, then the result must also be a
216           // vector with matching dimensions. In SPIR-V 1.4, a scalar condition
217           // can be used to select between vector types. |composites| is a
218           // proxy for SPIR-V 1.4 functionality.
219           if (!composites || _.IsBoolVectorType(condition_type)) {
220             return _.diag(SPV_ERROR_INVALID_DATA, inst)
221                    << "Expected vector sizes of Result Type and the condition "
222                       "to be equal: "
223                    << spvOpcodeString(opcode);
224           }
225         }
226 
227         if (result_type != left_type || result_type != right_type)
228           return _.diag(SPV_ERROR_INVALID_DATA, inst)
229                  << "Expected both objects to be of Result Type: "
230                  << spvOpcodeString(opcode);
231 
232         break;
233       }
234     }
235 
236     case spv::Op::OpIEqual:
237     case spv::Op::OpINotEqual:
238     case spv::Op::OpUGreaterThan:
239     case spv::Op::OpUGreaterThanEqual:
240     case spv::Op::OpULessThan:
241     case spv::Op::OpULessThanEqual:
242     case spv::Op::OpSGreaterThan:
243     case spv::Op::OpSGreaterThanEqual:
244     case spv::Op::OpSLessThan:
245     case spv::Op::OpSLessThanEqual: {
246       if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
247         return _.diag(SPV_ERROR_INVALID_DATA, inst)
248                << "Expected bool scalar or vector type as Result Type: "
249                << spvOpcodeString(opcode);
250 
251       const uint32_t left_type = _.GetOperandTypeId(inst, 2);
252       const uint32_t right_type = _.GetOperandTypeId(inst, 3);
253 
254       if (!left_type ||
255           (!_.IsIntScalarType(left_type) && !_.IsIntVectorType(left_type)))
256         return _.diag(SPV_ERROR_INVALID_DATA, inst)
257                << "Expected operands to be scalar or vector int: "
258                << spvOpcodeString(opcode);
259 
260       if (_.GetDimension(result_type) != _.GetDimension(left_type))
261         return _.diag(SPV_ERROR_INVALID_DATA, inst)
262                << "Expected vector sizes of Result Type and the operands to be"
263                << " equal: " << spvOpcodeString(opcode);
264 
265       if (!right_type ||
266           (!_.IsIntScalarType(right_type) && !_.IsIntVectorType(right_type)))
267         return _.diag(SPV_ERROR_INVALID_DATA, inst)
268                << "Expected operands to be scalar or vector int: "
269                << spvOpcodeString(opcode);
270 
271       if (_.GetDimension(result_type) != _.GetDimension(right_type))
272         return _.diag(SPV_ERROR_INVALID_DATA, inst)
273                << "Expected vector sizes of Result Type and the operands to be"
274                << " equal: " << spvOpcodeString(opcode);
275 
276       if (_.GetBitWidth(left_type) != _.GetBitWidth(right_type))
277         return _.diag(SPV_ERROR_INVALID_DATA, inst)
278                << "Expected both operands to have the same component bit "
279                   "width: "
280                << spvOpcodeString(opcode);
281 
282       break;
283     }
284 
285     default:
286       break;
287   }
288 
289   return SPV_SUCCESS;
290 }
291 
292 }  // namespace val
293 }  // namespace spvtools
294