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 bitwise 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
24namespace spvtools {
25namespace val {
26
27// Validates correctness of bitwise instructions.
28spv_result_t BitwisePass(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 SpvOpShiftRightLogical:
34 case SpvOpShiftRightArithmetic:
35 case SpvOpShiftLeftLogical: {
36 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
37 return _.diag(SPV_ERROR_INVALID_DATA, inst)
38 << "Expected int scalar or vector type as Result Type: "
39 << spvOpcodeString(opcode);
40
41 const uint32_t result_dimension = _.GetDimension(result_type);
42 const uint32_t base_type = _.GetOperandTypeId(inst, 2);
43 const uint32_t shift_type = _.GetOperandTypeId(inst, 3);
44
45 if (!base_type ||
46 (!_.IsIntScalarType(base_type) && !_.IsIntVectorType(base_type)))
47 return _.diag(SPV_ERROR_INVALID_DATA, inst)
48 << "Expected Base to be int scalar or vector: "
49 << spvOpcodeString(opcode);
50
51 if (_.GetDimension(base_type) != result_dimension)
52 return _.diag(SPV_ERROR_INVALID_DATA, inst)
53 << "Expected Base to have the same dimension "
54 << "as Result Type: " << spvOpcodeString(opcode);
55
56 if (_.GetBitWidth(base_type) != _.GetBitWidth(result_type))
57 return _.diag(SPV_ERROR_INVALID_DATA, inst)
58 << "Expected Base to have the same bit width "
59 << "as Result Type: " << spvOpcodeString(opcode);
60
61 if (!shift_type ||
62 (!_.IsIntScalarType(shift_type) && !_.IsIntVectorType(shift_type)))
63 return _.diag(SPV_ERROR_INVALID_DATA, inst)
64 << "Expected Shift to be int scalar or vector: "
65 << spvOpcodeString(opcode);
66
67 if (_.GetDimension(shift_type) != result_dimension)
68 return _.diag(SPV_ERROR_INVALID_DATA, inst)
69 << "Expected Shift to have the same dimension "
70 << "as Result Type: " << spvOpcodeString(opcode);
71 break;
72 }
73
74 case SpvOpBitwiseOr:
75 case SpvOpBitwiseXor:
76 case SpvOpBitwiseAnd:
77 case SpvOpNot: {
78 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
79 return _.diag(SPV_ERROR_INVALID_DATA, inst)
80 << "Expected int scalar or vector type as Result Type: "
81 << spvOpcodeString(opcode);
82
83 const uint32_t result_dimension = _.GetDimension(result_type);
84 const uint32_t result_bit_width = _.GetBitWidth(result_type);
85
86 for (size_t operand_index = 2; operand_index < inst->operands().size();
87 ++operand_index) {
88 const uint32_t type_id = _.GetOperandTypeId(inst, operand_index);
89 if (!type_id ||
90 (!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id)))
91 return _.diag(SPV_ERROR_INVALID_DATA, inst)
92 << "Expected int scalar or vector as operand: "
93 << spvOpcodeString(opcode) << " operand index "
94 << operand_index;
95
96 if (_.GetDimension(type_id) != result_dimension)
97 return _.diag(SPV_ERROR_INVALID_DATA, inst)
98 << "Expected operands to have the same dimension "
99 << "as Result Type: " << spvOpcodeString(opcode)
100 << " operand index " << operand_index;
101
102 if (_.GetBitWidth(type_id) != result_bit_width)
103 return _.diag(SPV_ERROR_INVALID_DATA, inst)
104 << "Expected operands to have the same bit width "
105 << "as Result Type: " << spvOpcodeString(opcode)
106 << " operand index " << operand_index;
107 }
108 break;
109 }
110
111 case SpvOpBitFieldInsert: {
112 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
113 return _.diag(SPV_ERROR_INVALID_DATA, inst)
114 << "Expected int scalar or vector type as Result Type: "
115 << spvOpcodeString(opcode);
116
117 const uint32_t base_type = _.GetOperandTypeId(inst, 2);
118 const uint32_t insert_type = _.GetOperandTypeId(inst, 3);
119 const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
120 const uint32_t count_type = _.GetOperandTypeId(inst, 5);
121
122 if (base_type != result_type)
123 return _.diag(SPV_ERROR_INVALID_DATA, inst)
124 << "Expected Base Type to be equal to Result Type: "
125 << spvOpcodeString(opcode);
126
127 if (insert_type != result_type)
128 return _.diag(SPV_ERROR_INVALID_DATA, inst)
129 << "Expected Insert Type to be equal to Result Type: "
130 << spvOpcodeString(opcode);
131
132 if (!offset_type || !_.IsIntScalarType(offset_type))
133 return _.diag(SPV_ERROR_INVALID_DATA, inst)
134 << "Expected Offset Type to be int scalar: "
135 << spvOpcodeString(opcode);
136
137 if (!count_type || !_.IsIntScalarType(count_type))
138 return _.diag(SPV_ERROR_INVALID_DATA, inst)
139 << "Expected Count Type to be int scalar: "
140 << spvOpcodeString(opcode);
141 break;
142 }
143
144 case SpvOpBitFieldSExtract:
145 case SpvOpBitFieldUExtract: {
146 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
147 return _.diag(SPV_ERROR_INVALID_DATA, inst)
148 << "Expected int scalar or vector type as Result Type: "
149 << spvOpcodeString(opcode);
150
151 const uint32_t base_type = _.GetOperandTypeId(inst, 2);
152 const uint32_t offset_type = _.GetOperandTypeId(inst, 3);
153 const uint32_t count_type = _.GetOperandTypeId(inst, 4);
154
155 if (base_type != result_type)
156 return _.diag(SPV_ERROR_INVALID_DATA, inst)
157 << "Expected Base Type to be equal to Result Type: "
158 << spvOpcodeString(opcode);
159
160 if (!offset_type || !_.IsIntScalarType(offset_type))
161 return _.diag(SPV_ERROR_INVALID_DATA, inst)
162 << "Expected Offset Type to be int scalar: "
163 << spvOpcodeString(opcode);
164
165 if (!count_type || !_.IsIntScalarType(count_type))
166 return _.diag(SPV_ERROR_INVALID_DATA, inst)
167 << "Expected Count Type to be int scalar: "
168 << spvOpcodeString(opcode);
169 break;
170 }
171
172 case SpvOpBitReverse: {
173 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
174 return _.diag(SPV_ERROR_INVALID_DATA, inst)
175 << "Expected int scalar or vector type as Result Type: "
176 << spvOpcodeString(opcode);
177
178 const uint32_t base_type = _.GetOperandTypeId(inst, 2);
179
180 if (base_type != result_type)
181 return _.diag(SPV_ERROR_INVALID_DATA, inst)
182 << "Expected Base Type to be equal to Result Type: "
183 << spvOpcodeString(opcode);
184 break;
185 }
186
187 case SpvOpBitCount: {
188 if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type))
189 return _.diag(SPV_ERROR_INVALID_DATA, inst)
190 << "Expected int scalar or vector type as Result Type: "
191 << spvOpcodeString(opcode);
192
193 const uint32_t base_type = _.GetOperandTypeId(inst, 2);
194 if (!base_type ||
195 (!_.IsIntScalarType(base_type) && !_.IsIntVectorType(base_type)))
196 return _.diag(SPV_ERROR_INVALID_DATA, inst)
197 << "Expected Base Type to be int scalar or vector: "
198 << spvOpcodeString(opcode);
199
200 const uint32_t base_dimension = _.GetDimension(base_type);
201 const uint32_t result_dimension = _.GetDimension(result_type);
202
203 if (base_dimension != result_dimension)
204 return _.diag(SPV_ERROR_INVALID_DATA, inst)
205 << "Expected Base dimension to be equal to Result Type "
206 "dimension: "
207 << spvOpcodeString(opcode);
208 break;
209 }
210
211 default:
212 break;
213 }
214
215 return SPV_SUCCESS;
216}
217
218} // namespace val
219} // namespace spvtools
220