Coverage Report

Created: 2026-02-14 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/val/validate_logicals.cpp
Line
Count
Source
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/opcode.h"
18
#include "source/val/instruction.h"
19
#include "source/val/validate.h"
20
#include "source/val/validation_state.h"
21
22
namespace spvtools {
23
namespace val {
24
25
// Validates correctness of logical instructions.
26
13.5M
spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) {
27
13.5M
  const spv::Op opcode = inst->opcode();
28
13.5M
  const uint32_t result_type = inst->type_id();
29
30
13.5M
  switch (opcode) {
31
14
    case spv::Op::OpAny:
32
32
    case spv::Op::OpAll: {
33
32
      if (!_.IsBoolScalarType(result_type))
34
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
35
4
               << "Expected bool scalar type as Result Type: "
36
4
               << spvOpcodeString(opcode);
37
38
28
      const uint32_t vector_type = _.GetOperandTypeId(inst, 2);
39
28
      if (!vector_type || !_.IsBoolVectorType(vector_type))
40
9
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
41
9
               << "Expected operand to be vector bool: "
42
9
               << spvOpcodeString(opcode);
43
44
19
      break;
45
28
    }
46
47
1.80k
    case spv::Op::OpIsNan:
48
2.61k
    case spv::Op::OpIsInf:
49
2.61k
    case spv::Op::OpIsFinite:
50
2.62k
    case spv::Op::OpIsNormal:
51
2.62k
    case spv::Op::OpSignBitSet: {
52
2.62k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
53
26
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
54
26
               << "Expected bool scalar or vector type as Result Type: "
55
26
               << spvOpcodeString(opcode);
56
57
2.59k
      const uint32_t operand_type = _.GetOperandTypeId(inst, 2);
58
2.59k
      if (!operand_type || (!_.IsFloatScalarType(operand_type) &&
59
9
                            !_.IsFloatVectorType(operand_type)))
60
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
61
5
               << "Expected operand to be scalar or vector float: "
62
5
               << spvOpcodeString(opcode);
63
64
2.59k
      if (_.GetDimension(result_type) != _.GetDimension(operand_type))
65
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
66
5
               << "Expected vector sizes of Result Type and the operand to be "
67
5
                  "equal: "
68
5
               << spvOpcodeString(opcode);
69
70
2.58k
      break;
71
2.59k
    }
72
73
2.58k
    case spv::Op::OpFOrdEqual:
74
499
    case spv::Op::OpFUnordEqual:
75
634
    case spv::Op::OpFOrdNotEqual:
76
824
    case spv::Op::OpFUnordNotEqual:
77
9.00k
    case spv::Op::OpFOrdLessThan:
78
9.28k
    case spv::Op::OpFUnordLessThan:
79
12.9k
    case spv::Op::OpFOrdGreaterThan:
80
13.2k
    case spv::Op::OpFUnordGreaterThan:
81
14.2k
    case spv::Op::OpFOrdLessThanEqual:
82
14.4k
    case spv::Op::OpFUnordLessThanEqual:
83
16.2k
    case spv::Op::OpFOrdGreaterThanEqual:
84
16.4k
    case spv::Op::OpFUnordGreaterThanEqual:
85
16.4k
    case spv::Op::OpLessOrGreater:
86
16.4k
    case spv::Op::OpOrdered:
87
16.4k
    case spv::Op::OpUnordered: {
88
16.4k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
89
48
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
90
48
               << "Expected bool scalar or vector type as Result Type: "
91
48
               << spvOpcodeString(opcode);
92
93
16.3k
      const uint32_t left_operand_type = _.GetOperandTypeId(inst, 2);
94
16.3k
      if (!left_operand_type || (!_.IsFloatScalarType(left_operand_type) &&
95
36
                                 !_.IsFloatVectorType(left_operand_type)))
96
28
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
97
28
               << "Expected operands to be scalar or vector float: "
98
28
               << spvOpcodeString(opcode);
99
100
16.3k
      if (_.GetDimension(result_type) != _.GetDimension(left_operand_type))
101
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
102
4
               << "Expected vector sizes of Result Type and the operands to be "
103
4
                  "equal: "
104
4
               << spvOpcodeString(opcode);
105
106
16.3k
      if (left_operand_type != _.GetOperandTypeId(inst, 3))
107
11
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
108
11
               << "Expected left and right operands to have the same type: "
109
11
               << spvOpcodeString(opcode);
110
111
16.3k
      break;
112
16.3k
    }
113
114
16.3k
    case spv::Op::OpLogicalEqual:
115
349
    case spv::Op::OpLogicalNotEqual:
116
755
    case spv::Op::OpLogicalOr:
117
3.30k
    case spv::Op::OpLogicalAnd: {
118
3.30k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
119
17
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
120
17
               << "Expected bool scalar or vector type as Result Type: "
121
17
               << spvOpcodeString(opcode);
122
123
3.28k
      if (result_type != _.GetOperandTypeId(inst, 2) ||
124
3.27k
          result_type != _.GetOperandTypeId(inst, 3))
125
14
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
126
14
               << "Expected both operands to be of Result Type: "
127
14
               << spvOpcodeString(opcode);
128
129
3.26k
      break;
130
3.28k
    }
131
132
5.40k
    case spv::Op::OpLogicalNot: {
133
5.40k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
134
7
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
135
7
               << "Expected bool scalar or vector type as Result Type: "
136
7
               << spvOpcodeString(opcode);
137
138
5.40k
      if (result_type != _.GetOperandTypeId(inst, 2))
139
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
140
5
               << "Expected operand to be of Result Type: "
141
5
               << spvOpcodeString(opcode);
142
143
5.39k
      break;
144
5.40k
    }
145
146
5.39k
    case spv::Op::OpSelect: {
147
4.51k
      uint32_t dimension = 1;
148
4.51k
      {
149
4.51k
        const Instruction* type_inst = _.FindDef(result_type);
150
4.51k
        assert(type_inst);
151
152
4.51k
        const auto composites = _.features().select_between_composites;
153
4.51k
        auto fail = [&_, composites, inst, opcode]() -> spv_result_t {
154
9
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
155
9
                 << "Expected scalar or "
156
9
                 << (composites ? "composite" : "vector")
157
9
                 << " type as Result Type: " << spvOpcodeString(opcode);
158
9
        };
159
160
4.51k
        const spv::Op type_opcode = type_inst->opcode();
161
4.51k
        switch (type_opcode) {
162
0
          case spv::Op::OpTypeUntypedPointerKHR:
163
3
          case spv::Op::OpTypePointer: {
164
3
            if (_.addressing_model() == spv::AddressingModel::Logical &&
165
3
                !_.HasCapability(
166
3
                    spv::Capability::VariablePointersStorageBuffer))
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
3
          case spv::Op::OpTypeSampler: {
176
3
            if (!_.HasCapability(spv::Capability::BindlessTextureNV))
177
3
              return _.diag(SPV_ERROR_INVALID_DATA, inst)
178
3
                     << "Using image/sampler with OpSelect requires capability "
179
3
                     << "BindlessTextureNV";
180
0
            break;
181
3
          }
182
183
5
          case spv::Op::OpTypeVector: {
184
5
            dimension = type_inst->word(3);
185
5
            break;
186
3
          }
187
0
          case spv::Op::OpTypeVectorIdEXT: {
188
0
            dimension = _.GetDimension(result_type);
189
0
            break;
190
3
          }
191
192
33
          case spv::Op::OpTypeBool:
193
3.08k
          case spv::Op::OpTypeInt:
194
4.49k
          case spv::Op::OpTypeFloat: {
195
4.49k
            break;
196
3.08k
          }
197
198
          // Not RuntimeArray because of other rules.
199
2
          case spv::Op::OpTypeArray:
200
4
          case spv::Op::OpTypeMatrix:
201
6
          case spv::Op::OpTypeStruct: {
202
6
            if (!composites) return fail();
203
0
            break;
204
6
          }
205
206
3
          default:
207
3
            return fail();
208
4.51k
        }
209
210
4.49k
        const uint32_t condition_type = _.GetOperandTypeId(inst, 2);
211
4.49k
        const uint32_t left_type = _.GetOperandTypeId(inst, 3);
212
4.49k
        const uint32_t right_type = _.GetOperandTypeId(inst, 4);
213
214
4.49k
        if (!condition_type || (!_.IsBoolScalarType(condition_type) &&
215
9
                                !_.IsBoolVectorType(condition_type)))
216
9
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
217
9
                 << "Expected bool scalar or vector type as condition: "
218
9
                 << spvOpcodeString(opcode);
219
220
4.48k
        if (_.GetDimension(condition_type) != dimension) {
221
          // If the condition is a vector type, then the result must also be a
222
          // vector with matching dimensions. In SPIR-V 1.4, a scalar condition
223
          // can be used to select between vector types. |composites| is a
224
          // proxy for SPIR-V 1.4 functionality.
225
5
          if (!composites || _.IsBoolVectorType(condition_type)) {
226
5
            return _.diag(SPV_ERROR_INVALID_DATA, inst)
227
5
                   << "Expected vector sizes of Result Type and the condition "
228
5
                      "to be equal: "
229
5
                   << spvOpcodeString(opcode);
230
5
          }
231
5
        }
232
233
4.48k
        if (result_type != left_type || result_type != right_type)
234
10
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
235
10
                 << "Expected both objects to be of Result Type: "
236
10
                 << spvOpcodeString(opcode);
237
238
4.47k
        break;
239
4.48k
      }
240
4.48k
    }
241
242
15.5k
    case spv::Op::OpIEqual:
243
20.6k
    case spv::Op::OpINotEqual:
244
22.5k
    case spv::Op::OpUGreaterThan:
245
23.6k
    case spv::Op::OpUGreaterThanEqual:
246
24.8k
    case spv::Op::OpULessThan:
247
26.1k
    case spv::Op::OpULessThanEqual:
248
33.8k
    case spv::Op::OpSGreaterThan:
249
37.1k
    case spv::Op::OpSGreaterThanEqual:
250
57.9k
    case spv::Op::OpSLessThan:
251
67.7k
    case spv::Op::OpSLessThanEqual: {
252
67.7k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
253
43
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
254
43
               << "Expected bool scalar or vector type as Result Type: "
255
43
               << spvOpcodeString(opcode);
256
257
67.7k
      const uint32_t left_type = _.GetOperandTypeId(inst, 2);
258
67.7k
      const uint32_t right_type = _.GetOperandTypeId(inst, 3);
259
260
67.7k
      if (!left_type ||
261
67.7k
          (!_.IsIntScalarType(left_type) && !_.IsIntVectorType(left_type)))
262
9
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
263
9
               << "Expected operands to be scalar or vector int: "
264
9
               << spvOpcodeString(opcode);
265
266
67.6k
      if (_.GetDimension(result_type) != _.GetDimension(left_type))
267
6
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
268
6
               << "Expected vector sizes of Result Type and the operands to be"
269
6
               << " equal: " << spvOpcodeString(opcode);
270
271
67.6k
      if (!right_type ||
272
67.6k
          (!_.IsIntScalarType(right_type) && !_.IsIntVectorType(right_type)))
273
6
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
274
6
               << "Expected operands to be scalar or vector int: "
275
6
               << spvOpcodeString(opcode);
276
277
67.6k
      if (_.GetDimension(result_type) != _.GetDimension(right_type))
278
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
279
4
               << "Expected vector sizes of Result Type and the operands to be"
280
4
               << " equal: " << spvOpcodeString(opcode);
281
282
67.6k
      if (_.GetBitWidth(left_type) != _.GetBitWidth(right_type))
283
0
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
284
0
               << "Expected both operands to have the same component bit "
285
0
                  "width: "
286
0
               << spvOpcodeString(opcode);
287
288
67.6k
      break;
289
67.6k
    }
290
291
13.4M
    default:
292
13.4M
      break;
293
13.5M
  }
294
295
13.5M
  return SPV_SUCCESS;
296
13.5M
}
297
298
}  // namespace val
299
}  // namespace spvtools