Coverage Report

Created: 2024-09-11 07:09

/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/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
10.1M
spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) {
27
10.1M
  const spv::Op opcode = inst->opcode();
28
10.1M
  const uint32_t result_type = inst->type_id();
29
30
10.1M
  switch (opcode) {
31
7
    case spv::Op::OpAny:
32
42
    case spv::Op::OpAll: {
33
42
      if (!_.IsBoolScalarType(result_type))
34
7
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
35
7
               << "Expected bool scalar type as Result Type: "
36
7
               << spvOpcodeString(opcode);
37
38
35
      const uint32_t vector_type = _.GetOperandTypeId(inst, 2);
39
35
      if (!vector_type || !_.IsBoolVectorType(vector_type))
40
7
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
41
7
               << "Expected operand to be vector bool: "
42
7
               << spvOpcodeString(opcode);
43
44
28
      break;
45
35
    }
46
47
1.17k
    case spv::Op::OpIsNan:
48
1.86k
    case spv::Op::OpIsInf:
49
1.87k
    case spv::Op::OpIsFinite:
50
1.87k
    case spv::Op::OpIsNormal:
51
1.87k
    case spv::Op::OpSignBitSet: {
52
1.87k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
53
25
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
54
25
               << "Expected bool scalar or vector type as Result Type: "
55
25
               << spvOpcodeString(opcode);
56
57
1.85k
      const uint32_t operand_type = _.GetOperandTypeId(inst, 2);
58
1.85k
      if (!operand_type || (!_.IsFloatScalarType(operand_type) &&
59
1.85k
                            !_.IsFloatVectorType(operand_type)))
60
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
61
4
               << "Expected operand to be scalar or vector float: "
62
4
               << spvOpcodeString(opcode);
63
64
1.85k
      if (_.GetDimension(result_type) != _.GetDimension(operand_type))
65
3
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
66
3
               << "Expected vector sizes of Result Type and the operand to be "
67
3
                  "equal: "
68
3
               << spvOpcodeString(opcode);
69
70
1.84k
      break;
71
1.85k
    }
72
73
1.84k
    case spv::Op::OpFOrdEqual:
74
237
    case spv::Op::OpFUnordEqual:
75
316
    case spv::Op::OpFOrdNotEqual:
76
394
    case spv::Op::OpFUnordNotEqual:
77
4.63k
    case spv::Op::OpFOrdLessThan:
78
4.77k
    case spv::Op::OpFUnordLessThan:
79
6.33k
    case spv::Op::OpFOrdGreaterThan:
80
6.48k
    case spv::Op::OpFUnordGreaterThan:
81
6.95k
    case spv::Op::OpFOrdLessThanEqual:
82
7.06k
    case spv::Op::OpFUnordLessThanEqual:
83
8.09k
    case spv::Op::OpFOrdGreaterThanEqual:
84
8.17k
    case spv::Op::OpFUnordGreaterThanEqual:
85
8.17k
    case spv::Op::OpLessOrGreater:
86
8.17k
    case spv::Op::OpOrdered:
87
8.17k
    case spv::Op::OpUnordered: {
88
8.17k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
89
21
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
90
21
               << "Expected bool scalar or vector type as Result Type: "
91
21
               << spvOpcodeString(opcode);
92
93
8.15k
      const uint32_t left_operand_type = _.GetOperandTypeId(inst, 2);
94
8.15k
      if (!left_operand_type || (!_.IsFloatScalarType(left_operand_type) &&
95
8.15k
                                 !_.IsFloatVectorType(left_operand_type)))
96
24
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
97
24
               << "Expected operands to be scalar or vector float: "
98
24
               << spvOpcodeString(opcode);
99
100
8.13k
      if (_.GetDimension(result_type) != _.GetDimension(left_operand_type))
101
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
102
5
               << "Expected vector sizes of Result Type and the operands to be "
103
5
                  "equal: "
104
5
               << spvOpcodeString(opcode);
105
106
8.12k
      if (left_operand_type != _.GetOperandTypeId(inst, 3))
107
7
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
108
7
               << "Expected left and right operands to have the same type: "
109
7
               << spvOpcodeString(opcode);
110
111
8.12k
      break;
112
8.12k
    }
113
114
8.12k
    case spv::Op::OpLogicalEqual:
115
289
    case spv::Op::OpLogicalNotEqual:
116
514
    case spv::Op::OpLogicalOr:
117
2.15k
    case spv::Op::OpLogicalAnd: {
118
2.15k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
119
14
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
120
14
               << "Expected bool scalar or vector type as Result Type: "
121
14
               << spvOpcodeString(opcode);
122
123
2.13k
      if (result_type != _.GetOperandTypeId(inst, 2) ||
124
2.13k
          result_type != _.GetOperandTypeId(inst, 3))
125
17
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
126
17
               << "Expected both operands to be of Result Type: "
127
17
               << spvOpcodeString(opcode);
128
129
2.12k
      break;
130
2.13k
    }
131
132
2.29k
    case spv::Op::OpLogicalNot: {
133
2.29k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
134
6
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
135
6
               << "Expected bool scalar or vector type as Result Type: "
136
6
               << spvOpcodeString(opcode);
137
138
2.28k
      if (result_type != _.GetOperandTypeId(inst, 2))
139
4
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
140
4
               << "Expected operand to be of Result Type: "
141
4
               << spvOpcodeString(opcode);
142
143
2.28k
      break;
144
2.28k
    }
145
146
2.45k
    case spv::Op::OpSelect: {
147
2.45k
      uint32_t dimension = 1;
148
2.45k
      {
149
2.45k
        const Instruction* type_inst = _.FindDef(result_type);
150
2.45k
        assert(type_inst);
151
152
2.45k
        const auto composites = _.features().select_between_composites;
153
2.45k
        auto fail = [&_, composites, inst, opcode]() -> spv_result_t {
154
4
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
155
4
                 << "Expected scalar or "
156
4
                 << (composites ? "composite" : "vector")
157
4
                 << " type as Result Type: " << spvOpcodeString(opcode);
158
4
        };
159
160
2.45k
        const spv::Op type_opcode = type_inst->opcode();
161
2.45k
        switch (type_opcode) {
162
0
          case spv::Op::OpTypeUntypedPointerKHR:
163
5
          case spv::Op::OpTypePointer: {
164
5
            if (_.addressing_model() == spv::AddressingModel::Logical &&
165
5
                !_.HasCapability(
166
5
                    spv::Capability::VariablePointersStorageBuffer))
167
5
              return _.diag(SPV_ERROR_INVALID_DATA, inst)
168
5
                     << "Using pointers with OpSelect requires capability "
169
5
                     << "VariablePointers or VariablePointersStorageBuffer";
170
0
            break;
171
5
          }
172
173
0
          case spv::Op::OpTypeSampledImage:
174
0
          case spv::Op::OpTypeImage:
175
1
          case spv::Op::OpTypeSampler: {
176
1
            if (!_.HasCapability(spv::Capability::BindlessTextureNV))
177
1
              return _.diag(SPV_ERROR_INVALID_DATA, inst)
178
1
                     << "Using image/sampler with OpSelect requires capability "
179
1
                     << "BindlessTextureNV";
180
0
            break;
181
1
          }
182
183
3
          case spv::Op::OpTypeVector: {
184
3
            dimension = type_inst->word(3);
185
3
            break;
186
1
          }
187
188
27
          case spv::Op::OpTypeBool:
189
1.82k
          case spv::Op::OpTypeInt:
190
2.44k
          case spv::Op::OpTypeFloat: {
191
2.44k
            break;
192
1.82k
          }
193
194
          // Not RuntimeArray because of other rules.
195
0
          case spv::Op::OpTypeArray:
196
0
          case spv::Op::OpTypeMatrix:
197
1
          case spv::Op::OpTypeStruct: {
198
1
            if (!composites) return fail();
199
0
            break;
200
1
          }
201
202
3
          default:
203
3
            return fail();
204
2.45k
        }
205
206
2.44k
        const uint32_t condition_type = _.GetOperandTypeId(inst, 2);
207
2.44k
        const uint32_t left_type = _.GetOperandTypeId(inst, 3);
208
2.44k
        const uint32_t right_type = _.GetOperandTypeId(inst, 4);
209
210
2.44k
        if (!condition_type || (!_.IsBoolScalarType(condition_type) &&
211
2.44k
                                !_.IsBoolVectorType(condition_type)))
212
6
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
213
6
                 << "Expected bool scalar or vector type as condition: "
214
6
                 << spvOpcodeString(opcode);
215
216
2.44k
        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
3
          if (!composites || _.IsBoolVectorType(condition_type)) {
222
3
            return _.diag(SPV_ERROR_INVALID_DATA, inst)
223
3
                   << "Expected vector sizes of Result Type and the condition "
224
3
                      "to be equal: "
225
3
                   << spvOpcodeString(opcode);
226
3
          }
227
3
        }
228
229
2.43k
        if (result_type != left_type || result_type != right_type)
230
6
          return _.diag(SPV_ERROR_INVALID_DATA, inst)
231
6
                 << "Expected both objects to be of Result Type: "
232
6
                 << spvOpcodeString(opcode);
233
234
2.43k
        break;
235
2.43k
      }
236
2.43k
    }
237
238
10.8k
    case spv::Op::OpIEqual:
239
13.5k
    case spv::Op::OpINotEqual:
240
14.3k
    case spv::Op::OpUGreaterThan:
241
15.3k
    case spv::Op::OpUGreaterThanEqual:
242
15.9k
    case spv::Op::OpULessThan:
243
16.7k
    case spv::Op::OpULessThanEqual:
244
22.4k
    case spv::Op::OpSGreaterThan:
245
24.7k
    case spv::Op::OpSGreaterThanEqual:
246
40.0k
    case spv::Op::OpSLessThan:
247
46.9k
    case spv::Op::OpSLessThanEqual: {
248
46.9k
      if (!_.IsBoolScalarType(result_type) && !_.IsBoolVectorType(result_type))
249
16
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
250
16
               << "Expected bool scalar or vector type as Result Type: "
251
16
               << spvOpcodeString(opcode);
252
253
46.9k
      const uint32_t left_type = _.GetOperandTypeId(inst, 2);
254
46.9k
      const uint32_t right_type = _.GetOperandTypeId(inst, 3);
255
256
46.9k
      if (!left_type ||
257
46.9k
          (!_.IsIntScalarType(left_type) && !_.IsIntVectorType(left_type)))
258
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
259
5
               << "Expected operands to be scalar or vector int: "
260
5
               << spvOpcodeString(opcode);
261
262
46.9k
      if (_.GetDimension(result_type) != _.GetDimension(left_type))
263
3
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
264
3
               << "Expected vector sizes of Result Type and the operands to be"
265
3
               << " equal: " << spvOpcodeString(opcode);
266
267
46.9k
      if (!right_type ||
268
46.9k
          (!_.IsIntScalarType(right_type) && !_.IsIntVectorType(right_type)))
269
5
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
270
5
               << "Expected operands to be scalar or vector int: "
271
5
               << spvOpcodeString(opcode);
272
273
46.9k
      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
46.9k
      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
46.9k
      break;
285
46.9k
    }
286
287
10.0M
    default:
288
10.0M
      break;
289
10.1M
  }
290
291
10.1M
  return SPV_SUCCESS;
292
10.1M
}
293
294
}  // namespace val
295
}  // namespace spvtools