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