1 // Copyright (c) 2017 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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"
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();
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
);
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 "
68 << spvOpcodeString(opcode
);
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 "
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
);
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
);
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
);
146 case spv::Op::OpSelect
: {
147 uint32_t dimension
= 1;
149 const Instruction
* type_inst
= _
.FindDef(result_type
);
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
&&
166 spv::Capability::VariablePointersStorageBuffer
))
167 return _
.diag(SPV_ERROR_INVALID_DATA
, inst
)
168 << "Using pointers with OpSelect requires capability "
169 << "VariablePointers or VariablePointersStorageBuffer";
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";
183 case spv::Op::OpTypeVector
: {
184 dimension
= type_inst
->word(3);
188 case spv::Op::OpTypeBool
:
189 case spv::Op::OpTypeInt
:
190 case spv::Op::OpTypeFloat
: {
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();
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 "
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
);
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);
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
);
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 "
282 << spvOpcodeString(opcode
);
295 } // namespace spvtools