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 
24 namespace spvtools {
25 namespace val {
26 
27 // Validates correctness of bitwise instructions.
BitwisePass(ValidationState_t & _,const Instruction * inst)28 spv_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