Coverage Report

Created: 2023-03-01 07:33

/src/spirv-tools/source/val/validate_logicals.cpp
Line
Count
Source (jump to first uncovered line)
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/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 logical instructions.
28
2.69M
spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) {
29
2.69M
  const spv::Op opcode = inst->opcode();
30
2.69M
  const uint32_t result_type = inst->type_id();
31
32
2.69M
  switch (opcode) {
33
7
    case spv::Op::OpAny:
34
36
    case spv::Op::OpAll: {
35
36
      if (!_.IsBoolScalarType(result_type))
36
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
37
4
               << "Expected bool scalar type as Result Type: "
38
4
               << spvOpcodeString(opcode);
39
40
32
      const uint32_t vector_type = _.GetOperandTypeId(inst, 2);
41
32
      if (!vector_type || !_.IsBoolVectorType(vector_type))
42
8
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
43
8
               << "Expected operand to be vector bool: "
44
8
               << spvOpcodeString(opcode);
45
46
24
      break;
47
32
    }
48
49
1.07k
    case spv::Op::OpIsNan:
50
1.68k
    case spv::Op::OpIsInf:
51
1.68k
    case spv::Op::OpIsFinite:
52
1.68k
    case spv::Op::OpIsNormal:
53
1.69k
    case spv::Op::OpSignBitSet: {
54
1.69k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
55
17
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
56
17
               << "Expected bool scalar or vector type as Result Type: "
57
17
               << spvOpcodeString(opcode);
58
59
1.67k
      const uint32_t operand_type = _.GetOperandTypeId(inst, 2);
60
1.67k
      if (!operand_type || (!_.IsFloatScalarType(operand_type) &&
61
1.67k
                            !_.IsFloatVectorType(operand_type)))
62
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
63
5
               << "Expected operand to be scalar or vector float: "
64
5
               << spvOpcodeString(opcode);
65
66
1.66k
      if (_.GetDimension(result_type) != _.GetDimension(operand_type))
67
3
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
68
3
               << "Expected vector sizes of Result Type and the operand to be "
69
3
                  "equal: "
70
3
               << spvOpcodeString(opcode);
71
72
1.66k
      break;
73
1.66k
    }
74
75
1.66k
    case spv::Op::OpFOrdEqual:
76
403
    case spv::Op::OpFUnordEqual:
77
538
    case spv::Op::OpFOrdNotEqual:
78
666
    case spv::Op::OpFUnordNotEqual:
79
5.70k
    case spv::Op::OpFOrdLessThan:
80
5.87k
    case spv::Op::OpFUnordLessThan:
81
8.06k
    case spv::Op::OpFOrdGreaterThan:
82
8.18k
    case spv::Op::OpFUnordGreaterThan:
83
8.84k
    case spv::Op::OpFOrdLessThanEqual:
84
8.95k
    case spv::Op::OpFUnordLessThanEqual:
85
10.8k
    case spv::Op::OpFOrdGreaterThanEqual:
86
11.0k
    case spv::Op::OpFUnordGreaterThanEqual:
87
11.0k
    case spv::Op::OpLessOrGreater:
88
11.0k
    case spv::Op::OpOrdered:
89
11.0k
    case spv::Op::OpUnordered: {
90
11.0k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
91
25
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
92
25
               << "Expected bool scalar or vector type as Result Type: "
93
25
               << spvOpcodeString(opcode);
94
95
10.9k
      const uint32_t left_operand_type = _.GetOperandTypeId(inst, 2);
96
10.9k
      if (!left_operand_type || (!_.IsFloatScalarType(left_operand_type) &&
97
10.9k
                                 !_.IsFloatVectorType(left_operand_type)))
98
24
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
99
24
               << "Expected operands to be scalar or vector float: "
100
24
               << spvOpcodeString(opcode);
101
102
10.9k
      if (_.GetDimension(result_type) != _.GetDimension(left_operand_type))
103
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
104
5
               << "Expected vector sizes of Result Type and the operands to be "
105
5
                  "equal: "
106
5
               << spvOpcodeString(opcode);
107
108
10.9k
      if (left_operand_type != _.GetOperandTypeId(inst, 3))
109
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
110
5
               << "Expected left and right operands to have the same type: "
111
5
               << spvOpcodeString(opcode);
112
113
10.9k
      break;
114
10.9k
    }
115
116
10.9k
    case spv::Op::OpLogicalEqual:
117
228
    case spv::Op::OpLogicalNotEqual:
118
420
    case spv::Op::OpLogicalOr:
119
3.05k
    case spv::Op::OpLogicalAnd: {
120
3.05k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
121
9
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
122
9
               << "Expected bool scalar or vector type as Result Type: "
123
9
               << spvOpcodeString(opcode);
124
125
3.04k
      if (result_type != _.GetOperandTypeId(inst, 2) ||
126
3.04k
          result_type != _.GetOperandTypeId(inst, 3))
127
14
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
128
14
               << "Expected both operands to be of Result Type: "
129
14
               << spvOpcodeString(opcode);
130
131
3.03k
      break;
132
3.04k
    }
133
134
3.37k
    case spv::Op::OpLogicalNot: {
135
3.37k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
136
3
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
137
3
               << "Expected bool scalar or vector type as Result Type: "
138
3
               << spvOpcodeString(opcode);
139
140
3.36k
      if (result_type != _.GetOperandTypeId(inst, 2))
141
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
142
4
               << "Expected operand to be of Result Type: "
143
4
               << spvOpcodeString(opcode);
144
145
3.36k
      break;
146
3.36k
    }
147
148
3.36k
    case spv::Op::OpSelect: {
149
2.83k
      uint32_t dimension = 1;
150
2.83k
      {
151
2.83k
        const Instruction* type_inst = _.FindDef(result_type);
152
2.83k
        assert(type_inst);
153
154
0
        const auto composites = _.features().select_between_composites;
155
2.83k
        auto fail = [&_, composites, inst, opcode]() -> spv_result_t {
156
5
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
157
5
                 << "Expected scalar or "
158
5
                 << (composites ? "composite" : "vector")
159
5
                 << " type as Result Type: " << spvOpcodeString(opcode);
160
5
        };
161
162
2.83k
        const spv::Op type_opcode = type_inst->opcode();
163
2.83k
        switch (type_opcode) {
164
3
          case spv::Op::OpTypePointer: {
165
3
            if (_.addressing_model() == spv::AddressingModel::Logical &&
166
3
                !_.features().variable_pointers)
167
3
              return _.diag(SPV_ERROR_INVALID_DATA, inst)
168
3
                     << "Using pointers with OpSelect requires capability "
169
3
                     << "VariablePointers or VariablePointersStorageBuffer";
170
0
            break;
171
3
          }
172
173
0
          case spv::Op::OpTypeSampledImage:
174
0
          case spv::Op::OpTypeImage:
175
0
          case spv::Op::OpTypeSampler: {
176
0
            if (!_.HasCapability(spv::Capability::BindlessTextureNV))
177
0
              return _.diag(SPV_ERROR_INVALID_DATA, inst)
178
0
                     << "Using image/sampler with OpSelect requires capability "
179
0
                     << "BindlessTextureNV";
180
0
            break;
181
0
          }
182
183
2
          case spv::Op::OpTypeVector: {
184
2
            dimension = type_inst->word(3);
185
2
            break;
186
0
          }
187
188
27
          case spv::Op::OpTypeBool:
189
2.00k
          case spv::Op::OpTypeInt:
190
2.82k
          case spv::Op::OpTypeFloat: {
191
2.82k
            break;
192
2.00k
          }
193
194
          // Not RuntimeArray because of other rules.
195
1
          case spv::Op::OpTypeArray:
196
2
          case spv::Op::OpTypeMatrix:
197
2
          case spv::Op::OpTypeStruct: {
198
2
            if (!composites) return fail();
199
0
            break;
200
2
          }
201
202
3
          default:
203
3
            return fail();
204
2.83k
        }
205
206
2.82k
        const uint32_t condition_type = _.GetOperandTypeId(inst, 2);
207
2.82k
        const uint32_t left_type = _.GetOperandTypeId(inst, 3);
208
2.82k
        const uint32_t right_type = _.GetOperandTypeId(inst, 4);
209
210
2.82k
        if (!condition_type || (!_.IsBoolScalarType(condition_type) &&
211
2.82k
                                !_.IsBoolVectorType(condition_type)))
212
5
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
213
5
                 << "Expected bool scalar or vector type as condition: "
214
5
                 << spvOpcodeString(opcode);
215
216
2.82k
        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
2
          if (!composites || _.IsBoolVectorType(condition_type)) {
222
2
            return _.diag(SPV_ERROR_INVALID_DATA, inst)
223
2
                   << "Expected vector sizes of Result Type and the condition "
224
2
                      "to be equal: "
225
2
                   << spvOpcodeString(opcode);
226
2
          }
227
2
        }
228
229
2.81k
        if (result_type != left_type || result_type != right_type)
230
7
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
231
7
                 << "Expected both objects to be of Result Type: "
232
7
                 << spvOpcodeString(opcode);
233
234
2.81k
        break;
235
2.81k
      }
236
2.81k
    }
237
238
14.1k
    case spv::Op::OpIEqual:
239
17.2k
    case spv::Op::OpINotEqual:
240
17.9k
    case spv::Op::OpUGreaterThan:
241
18.4k
    case spv::Op::OpUGreaterThanEqual:
242
18.9k
    case spv::Op::OpULessThan:
243
19.4k
    case spv::Op::OpULessThanEqual:
244
25.5k
    case spv::Op::OpSGreaterThan:
245
27.5k
    case spv::Op::OpSGreaterThanEqual:
246
49.8k
    case spv::Op::OpSLessThan:
247
57.7k
    case spv::Op::OpSLessThanEqual: {
248
57.7k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
249
24
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
250
24
               << "Expected bool scalar or vector type as Result Type: "
251
24
               << spvOpcodeString(opcode);
252
253
57.7k
      const uint32_t left_type = _.GetOperandTypeId(inst, 2);
254
57.7k
      const uint32_t right_type = _.GetOperandTypeId(inst, 3);
255
256
57.7k
      if (!left_type ||
257
57.7k
          (!_.IsIntScalarType(left_type) && !_.IsIntVectorType(left_type)))
258
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
259
4
               << "Expected operands to be scalar or vector int: "
260
4
               << spvOpcodeString(opcode);
261
262
57.6k
      if (_.GetDimension(result_type) != _.GetDimension(left_type))
263
2
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
264
2
               << "Expected vector sizes of Result Type and the operands to be"
265
2
               << " equal: " << spvOpcodeString(opcode);
266
267
57.6k
      if (!right_type ||
268
57.6k
          (!_.IsIntScalarType(right_type) && !_.IsIntVectorType(right_type)))
269
8
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
270
8
               << "Expected operands to be scalar or vector int: "
271
8
               << spvOpcodeString(opcode);
272
273
57.6k
      if (_.GetDimension(result_type) != _.GetDimension(right_type))
274
2
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
275
2
               << "Expected vector sizes of Result Type and the operands to be"
276
2
               << " equal: " << spvOpcodeString(opcode);
277
278
57.6k
      if (_.GetBitWidth(left_type) != _.GetBitWidth(right_type))
279
0
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
280
0
               << "Expected both operands to have the same component bit "
281
0
                  "width: "
282
0
               << spvOpcodeString(opcode);
283
284
57.6k
      break;
285
57.6k
    }
286
287
2.61M
    default:
288
2.61M
      break;
289
2.69M
  }
290
291
2.69M
  return SPV_SUCCESS;
292
2.69M
}
293
294
}  // namespace val
295
}  // namespace spvtools