Roll external/abseil_cpp/ 8f739d18b..917bfee46 (2 commits) (#5887)
[KhronosGroup/SPIRV-Tools.git] / source / val / validate_logicals.cpp
blob8a2e5d8c42e584d0092631c7961b16e8d5a4b5ac
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.
15 // Validates correctness of logical SPIR-V instructions.
17 #include "source/opcode.h"
18 #include "source/val/instruction.h"
19 #include "source/val/validate.h"
20 #include "source/val/validation_state.h"
22 namespace spvtools {
23 namespace val {
25 // Validates correctness of logical instructions.
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();
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);
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);
44 break;
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);
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);
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);
70 break;
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);
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);
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);
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);
111 break;
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);
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);
129 break;
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);
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);
143 break;
146 case spv::Op::OpSelect: {
147 uint32_t dimension = 1;
149 const Instruction* type_inst = _.FindDef(result_type);
150 assert(type_inst);
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);
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;
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;
183 case spv::Op::OpTypeVector: {
184 dimension = type_inst->word(3);
185 break;
188 case spv::Op::OpTypeBool:
189 case spv::Op::OpTypeInt:
190 case spv::Op::OpTypeFloat: {
191 break;
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;
202 default:
203 return fail();
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);
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);
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);
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);
234 break;
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);
253 const uint32_t left_type = _.GetOperandTypeId(inst, 2);
254 const uint32_t right_type = _.GetOperandTypeId(inst, 3);
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);
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);
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);
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);
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);
284 break;
287 default:
288 break;
291 return SPV_SUCCESS;
294 } // namespace val
295 } // namespace spvtools