1// Copyright (c) 2016 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#include "source/opt/instruction.h"
16
17#include <memory>
18#include <utility>
19#include <vector>
20
21#include "gmock/gmock.h"
22#include "source/opt/ir_context.h"
23#include "spirv-tools/libspirv.h"
24#include "test/opt/pass_fixture.h"
25#include "test/opt/pass_utils.h"
26#include "test/unit_spirv.h"
27
28namespace spvtools {
29namespace opt {
30namespace {
31
32using ::testing::Eq;
33using spvtest::MakeInstruction;
34using DescriptorTypeTest = PassTest<::testing::Test>;
35using OpaqueTypeTest = PassTest<::testing::Test>;
36using GetBaseTest = PassTest<::testing::Test>;
37using ValidBasePointerTest = PassTest<::testing::Test>;
38using VulkanBufferTest = PassTest<::testing::Test>;
39
40TEST(InstructionTest, CreateTrivial) {
41  Instruction empty;
42  EXPECT_EQ(spv::Op::OpNop, empty.opcode());
43  EXPECT_EQ(0u, empty.type_id());
44  EXPECT_EQ(0u, empty.result_id());
45  EXPECT_EQ(0u, empty.NumOperands());
46  EXPECT_EQ(0u, empty.NumOperandWords());
47  EXPECT_EQ(0u, empty.NumInOperandWords());
48  EXPECT_EQ(empty.cend(), empty.cbegin());
49  EXPECT_EQ(empty.end(), empty.begin());
50}
51
52TEST(InstructionTest, CreateWithOpcodeAndNoOperands) {
53  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
54  Instruction inst(&context, spv::Op::OpReturn);
55  EXPECT_EQ(spv::Op::OpReturn, inst.opcode());
56  EXPECT_EQ(0u, inst.type_id());
57  EXPECT_EQ(0u, inst.result_id());
58  EXPECT_EQ(0u, inst.NumOperands());
59  EXPECT_EQ(0u, inst.NumOperandWords());
60  EXPECT_EQ(0u, inst.NumInOperandWords());
61  EXPECT_EQ(inst.cend(), inst.cbegin());
62  EXPECT_EQ(inst.end(), inst.begin());
63}
64
65TEST(InstructionTest, OperandAsString) {
66  Operand::OperandData abcde{0x64636261, 0x65};
67  Operand operand(SPV_OPERAND_TYPE_LITERAL_STRING, std::move(abcde));
68  EXPECT_EQ("abcde", operand.AsString());
69}
70
71TEST(InstructionTest, OperandAsLiteralUint64_32bits) {
72  Operand::OperandData words{0x1234};
73  Operand operand(SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, std::move(words));
74  EXPECT_EQ(uint64_t(0x1234), operand.AsLiteralUint64());
75}
76
77TEST(InstructionTest, OperandAsLiteralUint64_64bits) {
78  Operand::OperandData words{0x1234, 0x89ab};
79  Operand operand(SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, std::move(words));
80  EXPECT_EQ((uint64_t(0x89ab) << 32 | 0x1234), operand.AsLiteralUint64());
81}
82
83// The words for an OpTypeInt for 32-bit signed integer resulting in Id 44.
84uint32_t kSampleInstructionWords[] = {(4 << 16) | uint32_t(spv::Op::OpTypeInt),
85                                      44, 32, 1};
86// The operands that would be parsed from kSampleInstructionWords
87spv_parsed_operand_t kSampleParsedOperands[] = {
88    {1, 1, SPV_OPERAND_TYPE_RESULT_ID, SPV_NUMBER_NONE, 0},
89    {2, 1, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_NUMBER_UNSIGNED_INT, 32},
90    {3, 1, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_NUMBER_UNSIGNED_INT, 1},
91};
92
93// A valid parse of kSampleParsedOperands.
94spv_parsed_instruction_t kSampleParsedInstruction = {
95    kSampleInstructionWords,
96    uint16_t(4),
97    uint16_t(spv::Op::OpTypeInt),
98    SPV_EXT_INST_TYPE_NONE,
99    0,   // type id
100    44,  // result id
101    kSampleParsedOperands,
102    3};
103
104// The words for an OpAccessChain instruction.
105uint32_t kSampleAccessChainInstructionWords[] = {
106    (7 << 16) | uint32_t(spv::Op::OpAccessChain), 100, 101, 102, 103, 104, 105};
107
108// The operands that would be parsed from kSampleAccessChainInstructionWords.
109spv_parsed_operand_t kSampleAccessChainOperands[] = {
110    {1, 1, SPV_OPERAND_TYPE_RESULT_ID, SPV_NUMBER_NONE, 0},
111    {2, 1, SPV_OPERAND_TYPE_TYPE_ID, SPV_NUMBER_NONE, 0},
112    {3, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
113    {4, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
114    {5, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
115    {6, 1, SPV_OPERAND_TYPE_ID, SPV_NUMBER_NONE, 0},
116};
117
118// A valid parse of kSampleAccessChainInstructionWords
119spv_parsed_instruction_t kSampleAccessChainInstruction = {
120    kSampleAccessChainInstructionWords,
121    uint16_t(7),
122    uint16_t(spv::Op::OpAccessChain),
123    SPV_EXT_INST_TYPE_NONE,
124    100,  // type id
125    101,  // result id
126    kSampleAccessChainOperands,
127    6};
128
129// The words for an OpControlBarrier instruction.
130uint32_t kSampleControlBarrierInstructionWords[] = {
131    (4 << 16) | uint32_t(spv::Op::OpControlBarrier), 100, 101, 102};
132
133// The operands that would be parsed from kSampleControlBarrierInstructionWords.
134spv_parsed_operand_t kSampleControlBarrierOperands[] = {
135    {1, 1, SPV_OPERAND_TYPE_SCOPE_ID, SPV_NUMBER_NONE, 0},  // Execution
136    {2, 1, SPV_OPERAND_TYPE_SCOPE_ID, SPV_NUMBER_NONE, 0},  // Memory
137    {3, 1, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID, SPV_NUMBER_NONE,
138     0},  // Semantics
139};
140
141// A valid parse of kSampleControlBarrierInstructionWords
142spv_parsed_instruction_t kSampleControlBarrierInstruction = {
143    kSampleControlBarrierInstructionWords,
144    uint16_t(4),
145    uint16_t(spv::Op::OpControlBarrier),
146    SPV_EXT_INST_TYPE_NONE,
147    0,  // type id
148    0,  // result id
149    kSampleControlBarrierOperands,
150    3};
151
152TEST(InstructionTest, CreateWithOpcodeAndOperands) {
153  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
154  Instruction inst(&context, kSampleParsedInstruction);
155  EXPECT_EQ(spv::Op::OpTypeInt, inst.opcode());
156  EXPECT_EQ(0u, inst.type_id());
157  EXPECT_EQ(44u, inst.result_id());
158  EXPECT_EQ(3u, inst.NumOperands());
159  EXPECT_EQ(3u, inst.NumOperandWords());
160  EXPECT_EQ(2u, inst.NumInOperandWords());
161}
162
163TEST(InstructionTest, GetOperand) {
164  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
165  Instruction inst(&context, kSampleParsedInstruction);
166  EXPECT_THAT(inst.GetOperand(0).words, Eq(std::vector<uint32_t>{44}));
167  EXPECT_THAT(inst.GetOperand(1).words, Eq(std::vector<uint32_t>{32}));
168  EXPECT_THAT(inst.GetOperand(2).words, Eq(std::vector<uint32_t>{1}));
169}
170
171TEST(InstructionTest, GetInOperand) {
172  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
173  Instruction inst(&context, kSampleParsedInstruction);
174  EXPECT_THAT(inst.GetInOperand(0).words, Eq(std::vector<uint32_t>{32}));
175  EXPECT_THAT(inst.GetInOperand(1).words, Eq(std::vector<uint32_t>{1}));
176}
177
178TEST(InstructionTest, OperandConstIterators) {
179  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
180  Instruction inst(&context, kSampleParsedInstruction);
181  // Spot check iteration across operands.
182  auto cbegin = inst.cbegin();
183  auto cend = inst.cend();
184  EXPECT_NE(cend, inst.cbegin());
185
186  auto citer = inst.cbegin();
187  for (int i = 0; i < 3; ++i, ++citer) {
188    const auto& operand = *citer;
189    EXPECT_THAT(operand.type, Eq(kSampleParsedOperands[i].type));
190    EXPECT_THAT(operand.words,
191                Eq(std::vector<uint32_t>{kSampleInstructionWords[i + 1]}));
192    EXPECT_NE(cend, citer);
193  }
194  EXPECT_EQ(cend, citer);
195
196  // Check that cbegin and cend have not changed.
197  EXPECT_EQ(cbegin, inst.cbegin());
198  EXPECT_EQ(cend, inst.cend());
199
200  // Check arithmetic.
201  const Operand& operand2 = *(inst.cbegin() + 2);
202  EXPECT_EQ(SPV_OPERAND_TYPE_LITERAL_INTEGER, operand2.type);
203}
204
205TEST(InstructionTest, OperandIterators) {
206  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
207  Instruction inst(&context, kSampleParsedInstruction);
208  // Spot check iteration across operands, with mutable iterators.
209  auto begin = inst.begin();
210  auto end = inst.end();
211  EXPECT_NE(end, inst.begin());
212
213  auto iter = inst.begin();
214  for (int i = 0; i < 3; ++i, ++iter) {
215    const auto& operand = *iter;
216    EXPECT_THAT(operand.type, Eq(kSampleParsedOperands[i].type));
217    EXPECT_THAT(operand.words,
218                Eq(std::vector<uint32_t>{kSampleInstructionWords[i + 1]}));
219    EXPECT_NE(end, iter);
220  }
221  EXPECT_EQ(end, iter);
222
223  // Check that begin and end have not changed.
224  EXPECT_EQ(begin, inst.begin());
225  EXPECT_EQ(end, inst.end());
226
227  // Check arithmetic.
228  Operand& operand2 = *(inst.begin() + 2);
229  EXPECT_EQ(SPV_OPERAND_TYPE_LITERAL_INTEGER, operand2.type);
230
231  // Check mutation through an iterator.
232  operand2.type = SPV_OPERAND_TYPE_TYPE_ID;
233  EXPECT_EQ(SPV_OPERAND_TYPE_TYPE_ID, (*(inst.cbegin() + 2)).type);
234}
235
236TEST(InstructionTest, ForInIdStandardIdTypes) {
237  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
238  Instruction inst(&context, kSampleAccessChainInstruction);
239
240  std::vector<uint32_t> ids;
241  inst.ForEachInId([&ids](const uint32_t* idptr) { ids.push_back(*idptr); });
242  EXPECT_THAT(ids, Eq(std::vector<uint32_t>{102, 103, 104, 105}));
243
244  ids.clear();
245  inst.ForEachInId([&ids](uint32_t* idptr) { ids.push_back(*idptr); });
246  EXPECT_THAT(ids, Eq(std::vector<uint32_t>{102, 103, 104, 105}));
247}
248
249TEST(InstructionTest, ForInIdNonstandardIdTypes) {
250  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
251  Instruction inst(&context, kSampleControlBarrierInstruction);
252
253  std::vector<uint32_t> ids;
254  inst.ForEachInId([&ids](const uint32_t* idptr) { ids.push_back(*idptr); });
255  EXPECT_THAT(ids, Eq(std::vector<uint32_t>{100, 101, 102}));
256
257  ids.clear();
258  inst.ForEachInId([&ids](uint32_t* idptr) { ids.push_back(*idptr); });
259  EXPECT_THAT(ids, Eq(std::vector<uint32_t>{100, 101, 102}));
260}
261
262TEST(InstructionTest, UniqueIds) {
263  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
264  Instruction inst1(&context);
265  Instruction inst2(&context);
266  EXPECT_NE(inst1.unique_id(), inst2.unique_id());
267}
268
269TEST(InstructionTest, CloneUniqueIdDifferent) {
270  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
271  Instruction inst(&context);
272  std::unique_ptr<Instruction> clone(inst.Clone(&context));
273  EXPECT_EQ(inst.context(), clone->context());
274  EXPECT_NE(inst.unique_id(), clone->unique_id());
275}
276
277TEST(InstructionTest, CloneDifferentContext) {
278  IRContext c1(SPV_ENV_UNIVERSAL_1_2, nullptr);
279  IRContext c2(SPV_ENV_UNIVERSAL_1_2, nullptr);
280  Instruction inst(&c1);
281  std::unique_ptr<Instruction> clone(inst.Clone(&c2));
282  EXPECT_EQ(&c1, inst.context());
283  EXPECT_EQ(&c2, clone->context());
284  EXPECT_NE(&c1, &c2);
285}
286
287TEST(InstructionTest, CloneDifferentContextDifferentUniqueId) {
288  IRContext c1(SPV_ENV_UNIVERSAL_1_2, nullptr);
289  IRContext c2(SPV_ENV_UNIVERSAL_1_2, nullptr);
290  Instruction inst(&c1);
291  Instruction other(&c2);
292  std::unique_ptr<Instruction> clone(inst.Clone(&c2));
293  EXPECT_EQ(&c2, clone->context());
294  EXPECT_NE(other.unique_id(), clone->unique_id());
295}
296
297TEST(InstructionTest, EqualsEqualsOperator) {
298  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
299  Instruction i1(&context);
300  Instruction i2(&context);
301  std::unique_ptr<Instruction> clone(i1.Clone(&context));
302  EXPECT_TRUE(i1 == i1);
303  EXPECT_FALSE(i1 == i2);
304  EXPECT_FALSE(i1 == *clone);
305  EXPECT_FALSE(i2 == *clone);
306}
307
308TEST(InstructionTest, LessThanOperator) {
309  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
310  Instruction i1(&context);
311  Instruction i2(&context);
312  std::unique_ptr<Instruction> clone(i1.Clone(&context));
313  EXPECT_TRUE(i1 < i2);
314  EXPECT_TRUE(i1 < *clone);
315  EXPECT_TRUE(i2 < *clone);
316}
317
318TEST_F(DescriptorTypeTest, StorageImage) {
319  const std::string text = R"(
320               OpCapability Shader
321          %1 = OpExtInstImport "GLSL.std.450"
322               OpMemoryModel Logical GLSL450
323               OpEntryPoint Fragment %2 "main"
324               OpExecutionMode %2 OriginUpperLeft
325               OpSource GLSL 430
326               OpName %3 "myStorageImage"
327               OpDecorate %3 DescriptorSet 0
328               OpDecorate %3 Binding 0
329          %4 = OpTypeVoid
330          %5 = OpTypeFunction %4
331          %6 = OpTypeFloat 32
332          %7 = OpTypeImage %6 2D 0 0 0 2 R32f
333          %8 = OpTypePointer UniformConstant %7
334          %3 = OpVariable %8 UniformConstant
335          %2 = OpFunction %4 None %5
336          %9 = OpLabel
337         %10 = OpCopyObject %8 %3
338               OpReturn
339               OpFunctionEnd
340)";
341
342  std::unique_ptr<IRContext> context =
343      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
344  Instruction* type = context->get_def_use_mgr()->GetDef(8);
345  EXPECT_TRUE(type->IsVulkanStorageImage());
346  EXPECT_FALSE(type->IsVulkanSampledImage());
347  EXPECT_FALSE(type->IsVulkanStorageTexelBuffer());
348  EXPECT_FALSE(type->IsVulkanStorageBuffer());
349  EXPECT_FALSE(type->IsVulkanUniformBuffer());
350
351  Instruction* variable = context->get_def_use_mgr()->GetDef(3);
352  EXPECT_FALSE(variable->IsReadOnlyPointer());
353
354  Instruction* object_copy = context->get_def_use_mgr()->GetDef(10);
355  EXPECT_FALSE(object_copy->IsReadOnlyPointer());
356}
357
358TEST_F(DescriptorTypeTest, SampledImage) {
359  const std::string text = R"(
360               OpCapability Shader
361          %1 = OpExtInstImport "GLSL.std.450"
362               OpMemoryModel Logical GLSL450
363               OpEntryPoint Fragment %2 "main"
364               OpExecutionMode %2 OriginUpperLeft
365               OpSource GLSL 430
366               OpName %3 "myStorageImage"
367               OpDecorate %3 DescriptorSet 0
368               OpDecorate %3 Binding 0
369          %4 = OpTypeVoid
370          %5 = OpTypeFunction %4
371          %6 = OpTypeFloat 32
372          %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
373          %8 = OpTypePointer UniformConstant %7
374          %3 = OpVariable %8 UniformConstant
375          %2 = OpFunction %4 None %5
376          %9 = OpLabel
377         %10 = OpCopyObject %8 %3
378               OpReturn
379               OpFunctionEnd
380)";
381
382  std::unique_ptr<IRContext> context =
383      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
384  Instruction* type = context->get_def_use_mgr()->GetDef(8);
385  EXPECT_FALSE(type->IsVulkanStorageImage());
386  EXPECT_TRUE(type->IsVulkanSampledImage());
387  EXPECT_FALSE(type->IsVulkanStorageTexelBuffer());
388  EXPECT_FALSE(type->IsVulkanStorageBuffer());
389  EXPECT_FALSE(type->IsVulkanUniformBuffer());
390
391  Instruction* variable = context->get_def_use_mgr()->GetDef(3);
392  EXPECT_TRUE(variable->IsReadOnlyPointer());
393
394  Instruction* object_copy = context->get_def_use_mgr()->GetDef(10);
395  EXPECT_TRUE(object_copy->IsReadOnlyPointer());
396}
397
398TEST_F(DescriptorTypeTest, StorageTexelBuffer) {
399  const std::string text = R"(
400               OpCapability Shader
401          %1 = OpExtInstImport "GLSL.std.450"
402               OpMemoryModel Logical GLSL450
403               OpEntryPoint Fragment %2 "main"
404               OpExecutionMode %2 OriginUpperLeft
405               OpSource GLSL 430
406               OpName %3 "myStorageImage"
407               OpDecorate %3 DescriptorSet 0
408               OpDecorate %3 Binding 0
409          %4 = OpTypeVoid
410          %5 = OpTypeFunction %4
411          %6 = OpTypeFloat 32
412          %7 = OpTypeImage %6 Buffer 0 0 0 2 R32f
413          %8 = OpTypePointer UniformConstant %7
414          %3 = OpVariable %8 UniformConstant
415          %2 = OpFunction %4 None %5
416          %9 = OpLabel
417         %10 = OpCopyObject %8 %3
418               OpReturn
419               OpFunctionEnd
420)";
421
422  std::unique_ptr<IRContext> context =
423      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
424  Instruction* type = context->get_def_use_mgr()->GetDef(8);
425  EXPECT_FALSE(type->IsVulkanStorageImage());
426  EXPECT_FALSE(type->IsVulkanSampledImage());
427  EXPECT_TRUE(type->IsVulkanStorageTexelBuffer());
428  EXPECT_FALSE(type->IsVulkanStorageBuffer());
429  EXPECT_FALSE(type->IsVulkanUniformBuffer());
430
431  Instruction* variable = context->get_def_use_mgr()->GetDef(3);
432  EXPECT_FALSE(variable->IsReadOnlyPointer());
433
434  Instruction* object_copy = context->get_def_use_mgr()->GetDef(10);
435  EXPECT_FALSE(object_copy->IsReadOnlyPointer());
436}
437
438TEST_F(DescriptorTypeTest, StorageBuffer) {
439  const std::string text = R"(
440               OpCapability Shader
441          %1 = OpExtInstImport "GLSL.std.450"
442               OpMemoryModel Logical GLSL450
443               OpEntryPoint Fragment %2 "main"
444               OpExecutionMode %2 OriginUpperLeft
445               OpSource GLSL 430
446               OpName %3 "myStorageImage"
447               OpDecorate %3 DescriptorSet 0
448               OpDecorate %3 Binding 0
449               OpDecorate %9 BufferBlock
450          %4 = OpTypeVoid
451          %5 = OpTypeFunction %4
452          %6 = OpTypeFloat 32
453          %7 = OpTypeVector %6 4
454          %8 = OpTypeRuntimeArray %7
455          %9 = OpTypeStruct %8
456         %10 = OpTypePointer Uniform %9
457          %3 = OpVariable %10 Uniform
458          %2 = OpFunction %4 None %5
459         %11 = OpLabel
460         %12 = OpCopyObject %8 %3
461               OpReturn
462               OpFunctionEnd
463)";
464
465  std::unique_ptr<IRContext> context =
466      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
467  Instruction* type = context->get_def_use_mgr()->GetDef(10);
468  EXPECT_FALSE(type->IsVulkanStorageImage());
469  EXPECT_FALSE(type->IsVulkanSampledImage());
470  EXPECT_FALSE(type->IsVulkanStorageTexelBuffer());
471  EXPECT_TRUE(type->IsVulkanStorageBuffer());
472  EXPECT_FALSE(type->IsVulkanUniformBuffer());
473
474  Instruction* variable = context->get_def_use_mgr()->GetDef(3);
475  EXPECT_FALSE(variable->IsReadOnlyPointer());
476
477  Instruction* object_copy = context->get_def_use_mgr()->GetDef(12);
478  EXPECT_FALSE(object_copy->IsReadOnlyPointer());
479}
480
481TEST_F(DescriptorTypeTest, UniformBuffer) {
482  const std::string text = R"(
483               OpCapability Shader
484          %1 = OpExtInstImport "GLSL.std.450"
485               OpMemoryModel Logical GLSL450
486               OpEntryPoint Fragment %2 "main"
487               OpExecutionMode %2 OriginUpperLeft
488               OpSource GLSL 430
489               OpName %3 "myStorageImage"
490               OpDecorate %3 DescriptorSet 0
491               OpDecorate %3 Binding 0
492               OpDecorate %9 Block
493          %4 = OpTypeVoid
494          %5 = OpTypeFunction %4
495          %6 = OpTypeFloat 32
496          %7 = OpTypeVector %6 4
497          %8 = OpTypeRuntimeArray %7
498          %9 = OpTypeStruct %8
499         %10 = OpTypePointer Uniform %9
500          %3 = OpVariable %10 Uniform
501          %2 = OpFunction %4 None %5
502         %11 = OpLabel
503         %12 = OpCopyObject %10 %3
504               OpReturn
505               OpFunctionEnd
506)";
507
508  std::unique_ptr<IRContext> context =
509      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
510  Instruction* type = context->get_def_use_mgr()->GetDef(10);
511  EXPECT_FALSE(type->IsVulkanStorageImage());
512  EXPECT_FALSE(type->IsVulkanSampledImage());
513  EXPECT_FALSE(type->IsVulkanStorageTexelBuffer());
514  EXPECT_FALSE(type->IsVulkanStorageBuffer());
515  EXPECT_TRUE(type->IsVulkanUniformBuffer());
516
517  Instruction* variable = context->get_def_use_mgr()->GetDef(3);
518  EXPECT_TRUE(variable->IsReadOnlyPointer());
519
520  Instruction* object_copy = context->get_def_use_mgr()->GetDef(12);
521  EXPECT_TRUE(object_copy->IsReadOnlyPointer());
522}
523
524TEST_F(DescriptorTypeTest, NonWritableIsReadOnly) {
525  const std::string text = R"(
526               OpCapability Shader
527          %1 = OpExtInstImport "GLSL.std.450"
528               OpMemoryModel Logical GLSL450
529               OpEntryPoint Fragment %2 "main"
530               OpExecutionMode %2 OriginUpperLeft
531               OpSource GLSL 430
532               OpName %3 "myStorageImage"
533               OpDecorate %3 DescriptorSet 0
534               OpDecorate %3 Binding 0
535               OpDecorate %9 BufferBlock
536               OpDecorate %3 NonWritable
537          %4 = OpTypeVoid
538          %5 = OpTypeFunction %4
539          %6 = OpTypeFloat 32
540          %7 = OpTypeVector %6 4
541          %8 = OpTypeRuntimeArray %7
542          %9 = OpTypeStruct %8
543         %10 = OpTypePointer Uniform %9
544          %3 = OpVariable %10 Uniform
545          %2 = OpFunction %4 None %5
546         %11 = OpLabel
547         %12 = OpCopyObject %8 %3
548               OpReturn
549               OpFunctionEnd
550)";
551
552  std::unique_ptr<IRContext> context =
553      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
554  Instruction* variable = context->get_def_use_mgr()->GetDef(3);
555  EXPECT_TRUE(variable->IsReadOnlyPointer());
556
557  // This demonstrates that the check for whether a pointer is read-only is not
558  // precise: copying a NonWritable-decorated variable can yield a pointer that
559  // the check does not regard as read-only.
560  Instruction* object_copy = context->get_def_use_mgr()->GetDef(12);
561  EXPECT_FALSE(object_copy->IsReadOnlyPointer());
562}
563
564TEST_F(DescriptorTypeTest, AccessChainIntoReadOnlyStructIsReadOnly) {
565  const std::string text = R"(
566               OpCapability Shader
567          %1 = OpExtInstImport "GLSL.std.450"
568               OpMemoryModel Logical GLSL450
569               OpEntryPoint Fragment %2 "main"
570               OpExecutionMode %2 OriginUpperLeft
571               OpSource ESSL 320
572               OpMemberDecorate %3 0 Offset 0
573               OpMemberDecorate %3 1 Offset 4
574               OpDecorate %3 Block
575          %4 = OpTypeVoid
576          %5 = OpTypeFunction %4
577          %6 = OpTypeInt 32 1
578          %7 = OpTypePointer Function %6
579          %8 = OpTypeFloat 32
580          %3 = OpTypeStruct %6 %8
581          %9 = OpTypePointer PushConstant %3
582         %10 = OpVariable %9 PushConstant
583         %11 = OpConstant %6 0
584         %12 = OpTypePointer PushConstant %6
585         %13 = OpConstant %6 1
586         %14 = OpTypePointer PushConstant %8
587          %2 = OpFunction %4 None %5
588         %15 = OpLabel
589         %16 = OpVariable %7 Function
590         %17 = OpAccessChain %12 %10 %11
591         %18 = OpAccessChain %14 %10 %13
592               OpReturn
593               OpFunctionEnd
594)";
595
596  std::unique_ptr<IRContext> context =
597      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
598
599  Instruction* push_constant_struct_variable =
600      context->get_def_use_mgr()->GetDef(10);
601  EXPECT_TRUE(push_constant_struct_variable->IsReadOnlyPointer());
602
603  Instruction* push_constant_struct_field_0 =
604      context->get_def_use_mgr()->GetDef(17);
605  EXPECT_TRUE(push_constant_struct_field_0->IsReadOnlyPointer());
606
607  Instruction* push_constant_struct_field_1 =
608      context->get_def_use_mgr()->GetDef(18);
609  EXPECT_TRUE(push_constant_struct_field_1->IsReadOnlyPointer());
610}
611
612TEST_F(DescriptorTypeTest, ReadOnlyPointerParameter) {
613  const std::string text = R"(
614               OpCapability Shader
615          %1 = OpExtInstImport "GLSL.std.450"
616               OpMemoryModel Logical GLSL450
617               OpEntryPoint Fragment %2 "main"
618               OpExecutionMode %2 OriginUpperLeft
619               OpSource ESSL 320
620               OpMemberDecorate %3 0 Offset 0
621               OpMemberDecorate %3 1 Offset 4
622               OpDecorate %3 Block
623          %4 = OpTypeVoid
624          %5 = OpTypeFunction %4
625          %6 = OpTypeInt 32 1
626          %7 = OpTypePointer Function %6
627          %8 = OpTypeFloat 32
628          %3 = OpTypeStruct %6 %8
629          %9 = OpTypePointer PushConstant %3
630         %10 = OpVariable %9 PushConstant
631         %11 = OpConstant %6 0
632         %12 = OpTypePointer PushConstant %6
633         %13 = OpConstant %6 1
634         %14 = OpTypePointer PushConstant %8
635         %15 = OpTypeFunction %4 %9
636          %2 = OpFunction %4 None %5
637         %16 = OpLabel
638         %17 = OpVariable %7 Function
639         %18 = OpAccessChain %12 %10 %11
640         %19 = OpAccessChain %14 %10 %13
641               OpReturn
642               OpFunctionEnd
643         %20 = OpFunction %4 None %15
644         %21 = OpFunctionParameter %9
645         %22 = OpLabel
646               OpReturn
647               OpFunctionEnd
648)";
649
650  std::unique_ptr<IRContext> context =
651      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
652
653  Instruction* push_constant_struct_parameter =
654      context->get_def_use_mgr()->GetDef(21);
655  EXPECT_TRUE(push_constant_struct_parameter->IsReadOnlyPointer());
656}
657
658TEST_F(OpaqueTypeTest, BaseOpaqueTypesShader) {
659  const std::string text = R"(
660               OpCapability Shader
661          %1 = OpExtInstImport "GLSL.std.450"
662               OpMemoryModel Logical GLSL450
663               OpEntryPoint Fragment %2 "main"
664               OpExecutionMode %2 OriginUpperLeft
665               OpSource GLSL 430
666          %3 = OpTypeVoid
667          %4 = OpTypeFunction %3
668          %5 = OpTypeFloat 32
669          %6 = OpTypeImage %5 2D 1 0 0 1 Unknown
670          %7 = OpTypeSampler
671          %8 = OpTypeSampledImage %6
672          %9 = OpTypeRuntimeArray %5
673          %2 = OpFunction %3 None %4
674         %10 = OpLabel
675               OpReturn
676               OpFunctionEnd
677)";
678
679  std::unique_ptr<IRContext> context =
680      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
681  Instruction* image_type = context->get_def_use_mgr()->GetDef(6);
682  EXPECT_TRUE(image_type->IsOpaqueType());
683  Instruction* sampler_type = context->get_def_use_mgr()->GetDef(7);
684  EXPECT_TRUE(sampler_type->IsOpaqueType());
685  Instruction* sampled_image_type = context->get_def_use_mgr()->GetDef(8);
686  EXPECT_TRUE(sampled_image_type->IsOpaqueType());
687  Instruction* runtime_array_type = context->get_def_use_mgr()->GetDef(9);
688  EXPECT_TRUE(runtime_array_type->IsOpaqueType());
689  Instruction* float_type = context->get_def_use_mgr()->GetDef(5);
690  EXPECT_FALSE(float_type->IsOpaqueType());
691  Instruction* void_type = context->get_def_use_mgr()->GetDef(3);
692  EXPECT_FALSE(void_type->IsOpaqueType());
693}
694
695TEST_F(OpaqueTypeTest, OpaqueStructTypes) {
696  const std::string text = R"(
697               OpCapability Shader
698          %1 = OpExtInstImport "GLSL.std.450"
699               OpMemoryModel Logical GLSL450
700               OpEntryPoint Fragment %2 "main"
701               OpExecutionMode %2 OriginUpperLeft
702               OpSource GLSL 430
703          %3 = OpTypeVoid
704          %4 = OpTypeFunction %3
705          %5 = OpTypeFloat 32
706          %6 = OpTypeRuntimeArray %5
707          %7 = OpTypeStruct %6 %6
708          %8 = OpTypeStruct %5 %6
709          %9 = OpTypeStruct %6 %5
710         %10 = OpTypeStruct %7
711          %2 = OpFunction %3 None %4
712         %11 = OpLabel
713               OpReturn
714               OpFunctionEnd
715)";
716
717  std::unique_ptr<IRContext> context =
718      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
719  for (int i = 7; i <= 10; i++) {
720    Instruction* type = context->get_def_use_mgr()->GetDef(i);
721    EXPECT_TRUE(type->IsOpaqueType());
722  }
723}
724
725TEST_F(GetBaseTest, SampleImage) {
726  const std::string text = R"(
727               OpCapability Shader
728          %1 = OpExtInstImport "GLSL.std.450"
729               OpMemoryModel Logical GLSL450
730               OpEntryPoint Fragment %2 "main"
731               OpExecutionMode %2 OriginUpperLeft
732               OpSource GLSL 430
733               OpName %3 "myStorageImage"
734               OpDecorate %3 DescriptorSet 0
735               OpDecorate %3 Binding 0
736          %4 = OpTypeVoid
737          %5 = OpTypeFunction %4
738          %6 = OpTypeFloat 32
739          %7 = OpTypeVector %6 2
740          %8 = OpTypeVector %6 4
741          %9 = OpConstant %6 0
742         %10 = OpConstantComposite %7 %9 %9
743         %11 = OpTypeImage %6 2D 0 0 0 1 R32f
744         %12 = OpTypePointer UniformConstant %11
745          %3 = OpVariable %12 UniformConstant
746         %13 = OpTypeSampledImage %11
747         %14 = OpTypeSampler
748         %15 = OpTypePointer UniformConstant %14
749         %16 = OpVariable %15 UniformConstant
750          %2 = OpFunction %4 None %5
751         %17 = OpLabel
752         %18 = OpLoad %11 %3
753         %19 = OpLoad %14 %16
754         %20 = OpSampledImage %13 %18 %19
755         %21 = OpImageSampleImplicitLod %8 %20 %10
756               OpReturn
757               OpFunctionEnd
758)";
759
760  std::unique_ptr<IRContext> context =
761      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
762  Instruction* load = context->get_def_use_mgr()->GetDef(21);
763  Instruction* base = context->get_def_use_mgr()->GetDef(20);
764  EXPECT_TRUE(load->GetBaseAddress() == base);
765}
766
767TEST_F(GetBaseTest, PtrAccessChain) {
768  const std::string text = R"(
769               OpCapability VariablePointers
770               OpMemoryModel Logical GLSL450
771               OpEntryPoint Fragment %1 "PSMain" %2
772               OpExecutionMode %1 OriginUpperLeft
773       %void = OpTypeVoid
774          %4 = OpTypeFunction %void
775      %float = OpTypeFloat 32
776    %v4float = OpTypeVector %float 4
777        %int = OpTypeInt 32 8388353
778      %int_0 = OpConstant %int 0
779%_ptr_Function_v4float = OpTypePointer Function %v4float
780          %2 = OpVariable %_ptr_Function_v4float Input
781          %1 = OpFunction %void None %4
782         %10 = OpLabel
783         %11 = OpPtrAccessChain %_ptr_Function_v4float %2 %int_0
784         %12 = OpLoad %v4float %11
785               OpReturn
786               OpFunctionEnd
787)";
788
789  std::unique_ptr<IRContext> context =
790      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
791  Instruction* load = context->get_def_use_mgr()->GetDef(12);
792  Instruction* base = context->get_def_use_mgr()->GetDef(2);
793  EXPECT_TRUE(load->GetBaseAddress() == base);
794}
795
796TEST_F(GetBaseTest, ImageRead) {
797  const std::string text = R"(
798               OpCapability Shader
799          %1 = OpExtInstImport "GLSL.std.450"
800               OpMemoryModel Logical GLSL450
801               OpEntryPoint Fragment %2 "main"
802               OpExecutionMode %2 OriginUpperLeft
803               OpSource GLSL 430
804               OpName %3 "myStorageImage"
805               OpDecorate %3 DescriptorSet 0
806               OpDecorate %3 Binding 0
807          %4 = OpTypeVoid
808          %5 = OpTypeFunction %4
809          %6 = OpTypeInt 32 0
810          %7 = OpTypeVector %6 2
811          %8 = OpConstant %6 0
812          %9 = OpConstantComposite %7 %8 %8
813         %10 = OpTypeImage %6 2D 0 0 0 2 R32f
814         %11 = OpTypePointer UniformConstant %10
815          %3 = OpVariable %11 UniformConstant
816          %2 = OpFunction %4 None %5
817         %12 = OpLabel
818         %13 = OpLoad %10 %3
819         %14 = OpImageRead %6 %13 %9
820               OpReturn
821               OpFunctionEnd
822)";
823
824  std::unique_ptr<IRContext> context =
825      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
826  Instruction* load = context->get_def_use_mgr()->GetDef(14);
827  Instruction* base = context->get_def_use_mgr()->GetDef(13);
828  EXPECT_TRUE(load->GetBaseAddress() == base);
829}
830
831TEST_F(ValidBasePointerTest, OpSelectBadNoVariablePointersStorageBuffer) {
832  const std::string text = R"(
833OpCapability Shader
834OpMemoryModel Logical GLSL450
835OpEntryPoint Fragment %1 "func"
836%2 = OpTypeVoid
837%3 = OpTypeInt 32 0
838%4 = OpTypePointer StorageBuffer %3
839%5 = OpVariable %4 StorageBuffer
840%6 = OpTypeFunction %2
841%7 = OpTypeBool
842%8 = OpConstantTrue %7
843%1 = OpFunction %2 None %6
844%9 = OpLabel
845%10 = OpSelect %4 %8 %5 %5
846OpReturn
847OpFunctionEnd
848)";
849
850  std::unique_ptr<IRContext> context =
851      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
852  EXPECT_NE(context, nullptr);
853  Instruction* select = context->get_def_use_mgr()->GetDef(10);
854  EXPECT_NE(select, nullptr);
855  EXPECT_FALSE(select->IsValidBasePointer());
856}
857
858TEST_F(ValidBasePointerTest, OpSelectBadNoVariablePointers) {
859  const std::string text = R"(
860OpCapability Shader
861OpCapability VariablePointersStorageBuffer
862OpMemoryModel Logical GLSL450
863OpEntryPoint Fragment %1 "func"
864%2 = OpTypeVoid
865%3 = OpTypeInt 32 0
866%4 = OpTypePointer Workgroup %3
867%5 = OpVariable %4 Workgroup
868%6 = OpTypeFunction %2
869%7 = OpTypeBool
870%8 = OpConstantTrue %7
871%1 = OpFunction %2 None %6
872%9 = OpLabel
873%10 = OpSelect %4 %8 %5 %5
874OpReturn
875OpFunctionEnd
876)";
877
878  std::unique_ptr<IRContext> context =
879      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
880  EXPECT_NE(context, nullptr);
881  Instruction* select = context->get_def_use_mgr()->GetDef(10);
882  EXPECT_NE(select, nullptr);
883  EXPECT_FALSE(select->IsValidBasePointer());
884}
885
886TEST_F(ValidBasePointerTest, OpSelectGoodVariablePointersStorageBuffer) {
887  const std::string text = R"(
888OpCapability Shader
889OpCapability VariablePointersStorageBuffer
890OpMemoryModel Logical GLSL450
891OpEntryPoint Fragment %1 "func"
892%2 = OpTypeVoid
893%3 = OpTypeInt 32 0
894%4 = OpTypePointer StorageBuffer %3
895%5 = OpVariable %4 StorageBuffer
896%6 = OpTypeFunction %2
897%7 = OpTypeBool
898%8 = OpConstantTrue %7
899%1 = OpFunction %2 None %6
900%9 = OpLabel
901%10 = OpSelect %4 %8 %5 %5
902OpReturn
903OpFunctionEnd
904)";
905
906  std::unique_ptr<IRContext> context =
907      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
908  EXPECT_NE(context, nullptr);
909  Instruction* select = context->get_def_use_mgr()->GetDef(10);
910  EXPECT_NE(select, nullptr);
911  EXPECT_TRUE(select->IsValidBasePointer());
912}
913
914TEST_F(ValidBasePointerTest, OpSelectGoodVariablePointers) {
915  const std::string text = R"(
916OpCapability Shader
917OpCapability VariablePointers
918OpMemoryModel Logical GLSL450
919OpEntryPoint Fragment %1 "func"
920%2 = OpTypeVoid
921%3 = OpTypeInt 32 0
922%4 = OpTypePointer Workgroup %3
923%5 = OpVariable %4 Workgroup
924%6 = OpTypeFunction %2
925%7 = OpTypeBool
926%8 = OpConstantTrue %7
927%1 = OpFunction %2 None %6
928%9 = OpLabel
929%10 = OpSelect %4 %8 %5 %5
930OpReturn
931OpFunctionEnd
932)";
933
934  std::unique_ptr<IRContext> context =
935      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
936  EXPECT_NE(context, nullptr);
937  Instruction* select = context->get_def_use_mgr()->GetDef(10);
938  EXPECT_NE(select, nullptr);
939  EXPECT_TRUE(select->IsValidBasePointer());
940}
941
942TEST_F(ValidBasePointerTest, OpConstantNullBadNoVariablePointersStorageBuffer) {
943  const std::string text = R"(
944OpCapability Shader
945OpMemoryModel Logical GLSL450
946OpEntryPoint Fragment %1 "func"
947%2 = OpTypeVoid
948%3 = OpTypeInt 32 0
949%4 = OpTypePointer StorageBuffer %3
950%5 = OpConstantNull %4
951%6 = OpTypeFunction %2
952%1 = OpFunction %2 None %6
953%7 = OpLabel
954OpReturn
955OpFunctionEnd
956)";
957
958  std::unique_ptr<IRContext> context =
959      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
960  EXPECT_NE(context, nullptr);
961  Instruction* null_inst = context->get_def_use_mgr()->GetDef(5);
962  EXPECT_NE(null_inst, nullptr);
963  EXPECT_FALSE(null_inst->IsValidBasePointer());
964}
965
966TEST_F(ValidBasePointerTest, OpConstantNullBadNoVariablePointers) {
967  const std::string text = R"(
968OpCapability Shader
969OpCapability VariablePointersStorageBuffer
970OpMemoryModel Logical GLSL450
971OpEntryPoint Fragment %1 "func"
972%2 = OpTypeVoid
973%3 = OpTypeInt 32 0
974%4 = OpTypePointer Workgroup %3
975%5 = OpConstantNull %4
976%6 = OpTypeFunction %2
977%1 = OpFunction %2 None %6
978%7 = OpLabel
979OpReturn
980OpFunctionEnd
981)";
982
983  std::unique_ptr<IRContext> context =
984      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
985  EXPECT_NE(context, nullptr);
986  Instruction* null_inst = context->get_def_use_mgr()->GetDef(5);
987  EXPECT_NE(null_inst, nullptr);
988  EXPECT_FALSE(null_inst->IsValidBasePointer());
989}
990
991TEST_F(ValidBasePointerTest, OpConstantNullGoodVariablePointersStorageBuffer) {
992  const std::string text = R"(
993OpCapability Shader
994OpCapability VariablePointersStorageBuffer
995OpMemoryModel Logical GLSL450
996OpEntryPoint Fragment %1 "func"
997%2 = OpTypeVoid
998%3 = OpTypeInt 32 0
999%4 = OpTypePointer StorageBuffer %3
1000%5 = OpConstantNull %4
1001%6 = OpTypeFunction %2
1002%1 = OpFunction %2 None %6
1003%9 = OpLabel
1004OpReturn
1005OpFunctionEnd
1006)";
1007
1008  std::unique_ptr<IRContext> context =
1009      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1010  EXPECT_NE(context, nullptr);
1011  Instruction* null_inst = context->get_def_use_mgr()->GetDef(5);
1012  EXPECT_NE(null_inst, nullptr);
1013  EXPECT_TRUE(null_inst->IsValidBasePointer());
1014}
1015
1016TEST_F(ValidBasePointerTest, OpConstantNullGoodVariablePointers) {
1017  const std::string text = R"(
1018OpCapability Shader
1019OpCapability VariablePointers
1020OpMemoryModel Logical GLSL450
1021OpEntryPoint Fragment %1 "func"
1022%2 = OpTypeVoid
1023%3 = OpTypeInt 32 0
1024%4 = OpTypePointer Workgroup %3
1025%5 = OpConstantNull %4
1026%6 = OpTypeFunction %2
1027%1 = OpFunction %2 None %6
1028%7 = OpLabel
1029OpReturn
1030OpFunctionEnd
1031)";
1032
1033  std::unique_ptr<IRContext> context =
1034      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1035  EXPECT_NE(context, nullptr);
1036  Instruction* null_inst = context->get_def_use_mgr()->GetDef(5);
1037  EXPECT_NE(null_inst, nullptr);
1038  EXPECT_TRUE(null_inst->IsValidBasePointer());
1039}
1040
1041TEST_F(ValidBasePointerTest, OpPhiBadNoVariablePointersStorageBuffer) {
1042  const std::string text = R"(
1043OpCapability Shader
1044OpMemoryModel Logical GLSL450
1045OpEntryPoint Fragment %1 "func"
1046%2 = OpTypeVoid
1047%3 = OpTypeInt 32 0
1048%4 = OpTypePointer StorageBuffer %3
1049%5 = OpVariable %4 StorageBuffer
1050%6 = OpTypeFunction %2
1051%1 = OpFunction %2 None %6
1052%7 = OpLabel
1053OpBranch %8
1054%8 = OpLabel
1055%9 = OpPhi %4 %5 %7
1056OpReturn
1057OpFunctionEnd
1058)";
1059
1060  std::unique_ptr<IRContext> context =
1061      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1062  EXPECT_NE(context, nullptr);
1063  Instruction* phi = context->get_def_use_mgr()->GetDef(9);
1064  EXPECT_NE(phi, nullptr);
1065  EXPECT_FALSE(phi->IsValidBasePointer());
1066}
1067
1068TEST_F(ValidBasePointerTest, OpPhiBadNoVariablePointers) {
1069  const std::string text = R"(
1070OpCapability Shader
1071OpCapability VariablePointersStorageBuffer
1072OpMemoryModel Logical GLSL450
1073OpEntryPoint Fragment %1 "func"
1074%2 = OpTypeVoid
1075%3 = OpTypeInt 32 0
1076%4 = OpTypePointer Workgroup %3
1077%5 = OpVariable %4 Workgroup
1078%6 = OpTypeFunction %2
1079%1 = OpFunction %2 None %6
1080%7 = OpLabel
1081OpBranch %8
1082%8 = OpLabel
1083%9 = OpPhi %4 %5 %7
1084OpReturn
1085OpFunctionEnd
1086)";
1087
1088  std::unique_ptr<IRContext> context =
1089      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1090  EXPECT_NE(context, nullptr);
1091  Instruction* phi = context->get_def_use_mgr()->GetDef(9);
1092  EXPECT_NE(phi, nullptr);
1093  EXPECT_FALSE(phi->IsValidBasePointer());
1094}
1095
1096TEST_F(ValidBasePointerTest, OpPhiGoodVariablePointersStorageBuffer) {
1097  const std::string text = R"(
1098OpCapability Shader
1099OpCapability VariablePointersStorageBuffer
1100OpMemoryModel Logical GLSL450
1101OpEntryPoint Fragment %1 "func"
1102%2 = OpTypeVoid
1103%3 = OpTypeInt 32 0
1104%4 = OpTypePointer StorageBuffer %3
1105%5 = OpVariable %4 StorageBuffer
1106%6 = OpTypeFunction %2
1107%1 = OpFunction %2 None %6
1108%7 = OpLabel
1109OpBranch %8
1110%8 = OpLabel
1111%9 = OpPhi %4 %5 %7
1112OpReturn
1113OpFunctionEnd
1114)";
1115
1116  std::unique_ptr<IRContext> context =
1117      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1118  EXPECT_NE(context, nullptr);
1119  Instruction* phi = context->get_def_use_mgr()->GetDef(9);
1120  EXPECT_NE(phi, nullptr);
1121  EXPECT_TRUE(phi->IsValidBasePointer());
1122}
1123
1124TEST_F(ValidBasePointerTest, OpPhiGoodVariablePointers) {
1125  const std::string text = R"(
1126OpCapability Shader
1127OpCapability VariablePointers
1128OpMemoryModel Logical GLSL450
1129OpEntryPoint Fragment %1 "func"
1130%2 = OpTypeVoid
1131%3 = OpTypeInt 32 0
1132%4 = OpTypePointer Workgroup %3
1133%5 = OpVariable %4 Workgroup
1134%6 = OpTypeFunction %2
1135%1 = OpFunction %2 None %6
1136%7 = OpLabel
1137OpBranch %8
1138%8 = OpLabel
1139%9 = OpPhi %4 %5 %7
1140OpReturn
1141OpFunctionEnd
1142)";
1143
1144  std::unique_ptr<IRContext> context =
1145      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1146  EXPECT_NE(context, nullptr);
1147  Instruction* phi = context->get_def_use_mgr()->GetDef(9);
1148  EXPECT_NE(phi, nullptr);
1149  EXPECT_TRUE(phi->IsValidBasePointer());
1150}
1151
1152TEST_F(ValidBasePointerTest, OpFunctionCallBadNoVariablePointersStorageBuffer) {
1153  const std::string text = R"(
1154OpCapability Shader
1155OpMemoryModel Logical GLSL450
1156OpEntryPoint Fragment %1 "func"
1157%2 = OpTypeVoid
1158%3 = OpTypeInt 32 0
1159%4 = OpTypePointer StorageBuffer %3
1160%5 = OpConstantNull %4
1161%6 = OpTypeFunction %2
1162%7 = OpTypeFunction %4
1163%1 = OpFunction %2 None %6
1164%8 = OpLabel
1165%9 = OpFunctionCall %4 %10
1166OpReturn
1167OpFunctionEnd
1168%10 = OpFunction %4 None %7
1169%11 = OpLabel
1170OpReturnValue %5
1171OpFunctionEnd
1172)";
1173
1174  std::unique_ptr<IRContext> context =
1175      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1176  EXPECT_NE(context, nullptr);
1177  Instruction* null_inst = context->get_def_use_mgr()->GetDef(9);
1178  EXPECT_NE(null_inst, nullptr);
1179  EXPECT_FALSE(null_inst->IsValidBasePointer());
1180}
1181
1182TEST_F(ValidBasePointerTest, OpFunctionCallBadNoVariablePointers) {
1183  const std::string text = R"(
1184OpCapability Shader
1185OpCapability VariablePointersStorageBuffer
1186OpMemoryModel Logical GLSL450
1187OpEntryPoint Fragment %1 "func"
1188%2 = OpTypeVoid
1189%3 = OpTypeInt 32 0
1190%4 = OpTypePointer Workgroup %3
1191%5 = OpConstantNull %4
1192%6 = OpTypeFunction %2
1193%7 = OpTypeFunction %4
1194%1 = OpFunction %2 None %6
1195%8 = OpLabel
1196%9 = OpFunctionCall %4 %10
1197OpReturn
1198OpFunctionEnd
1199%10 = OpFunction %4 None %7
1200%11 = OpLabel
1201OpReturnValue %5
1202OpFunctionEnd
1203)";
1204
1205  std::unique_ptr<IRContext> context =
1206      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1207  EXPECT_NE(context, nullptr);
1208  Instruction* null_inst = context->get_def_use_mgr()->GetDef(9);
1209  EXPECT_NE(null_inst, nullptr);
1210  EXPECT_FALSE(null_inst->IsValidBasePointer());
1211}
1212
1213TEST_F(ValidBasePointerTest, OpFunctionCallGoodVariablePointersStorageBuffer) {
1214  const std::string text = R"(
1215OpCapability Shader
1216OpCapability VariablePointersStorageBuffer
1217OpMemoryModel Logical GLSL450
1218OpEntryPoint Fragment %1 "func"
1219%2 = OpTypeVoid
1220%3 = OpTypeInt 32 0
1221%4 = OpTypePointer StorageBuffer %3
1222%5 = OpConstantNull %4
1223%6 = OpTypeFunction %2
1224%7 = OpTypeFunction %4
1225%1 = OpFunction %2 None %6
1226%8 = OpLabel
1227%9 = OpFunctionCall %4 %10
1228OpReturn
1229OpFunctionEnd
1230%10 = OpFunction %4 None %7
1231%11 = OpLabel
1232OpReturnValue %5
1233OpFunctionEnd
1234)";
1235
1236  std::unique_ptr<IRContext> context =
1237      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1238  EXPECT_NE(context, nullptr);
1239  Instruction* null_inst = context->get_def_use_mgr()->GetDef(9);
1240  EXPECT_NE(null_inst, nullptr);
1241  EXPECT_TRUE(null_inst->IsValidBasePointer());
1242}
1243
1244TEST_F(ValidBasePointerTest, OpFunctionCallGoodVariablePointers) {
1245  const std::string text = R"(
1246OpCapability Shader
1247OpCapability VariablePointers
1248OpMemoryModel Logical GLSL450
1249OpEntryPoint Fragment %1 "func"
1250%2 = OpTypeVoid
1251%3 = OpTypeInt 32 0
1252%4 = OpTypePointer Workgroup %3
1253%5 = OpConstantNull %4
1254%6 = OpTypeFunction %2
1255%7 = OpTypeFunction %4
1256%1 = OpFunction %2 None %6
1257%8 = OpLabel
1258%9 = OpFunctionCall %4 %10
1259OpReturn
1260OpFunctionEnd
1261%10 = OpFunction %4 None %7
1262%11 = OpLabel
1263OpReturnValue %5
1264OpFunctionEnd
1265)";
1266
1267  std::unique_ptr<IRContext> context =
1268      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1269  EXPECT_NE(context, nullptr);
1270  Instruction* null_inst = context->get_def_use_mgr()->GetDef(9);
1271  EXPECT_NE(null_inst, nullptr);
1272  EXPECT_TRUE(null_inst->IsValidBasePointer());
1273}
1274
1275TEST_F(VulkanBufferTest, VulkanStorageBuffer) {
1276  const std::string text = R"(
1277OpCapability Shader
1278OpCapability RuntimeDescriptorArray
1279OpMemoryModel Logical GLSL450
1280OpEntryPoint GLCompute %1 "main"
1281OpExecutionMode %1 LocalSize 1 1 1
1282OpDecorate %2 Block
1283OpMemberDecorate %2 0 Offset 0
1284OpDecorate %3 BufferBlock
1285OpMemberDecorate %3 0 Offset 0
1286%4 = OpTypeVoid
1287%5 = OpTypeInt 32 0
1288%2 = OpTypeStruct %5
1289%3 = OpTypeStruct %5
1290
1291%6 = OpTypePointer StorageBuffer %2
1292%7 = OpTypePointer Uniform %2
1293%8 = OpTypePointer Uniform %3
1294
1295%9 = OpConstant %5 1
1296%10 = OpTypeArray %2 %9
1297%11 = OpTypeArray %3 %9
1298%12 = OpTypePointer StorageBuffer %10
1299%13 = OpTypePointer Uniform %10
1300%14 = OpTypePointer Uniform %11
1301
1302%15 = OpTypeRuntimeArray %2
1303%16 = OpTypeRuntimeArray %3
1304%17 = OpTypePointer StorageBuffer %15
1305%18 = OpTypePointer Uniform %15
1306%19 = OpTypePointer Uniform %16
1307
1308%50 = OpTypeFunction %4
1309%1 = OpFunction %4 None %50
1310%51 = OpLabel
1311OpReturn
1312OpFunctionEnd
1313)";
1314
1315  std::unique_ptr<IRContext> context =
1316      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1317  EXPECT_NE(context, nullptr);
1318
1319  // Standard SSBO and UBO
1320  Instruction* inst = context->get_def_use_mgr()->GetDef(6);
1321  EXPECT_EQ(true, inst->IsVulkanStorageBuffer());
1322  inst = context->get_def_use_mgr()->GetDef(7);
1323  EXPECT_EQ(false, inst->IsVulkanStorageBuffer());
1324  inst = context->get_def_use_mgr()->GetDef(8);
1325  EXPECT_EQ(true, inst->IsVulkanStorageBuffer());
1326
1327  // Arrayed SSBO and UBO
1328  inst = context->get_def_use_mgr()->GetDef(12);
1329  EXPECT_EQ(true, inst->IsVulkanStorageBuffer());
1330  inst = context->get_def_use_mgr()->GetDef(13);
1331  EXPECT_EQ(false, inst->IsVulkanStorageBuffer());
1332  inst = context->get_def_use_mgr()->GetDef(14);
1333  EXPECT_EQ(true, inst->IsVulkanStorageBuffer());
1334
1335  // Runtime arrayed SSBO and UBO
1336  inst = context->get_def_use_mgr()->GetDef(17);
1337  EXPECT_EQ(true, inst->IsVulkanStorageBuffer());
1338  inst = context->get_def_use_mgr()->GetDef(18);
1339  EXPECT_EQ(false, inst->IsVulkanStorageBuffer());
1340  inst = context->get_def_use_mgr()->GetDef(19);
1341  EXPECT_EQ(true, inst->IsVulkanStorageBuffer());
1342}
1343
1344TEST_F(VulkanBufferTest, VulkanUniformBuffer) {
1345  const std::string text = R"(
1346OpCapability Shader
1347OpCapability RuntimeDescriptorArray
1348OpMemoryModel Logical GLSL450
1349OpEntryPoint GLCompute %1 "main"
1350OpExecutionMode %1 LocalSize 1 1 1
1351OpDecorate %2 Block
1352OpMemberDecorate %2 0 Offset 0
1353OpDecorate %3 BufferBlock
1354OpMemberDecorate %3 0 Offset 0
1355%4 = OpTypeVoid
1356%5 = OpTypeInt 32 0
1357%2 = OpTypeStruct %5
1358%3 = OpTypeStruct %5
1359
1360%6 = OpTypePointer StorageBuffer %2
1361%7 = OpTypePointer Uniform %2
1362%8 = OpTypePointer Uniform %3
1363
1364%9 = OpConstant %5 1
1365%10 = OpTypeArray %2 %9
1366%11 = OpTypeArray %3 %9
1367%12 = OpTypePointer StorageBuffer %10
1368%13 = OpTypePointer Uniform %10
1369%14 = OpTypePointer Uniform %11
1370
1371%15 = OpTypeRuntimeArray %2
1372%16 = OpTypeRuntimeArray %3
1373%17 = OpTypePointer StorageBuffer %15
1374%18 = OpTypePointer Uniform %15
1375%19 = OpTypePointer Uniform %16
1376
1377%50 = OpTypeFunction %4
1378%1 = OpFunction %4 None %50
1379%51 = OpLabel
1380OpReturn
1381OpFunctionEnd
1382)";
1383
1384  std::unique_ptr<IRContext> context =
1385      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1386  EXPECT_NE(context, nullptr);
1387
1388  // Standard SSBO and UBO
1389  Instruction* inst = context->get_def_use_mgr()->GetDef(6);
1390  EXPECT_EQ(false, inst->IsVulkanUniformBuffer());
1391  inst = context->get_def_use_mgr()->GetDef(7);
1392  EXPECT_EQ(true, inst->IsVulkanUniformBuffer());
1393  inst = context->get_def_use_mgr()->GetDef(8);
1394  EXPECT_EQ(false, inst->IsVulkanUniformBuffer());
1395
1396  // Arrayed SSBO and UBO
1397  inst = context->get_def_use_mgr()->GetDef(12);
1398  EXPECT_EQ(false, inst->IsVulkanUniformBuffer());
1399  inst = context->get_def_use_mgr()->GetDef(13);
1400  EXPECT_EQ(true, inst->IsVulkanUniformBuffer());
1401  inst = context->get_def_use_mgr()->GetDef(14);
1402  EXPECT_EQ(false, inst->IsVulkanUniformBuffer());
1403
1404  // Runtime arrayed SSBO and UBO
1405  inst = context->get_def_use_mgr()->GetDef(17);
1406  EXPECT_EQ(false, inst->IsVulkanUniformBuffer());
1407  inst = context->get_def_use_mgr()->GetDef(18);
1408  EXPECT_EQ(true, inst->IsVulkanUniformBuffer());
1409  inst = context->get_def_use_mgr()->GetDef(19);
1410  EXPECT_EQ(false, inst->IsVulkanUniformBuffer());
1411}
1412
1413TEST_F(VulkanBufferTest, ImageQueries) {
1414  const std::string text = R"(
1415OpCapability Shader
1416OpCapability ImageBuffer
1417OpCapability RuntimeDescriptorArray
1418OpMemoryModel Logical GLSL450
1419OpEntryPoint GLCompute %1 "main"
1420OpExecutionMode %1 LocalSize 1 1 1
1421%2 = OpTypeVoid
1422%3 = OpTypeFloat 32
1423
1424%4 = OpTypeImage %3 Buffer 0 0 0 1 Rgba32f
1425%5 = OpTypeImage %3 Buffer 0 0 0 2 Rgba32f
1426%6 = OpTypeImage %3 2D 0 0 0 1 Rgba32f
1427%7 = OpTypeImage %3 2D 0 0 0 2 Rgba32f
1428
1429%8 = OpTypePointer UniformConstant %4
1430%9 = OpTypePointer UniformConstant %5
1431%10 = OpTypePointer UniformConstant %6
1432%11 = OpTypePointer UniformConstant %7
1433
1434%12 = OpTypeInt 32 0
1435%13 = OpConstant %12 1
1436%14 = OpTypeArray %4 %13
1437%15 = OpTypeArray %5 %13
1438%16 = OpTypeArray %6 %13
1439%17 = OpTypeArray %7 %13
1440%18 = OpTypePointer UniformConstant %14
1441%19 = OpTypePointer UniformConstant %15
1442%20 = OpTypePointer UniformConstant %16
1443%21 = OpTypePointer UniformConstant %17
1444
1445%22 = OpTypeRuntimeArray %4
1446%23 = OpTypeRuntimeArray %5
1447%24 = OpTypeRuntimeArray %6
1448%25 = OpTypeRuntimeArray %7
1449%26 = OpTypePointer UniformConstant %22
1450%27 = OpTypePointer UniformConstant %23
1451%28 = OpTypePointer UniformConstant %24
1452%29 = OpTypePointer UniformConstant %25
1453
1454%50 = OpTypeFunction %4
1455%1 = OpFunction %4 None %50
1456%51 = OpLabel
1457OpReturn
1458OpFunctionEnd
1459)";
1460
1461  std::unique_ptr<IRContext> context =
1462      BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, text);
1463  EXPECT_NE(context, nullptr);
1464
1465  // Bare pointers
1466  Instruction* inst = context->get_def_use_mgr()->GetDef(8);
1467  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1468  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1469  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1470
1471  inst = context->get_def_use_mgr()->GetDef(9);
1472  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1473  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1474  EXPECT_EQ(true, inst->IsVulkanStorageTexelBuffer());
1475
1476  inst = context->get_def_use_mgr()->GetDef(10);
1477  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1478  EXPECT_EQ(true, inst->IsVulkanSampledImage());
1479  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1480
1481  inst = context->get_def_use_mgr()->GetDef(11);
1482  EXPECT_EQ(true, inst->IsVulkanStorageImage());
1483  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1484  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1485
1486  // Array pointers
1487  inst = context->get_def_use_mgr()->GetDef(18);
1488  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1489  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1490  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1491
1492  inst = context->get_def_use_mgr()->GetDef(19);
1493  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1494  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1495  EXPECT_EQ(true, inst->IsVulkanStorageTexelBuffer());
1496
1497  inst = context->get_def_use_mgr()->GetDef(20);
1498  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1499  EXPECT_EQ(true, inst->IsVulkanSampledImage());
1500  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1501
1502  inst = context->get_def_use_mgr()->GetDef(21);
1503  EXPECT_EQ(true, inst->IsVulkanStorageImage());
1504  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1505  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1506
1507  // Runtime array pointers
1508  inst = context->get_def_use_mgr()->GetDef(26);
1509  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1510  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1511  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1512
1513  inst = context->get_def_use_mgr()->GetDef(27);
1514  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1515  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1516  EXPECT_EQ(true, inst->IsVulkanStorageTexelBuffer());
1517
1518  inst = context->get_def_use_mgr()->GetDef(28);
1519  EXPECT_EQ(false, inst->IsVulkanStorageImage());
1520  EXPECT_EQ(true, inst->IsVulkanSampledImage());
1521  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1522
1523  inst = context->get_def_use_mgr()->GetDef(29);
1524  EXPECT_EQ(true, inst->IsVulkanStorageImage());
1525  EXPECT_EQ(false, inst->IsVulkanSampledImage());
1526  EXPECT_EQ(false, inst->IsVulkanStorageTexelBuffer());
1527}
1528
1529TEST_F(DescriptorTypeTest, GetShader100DebugOpcode) {
1530  const std::string text = R"(
1531              OpCapability Shader
1532         %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
1533         %2 = OpString "ps.hlsl"
1534         %3 = OpString "#line 1 \"ps.hlsl\""
1535      %void = OpTypeVoid
1536         %5 = OpExtInst %void %1 DebugExpression
1537         %6 = OpExtInst %void %1 DebugSource %2 %3
1538)";
1539
1540  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1541  std::unique_ptr<IRContext> context =
1542      BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
1543  Instruction* debug_expression = context->get_def_use_mgr()->GetDef(5);
1544  EXPECT_EQ(debug_expression->GetShader100DebugOpcode(),
1545            NonSemanticShaderDebugInfo100DebugExpression);
1546  Instruction* debug_source = context->get_def_use_mgr()->GetDef(6);
1547  EXPECT_EQ(debug_source->GetShader100DebugOpcode(),
1548            NonSemanticShaderDebugInfo100DebugSource);
1549
1550  // Test that an opcode larger than the max will return Max.  This instruction
1551  // cannot be in the assembly above because the assembler expects the string
1552  // for the opcode, so we cannot use an arbitrary number.  However, a binary
1553  // file could have an arbitrary number.
1554  std::unique_ptr<Instruction> past_max(debug_expression->Clone(context.get()));
1555  const uint32_t kExtInstOpcodeInIndex = 1;
1556  uint32_t large_opcode = NonSemanticShaderDebugInfo100InstructionsMax + 2;
1557  past_max->SetInOperand(kExtInstOpcodeInIndex, {large_opcode});
1558  EXPECT_EQ(past_max->GetShader100DebugOpcode(),
1559            NonSemanticShaderDebugInfo100InstructionsMax);
1560
1561  // Test that an opcode without a value in the enum, but less than Max returns
1562  // the same value.
1563  uint32_t opcode = NonSemanticShaderDebugInfo100InstructionsMax - 2;
1564  past_max->SetInOperand(kExtInstOpcodeInIndex, {opcode});
1565  EXPECT_EQ(past_max->GetShader100DebugOpcode(), opcode);
1566}
1567
1568}  // namespace
1569}  // namespace opt
1570}  // namespace spvtools
1571