| // Copyright 2019 The Shaderc Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <algorithm> |
| #include <cstdarg> |
| #include <iostream> |
| #include <sstream> |
| #include <string> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include "gmock/gmock.h" |
| #include "spvcir_pass.h" |
| #include "test/opt/assembly_builder.h" |
| #include "test/opt/pass_fixture.h" |
| #include "test/opt/pass_utils.h" |
| |
| namespace spvtools { |
| namespace opt { |
| namespace { |
| |
| using ::testing::HasSubstr; |
| using ::testing::MatchesRegex; |
| |
| // For a given result Id returns the previously constructed instruction. |
| template <typename T> |
| T& get(uint32_t id, spirv_cross::ParsedIR* ir) { |
| return spirv_cross::variant_get<T>(ir->ids[id]); |
| } |
| |
| // For a given result Id returns the instruction if it was previously |
| // constructed and had the same result Type otherwise returns nullptr. |
| template <typename T> |
| T* maybe_get(uint32_t id, spirv_cross::ParsedIR* ir) { |
| if (id >= ir->ids.size()) |
| return nullptr; |
| else if (ir->ids[id].get_type() == static_cast<spirv_cross::Types>(T::type)) |
| return &get<T>(id, ir); |
| else |
| return nullptr; |
| } |
| |
| std::string SelectiveJoin(const std::vector<const char*>& strings, |
| const std::function<bool(const char*)>& skip_dictator, |
| char delimiter = '\n') { |
| std::ostringstream oss; |
| for (const auto* str : strings) { |
| if (!skip_dictator(str)) oss << str << delimiter; |
| } |
| return oss.str(); |
| } |
| |
| std::string JoinAllInsts(const std::vector<const char*>& insts) { |
| return SelectiveJoin(insts, [](const char*) { return false; }); |
| } |
| |
| bool createSpvcIr(spirv_cross::ParsedIR* ir, std::string text) { |
| std::vector<uint32_t> binary; |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| if (!context) return false; |
| context->module()->ToBinary(&binary, false); |
| ir->spirv = |
| std::vector<uint32_t>(binary.data(), binary.data() + binary.size()); |
| return true; |
| } |
| |
| class SpvcIrParsingTest : public PassTest<::testing::Test> { |
| protected: |
| void SetUp() override { |
| input_ = R"( |
| OpCapability Shader |
| %5 = OpExtInstImport "GLSL.std.450" |
| OpCapability VulkanMemoryModelKHR |
| OpExtension "SPV_KHR_vulkan_memory_model" |
| OpMemoryModel Logical VulkanKHR |
| OpEntryPoint Vertex %1 "shader" |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %1 = OpFunction %2 None %3 |
| %4 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| before_ = { |
| // clang-format off |
| "OpCapability Shader", |
| "OpCapability VulkanMemoryModelKHR", |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", |
| "OpMemoryModel Logical VulkanKHR", |
| "OpEntryPoint Vertex %1 \"shader\"", |
| // clang-format on |
| }; |
| |
| after_ = { |
| // clang-format off |
| "%2 = OpTypeVoid", |
| "%3 = OpTypeFunction %2", |
| "%1 = OpFunction %2 None %3", |
| "%4 = OpLabel", |
| "OpReturn", |
| "OpFunctionEnd" |
| // clang-format on |
| }; |
| |
| SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| std::vector<uint32_t> binary; |
| std::unique_ptr<IRContext> context = |
| BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, input_, |
| SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); |
| assert(context && "context"); |
| context->module()->ToBinary(&binary, false); |
| ir_.spirv = |
| std::vector<uint32_t>(binary.data(), binary.data() + binary.size()); |
| } |
| std::string input_; |
| spirv_cross::ParsedIR ir_; |
| std::vector<const char*> before_; |
| std::vector<const char*> after_; |
| }; |
| |
| TEST_F(SpvcIrParsingTest, OpExtInstImportInsruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_ext = maybe_get<spirv_cross::SPIRExtension>(5, &ir_); |
| ASSERT_NE(spir_ext, nullptr); |
| EXPECT_EQ(spir_ext->ext, spirv_cross::SPIRExtension::GLSL); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpCapabilityInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| ASSERT_EQ(ir_.declared_capabilities.size(), 2); |
| EXPECT_EQ(ir_.declared_capabilities[0], spv::Capability::CapabilityShader); |
| EXPECT_EQ(ir_.declared_capabilities[1], |
| spv::Capability::CapabilityVulkanMemoryModelKHR); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpExtensionInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| ASSERT_EQ(ir_.declared_extensions.size(), 1); |
| EXPECT_EQ(ir_.declared_extensions[0], "SPV_KHR_vulkan_memory_model"); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpMemoryModelInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| EXPECT_EQ(ir_.addressing_model, spv::AddressingModel::AddressingModelLogical); |
| EXPECT_EQ(ir_.memory_model, spv::MemoryModel::MemoryModelVulkanKHR); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpEntryPointInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| ASSERT_EQ(ir_.entry_points.size(), 1); |
| const auto functionId = 1; |
| const auto entry = *ir_.entry_points.begin(); |
| EXPECT_EQ(entry.first, static_cast<spirv_cross::FunctionID>(functionId)); |
| EXPECT_EQ(entry.second.orig_name, "shader"); |
| EXPECT_EQ(entry.second.model, spv::ExecutionModelVertex); |
| EXPECT_EQ(entry.second.self, |
| static_cast<spirv_cross::FunctionID>(functionId)); |
| EXPECT_EQ(ir_.meta[functionId].decoration.alias, "shader"); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpUndefInstruction) { |
| const std::vector<const char*> middle = {"%10 = OpTypeFloat 32", |
| "%11 = OpUndef %10"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_undef = maybe_get<spirv_cross::SPIRUndef>(11, &ir); |
| ASSERT_NE(spir_undef, nullptr); |
| EXPECT_EQ(spir_undef->basetype, static_cast<spirv_cross::TypeID>(10)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpMemberDecorateInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpMemberDecorate %15 0 Offset 8", |
| "OpMemberDecorate %15 0 NonWritable", |
| "%float = OpTypeFloat 32", |
| "%v4float = OpTypeVector %float 4", |
| "%_runtimearr_v4float = OpTypeRuntimeArray %v4float", |
| "%15 = OpTypeStruct %_runtimearr_v4float", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto offset = |
| ir.get_member_decoration(15, 0, spv::Decoration::DecorationOffset); |
| auto writable = |
| ir.get_member_decoration(15, 0, spv::Decoration::DecorationNonWritable); |
| EXPECT_EQ(offset, 8); |
| EXPECT_EQ(writable, 1); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpMemberNameInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpMemberName %16 0 \"u\"", |
| "OpMemberName %16 1 \"i\"", |
| "%int = OpTypeInt 32 1", |
| "%ivec4 = OpTypeVector %int 4", |
| "%uint = OpTypeInt 32 0", |
| "%uvec4 = OpTypeVector %uint 4", |
| "%16 = OpTypeStruct %uvec4 %ivec4", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto i = ir.get_member_name(16, 0); |
| auto u = ir.get_member_name(16, 1); |
| EXPECT_EQ(i, "u"); |
| EXPECT_EQ(u, "i"); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpExecutionModeInstruction) { |
| const std::vector<const char*> middle = { |
| "OpExecutionMode %1 LocalSize 4 3 5", |
| "OpExecutionMode %1 OutputVertices 1", |
| "OpExecutionMode %1 Invocations 1"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| ASSERT_EQ(ir.entry_points.size(), 1); |
| const auto& execution = ir.entry_points[1]; |
| EXPECT_EQ(execution.workgroup_size.x, 4); |
| EXPECT_EQ(execution.workgroup_size.y, 3); |
| EXPECT_EQ(execution.workgroup_size.z, 5); |
| EXPECT_EQ(execution.output_vertices, 1); |
| EXPECT_EQ(execution.invocations, 1); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeVoidInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto func_type = maybe_get<spirv_cross::SPIRType>(2, &ir_); |
| ASSERT_NE(func_type, nullptr); |
| EXPECT_EQ(func_type->basetype, spirv_cross::SPIRType::Void); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpStringInstruction) { |
| const std::vector<const char*> middle = {"%10 = OpString \"main\""}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_str = maybe_get<spirv_cross::SPIRString>(10, &ir); |
| ASSERT_NE(spir_str, nullptr); |
| EXPECT_EQ(spir_str->str, "main"); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeBoolInstruction) { |
| const std::vector<const char*> middle = {"%25 = OpTypeBool", |
| "%27 = OpTypeFunction %25"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto bool_type = maybe_get<spirv_cross::SPIRType>(25, &ir); |
| ASSERT_NE(bool_type, nullptr); |
| EXPECT_EQ(bool_type->basetype, spirv_cross::SPIRType::Boolean); |
| EXPECT_EQ(bool_type->width, 1); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeFloatInstruction16) { |
| const std::vector<const char*> middle = {"%25 = OpTypeFloat 16", |
| "%27 = OpTypeFunction %25"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto bool_type = maybe_get<spirv_cross::SPIRType>(25, &ir); |
| ASSERT_NE(bool_type, nullptr); |
| EXPECT_EQ(bool_type->basetype, spirv_cross::SPIRType::Half); |
| EXPECT_EQ(bool_type->width, 16); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeFloatInstruction32) { |
| const std::vector<const char*> middle = {"%25 = OpTypeFloat 32", |
| "%27 = OpTypeFunction %25"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto bool_type = maybe_get<spirv_cross::SPIRType>(25, &ir); |
| ASSERT_NE(bool_type, nullptr); |
| EXPECT_EQ(bool_type->basetype, spirv_cross::SPIRType::Float); |
| EXPECT_EQ(bool_type->width, 32); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeFloatInstruction64) { |
| const std::vector<const char*> middle = {"%25 = OpTypeFloat 64", |
| "%27 = OpTypeFunction %25"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto bool_type = maybe_get<spirv_cross::SPIRType>(25, &ir); |
| ASSERT_NE(bool_type, nullptr); |
| EXPECT_EQ(bool_type->basetype, spirv_cross::SPIRType::Double); |
| EXPECT_EQ(bool_type->width, 64); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeVectorInstruction) { |
| const std::vector<const char*> middle = {"%6 = OpTypeFloat 32", |
| "%7 = OpTypeVector %6 4"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto vector_type = maybe_get<spirv_cross::SPIRType>(7, &ir); |
| ASSERT_NE(vector_type, nullptr); |
| EXPECT_EQ(vector_type->basetype, spirv_cross::SPIRType::Float); |
| EXPECT_EQ(vector_type->vecsize, 4); |
| EXPECT_EQ(vector_type->self, static_cast<spirv_cross::TypeID>(7)); |
| EXPECT_EQ(vector_type->parent_type, static_cast<spirv_cross::TypeID>(6)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeMatrixInstruction) { |
| const std::vector<const char*> middle = {"%6 = OpTypeFloat 32", |
| "%8 = OpTypeVector %6 4", |
| "%7 = OpTypeMatrix %8 4"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto matrix_type = maybe_get<spirv_cross::SPIRType>(7, &ir); |
| ASSERT_NE(matrix_type, nullptr); |
| EXPECT_EQ(matrix_type->columns, 4); |
| EXPECT_EQ(matrix_type->self, static_cast<spirv_cross::TypeID>(7)); |
| EXPECT_EQ(matrix_type->parent_type, static_cast<spirv_cross::TypeID>(8)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeImageInstruction) { |
| const std::vector<const char*> cap = {"OpCapability SampledBuffer"}; |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%5 = OpTypeInt 32 0", |
| "%6 = OpTypeImage %5 Buffer 0 0 0 2 R32ui" |
| // clang format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(cap,(Concat(Concat(before_, middle), after_)))); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto image_type = maybe_get<spirv_cross::SPIRType>(6, &ir); |
| ASSERT_NE(image_type, nullptr); |
| EXPECT_EQ(image_type->image.type, static_cast<spirv_cross::TypeID>(5)); |
| EXPECT_EQ(image_type->image.dim, spv::Dim::DimBuffer); |
| EXPECT_EQ(image_type->image.depth, 0); |
| EXPECT_EQ(image_type->image.arrayed, 0); |
| EXPECT_EQ(image_type->image.ms, 0); |
| EXPECT_EQ(image_type->image.sampled, 2); |
| EXPECT_EQ(image_type->image.format, spv::ImageFormat::ImageFormatR32ui); |
| |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeSampledImageInstruction) { |
| const std::vector<const char*> cap = {"OpCapability SampledBuffer"}; |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%5 = OpTypeInt 32 0", |
| "%6 = OpTypeImage %5 Buffer 0 0 0 2 R32ui", |
| "%18 = OpTypeSampledImage %6", |
| // clang-format on |
| }; |
| std::string spirv = |
| JoinAllInsts(Concat(cap, (Concat(Concat(before_, middle), after_)))); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto sampledImage_type = maybe_get<spirv_cross::SPIRType>(18, &ir); |
| ASSERT_NE(sampledImage_type, nullptr); |
| EXPECT_EQ(sampledImage_type->basetype, spirv_cross::SPIRType::SampledImage); |
| EXPECT_EQ(sampledImage_type->self, static_cast<spirv_cross::TypeID>(18)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeSamplerInstruction) { |
| const std::vector<const char*> cap = {"OpCapability SampledBuffer"}; |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%12 = OpTypeSampler", |
| // clang-format on |
| }; |
| std::string spirv = |
| JoinAllInsts(Concat(cap, (Concat(Concat(before_, middle), after_)))); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto sampledImage_type = maybe_get<spirv_cross::SPIRType>(12, &ir); |
| ASSERT_NE(sampledImage_type, nullptr); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeArrayInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%13 = OpTypeInt 32 0", |
| "%14 = OpConstant %13 70", |
| " %7 = OpTypeVector %13 4", |
| "%15 = OpTypeArray %7 %14" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto array_type = maybe_get<spirv_cross::SPIRType>(15, &ir); |
| ASSERT_NE(array_type, nullptr); |
| EXPECT_EQ(array_type->parent_type, static_cast<spirv_cross::TypeID>(7)); |
| ASSERT_EQ(array_type->array_size_literal.size(), 1); |
| EXPECT_TRUE(array_type->array_size_literal[0]); |
| EXPECT_EQ(array_type->array[0], 70); |
| |
| auto constant_type = maybe_get<spirv_cross::SPIRConstant>(14, &ir); |
| EXPECT_TRUE(constant_type->is_used_as_array_length); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeArrayInstructionSpec) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%12 = OpTypeInt 32 0", |
| "%13 = OpTypeFloat 32", |
| "%14 = OpSpecConstant %12 3", |
| " %7 = OpTypeVector %13 4", |
| "%15 = OpTypeArray %7 %14" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto array_type = maybe_get<spirv_cross::SPIRType>(15, &ir); |
| ASSERT_NE(array_type, nullptr); |
| EXPECT_EQ(array_type->parent_type, static_cast<spirv_cross::TypeID>(7)); |
| ASSERT_EQ(array_type->array_size_literal.size(), 1); |
| EXPECT_FALSE(array_type->array_size_literal[0]); |
| EXPECT_EQ(array_type->array[0], 14); |
| |
| auto constant_type = maybe_get<spirv_cross::SPIRConstant>(14, &ir); |
| EXPECT_TRUE(constant_type->is_used_as_array_length); |
| } |
| TEST_F(SpvcIrParsingTest, OpTypeRuntimeArrayInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%15 = OpTypeFloat 32", |
| "%17 = OpTypeRuntimeArray %15", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto run_type = maybe_get<spirv_cross::SPIRType>(17, &ir); |
| ASSERT_NE(run_type, nullptr); |
| ASSERT_EQ(run_type->array.size(), 1); |
| EXPECT_EQ(run_type->array[0], 0); |
| ASSERT_EQ(run_type->array_size_literal.size(), 1); |
| EXPECT_TRUE(run_type->array_size_literal[0]); |
| EXPECT_EQ(run_type->parent_type, static_cast<spirv_cross::TypeID>(15)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeFunctionInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto func = maybe_get<spirv_cross::SPIRFunctionPrototype>(3, &ir_); |
| ASSERT_NE(func, nullptr); |
| EXPECT_EQ(func->return_type, static_cast<spirv_cross::TypeID>(2)); |
| EXPECT_TRUE(func->parameter_types.empty()); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeAccelerationStructureNVInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%10 = OpTypeAccelerationStructureNV" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_var = maybe_get<spirv_cross::SPIRType>(10, &ir); |
| ASSERT_NE(spir_var, nullptr); |
| EXPECT_EQ(spir_var->basetype, spirv_cross::SPIRType::AccelerationStructureNV); |
| } |
| |
| |
| TEST_F(SpvcIrParsingTest, SpvOpSFunctionParameterInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%8 = OpTypeFunction %9 %9 %9", |
| "%9 = OpTypeFloat 32", |
| "%add_v = OpFunction %9 None %8", |
| "%10 = OpFunctionParameter %9", |
| "%11 = OpFunctionParameter %9", |
| "%12 = OpLabel", |
| "%15 = OpFAdd %float %v %w", |
| "OpReturn", |
| "OpFunctionEnd" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_var = maybe_get<spirv_cross::SPIRVariable>(10, &ir); |
| ASSERT_NE(spir_var, nullptr); |
| EXPECT_EQ(spir_var->basetype, static_cast<spirv_cross::TypeID>(9)); |
| EXPECT_EQ(spir_var->storage, spv::StorageClass::StorageClassFunction); |
| EXPECT_EQ(spir_var->initializer, static_cast<spirv_cross::TypeID>(0)); |
| EXPECT_EQ(spir_var->basevariable, static_cast<spirv_cross::TypeID>(0)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpFunctionInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto func = maybe_get<spirv_cross::SPIRFunction>(1, &ir_); |
| ASSERT_NE(func, nullptr); |
| EXPECT_EQ(func->type, spirv_cross::TypeFunction); |
| EXPECT_EQ(func->return_type, static_cast<spirv_cross::TypeID>(2)); |
| EXPECT_EQ(func->function_type, static_cast<spirv_cross::TypeID>(3)); |
| EXPECT_TRUE(func->arguments.empty()); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpLabelInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto func = maybe_get<spirv_cross::SPIRFunction>(1, &ir_); |
| ASSERT_NE(func, nullptr); |
| auto block = maybe_get<spirv_cross::SPIRBlock>(4, &ir_); |
| ASSERT_NE(block, nullptr); |
| EXPECT_EQ(func->blocks.size(), static_cast<size_t>(1)); |
| EXPECT_EQ(func->blocks.data()[0], static_cast<spirv_cross::TypeID>(4)); |
| EXPECT_EQ(func->entry_block, static_cast<spirv_cross::TypeID>(4)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpSourceInstruction) { |
| const std::vector<const char*> middle = {"OpSource HLSL 500"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| EXPECT_FALSE(ir.source.es); |
| EXPECT_EQ(ir.source.version, 450); |
| EXPECT_TRUE(ir.source.known); |
| EXPECT_TRUE(ir.source.hlsl); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpTypeIntInstruction) { |
| const std::vector<const char*> middle = {"%16 = OpTypeInt 32 1"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto int_type = maybe_get<spirv_cross::SPIRType>(16, &ir); |
| ASSERT_NE(int_type, nullptr); |
| EXPECT_EQ(int_type->width, 32); |
| EXPECT_EQ(int_type->basetype, spirv_cross::SPIRType::Int); |
| EXPECT_EQ(int_type->vecsize, 1); |
| EXPECT_EQ(int_type->columns, 1); |
| EXPECT_EQ(int_type->array.size(), 0); |
| EXPECT_EQ(int_type->type_alias, static_cast<spirv_cross::TypeID>(0)); |
| EXPECT_EQ(int_type->parent_type, static_cast<spirv_cross::TypeID>(0)); |
| EXPECT_TRUE(int_type->member_name_cache.empty()); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpTypeIntInstructionUnsigned) { |
| const std::vector<const char*> middle = {"%16 = OpTypeInt 32 0"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto int_type = maybe_get<spirv_cross::SPIRType>(16, &ir); |
| ASSERT_NE(int_type, nullptr); |
| EXPECT_EQ(int_type->width, 32); |
| EXPECT_EQ(int_type->basetype, spirv_cross::SPIRType::UInt); |
| EXPECT_EQ(int_type->vecsize, 1); |
| EXPECT_EQ(int_type->columns, 1); |
| EXPECT_EQ(int_type->array.size(), 0); |
| EXPECT_EQ(int_type->type_alias, static_cast<spirv_cross::TypeID>(0)); |
| EXPECT_EQ(int_type->parent_type, static_cast<spirv_cross::TypeID>(0)); |
| EXPECT_TRUE(int_type->member_name_cache.empty()); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantInstruction) { |
| const std::vector<const char*> middle = {" %8 = OpTypeInt 32 1", |
| "%13 = OpConstant %8 100"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(8)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_EQ(spir_constant->scalar(0, 0), 100); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantInstruction64) { |
| const std::vector<const char*> middle = {" %8 = OpTypeInt 64 1", |
| "%13 = OpConstant %8 0xF1F2F3F4"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(8)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_EQ(spir_constant->scalar_u64(0, 0), 0xF1F2F3F4); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpSpecConstantInstruction) { |
| const std::vector<const char*> middle = {"%13 = OpTypeFloat 32", |
| "%14 = OpSpecConstant %13 3.14159"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(14, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(13)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(0, 0), 3.14159); |
| EXPECT_TRUE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantFalseInstruction) { |
| const std::vector<const char*> middle = {" %8 = OpTypeBool", |
| "%13 = OpConstantFalse %8"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(8)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_EQ(spir_constant->scalar(0, 0), 0); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpSpecConstantFalseInstruction) { |
| const std::vector<const char*> middle = {" %8 = OpTypeBool", |
| "%13 = OpSpecConstantFalse %8"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(8)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_EQ(spir_constant->scalar(0, 0), 0); |
| EXPECT_TRUE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantTrueInstruction) { |
| const std::vector<const char*> middle = {" %8 = OpTypeBool", |
| "%13 = OpConstantTrue %8"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(8)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_EQ(spir_constant->scalar(0, 0), 1); |
| EXPECT_FALSE(spir_constant->constant_is_null()); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpSpecConstantTrueInstruction) { |
| const std::vector<const char*> middle = {" %8 = OpTypeBool", |
| "%13 = OpSpecConstantTrue %8"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(8)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_EQ(spir_constant->scalar(0, 0), 1); |
| EXPECT_FALSE(spir_constant->constant_is_null()); |
| EXPECT_TRUE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantNullInstruction) { |
| const std::vector<const char*> middle = {" %8 = OpTypeFloat 32", |
| "%13 = OpConstantNull %8"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(8)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 1); |
| EXPECT_TRUE(spir_constant->constant_is_null()); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantNullInstructionMatrix) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%float = OpTypeFloat 32", |
| "%v4float = OpTypeVector %float 4", |
| "%7 = OpTypeMatrix %v4float 4", |
| "%13 = OpConstantNull %7" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(13, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(7)); |
| ASSERT_EQ(spir_constant->m.columns, 4); |
| ASSERT_EQ(spir_constant->vector_size(), 4); |
| EXPECT_TRUE(spir_constant->constant_is_null()); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantCompositeInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%6 = OpTypeInt 32 0", |
| "%7 = OpTypeVector %6 4", |
| "%10 = OpConstant %6 11", |
| "%11 = OpConstant %6 22", |
| "%12 = OpConstantComposite %7 %10 %10 %11 %10", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(12, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(7)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 4); |
| EXPECT_EQ(spir_constant->scalar(0, 0), 11); |
| EXPECT_EQ(spir_constant->scalar(0, 1), 11); |
| EXPECT_EQ(spir_constant->scalar(0, 2), 22); |
| EXPECT_EQ(spir_constant->scalar(0, 3), 11); |
| EXPECT_FALSE(spir_constant->constant_is_null()); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpConstantCompositeInstructionMatrix) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%float = OpTypeFloat 32", |
| "%float_1 = OpConstant %float 1", |
| "%float_0 = OpConstant %float 0", |
| "%float_0_5 = OpConstant %float 0.5", |
| "%v4float = OpTypeVector %float 4", |
| "%7 = OpTypeMatrix %v4float 4", |
| "%39 = OpConstantComposite %v4float %float_0_5 %float_0 %float_0 %float_0", |
| "%40 = OpConstantComposite %v4float %float_0 %float_0_5 %float_0 %float_0", |
| "%41 = OpConstantComposite %v4float %float_0 %float_0 %float_0_5 %float_0", |
| "%43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1", |
| "%44 = OpConstantComposite %7 %39 %40 %41 %43" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(44, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(7)); |
| ASSERT_EQ(spir_constant->m.columns, 4); |
| EXPECT_FLOAT_EQ(spir_constant->vector_size(), 4); |
| |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(0, 0), 0.5); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(0, 1), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(0, 2), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(0, 3), 0); |
| |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(1, 0), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(1, 1), 0.5); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(1, 2), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(1, 3), 0); |
| |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(2, 0), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(2, 1), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(2, 2), 0.5); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(2, 3), 0); |
| |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(3, 0), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(3, 1), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(3, 2), 0); |
| EXPECT_FLOAT_EQ(spir_constant->scalar_f32(3, 3), 1.0); |
| |
| EXPECT_FALSE(spir_constant->constant_is_null()); |
| EXPECT_FALSE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpSpecConstantCompositeInstructionSpec) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%6 = OpTypeInt 32 0", |
| "%7 = OpTypeVector %6 4", |
| "%10 = OpConstant %6 15", |
| "%11 = OpConstant %6 22", |
| "%12 = OpSpecConstantComposite %7 %10 %10 %11 %10", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstant>(12, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->constant_type, static_cast<spirv_cross::TypeID>(7)); |
| ASSERT_EQ(spir_constant->m.columns, 1); |
| ASSERT_EQ(spir_constant->vector_size(), 4); |
| EXPECT_EQ(spir_constant->scalar(0, 0), 15); |
| EXPECT_EQ(spir_constant->scalar(0, 1), 15); |
| EXPECT_EQ(spir_constant->scalar(0, 2), 22); |
| EXPECT_EQ(spir_constant->scalar(0, 3), 15); |
| EXPECT_FALSE(spir_constant->constant_is_null()); |
| EXPECT_TRUE(spir_constant->specialization); |
| EXPECT_FALSE(spir_constant->is_used_as_array_length); |
| EXPECT_FALSE(spir_constant->is_used_as_lut); |
| EXPECT_EQ(spir_constant->subconstants.size(), 0); |
| EXPECT_EQ(spir_constant->specialization_constant_macro_name, ""); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpSpecConstantOpInstructionSpec) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%12 = OpTypeInt 32 1", |
| "%13 = OpSpecConstant %12 -10", |
| "%14 = OpConstant %12 2", |
| "%15 = OpSpecConstantOp %12 IAdd %13 %14", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_constant = maybe_get<spirv_cross::SPIRConstantOp>(15, &ir); |
| ASSERT_NE(spir_constant, nullptr); |
| EXPECT_EQ(spir_constant->basetype, static_cast<spirv_cross::TypeID>(12)); |
| ASSERT_EQ(spir_constant->arguments.size(), 2); |
| EXPECT_EQ(spir_constant->arguments.data()[0], 13); |
| EXPECT_EQ(spir_constant->arguments.data()[1], 14); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpTypePointer) { |
| const std::vector<const char*> middle = {" %8 = OpTypeInt 32 1", |
| "%16 = OpTypePointer Output %8"}; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_pointer = maybe_get<spirv_cross::SPIRType>(16, &ir); |
| ASSERT_NE(spir_pointer, nullptr); |
| EXPECT_TRUE(spir_pointer); |
| EXPECT_EQ(spir_pointer->pointer_depth, 1); |
| EXPECT_EQ(spir_pointer->storage, spv::StorageClass::StorageClassOutput); |
| EXPECT_EQ(spir_pointer->parent_type, static_cast<spirv_cross::TypeID>(8)); |
| EXPECT_EQ(spir_pointer->width, 32); |
| EXPECT_EQ(spir_pointer->basetype, spirv_cross::SPIRType::Int); |
| EXPECT_EQ(spir_pointer->vecsize, 1); |
| EXPECT_EQ(spir_pointer->columns, 1); |
| EXPECT_EQ(spir_pointer->array.size(), 0); |
| EXPECT_EQ(spir_pointer->type_alias, static_cast<spirv_cross::TypeID>(0)); |
| EXPECT_TRUE(spir_pointer->member_name_cache.empty()); |
| } |
| |
| TEST_F(SpvcIrParsingTest, SpvOpVariableInstruction) { |
| const std::vector<const char*> middle = { |
| " %8 = OpTypeInt 32 1", |
| "%16 = OpTypePointer Output %8", |
| "%17 = OpVariable %16 Output", |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, false, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_variable = maybe_get<spirv_cross::SPIRVariable>(17, &ir); |
| ASSERT_NE(spir_variable, nullptr); |
| EXPECT_EQ(spir_variable->basetype, static_cast<spirv_cross::TypeID>(16)); |
| EXPECT_EQ(spir_variable->storage, spv::StorageClass::StorageClassOutput); |
| EXPECT_EQ(spir_variable->initializer, static_cast<spirv_cross::TypeID>(0)); |
| EXPECT_EQ(spir_variable->basevariable, static_cast<spirv_cross::TypeID>(0)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpDecorateInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpDecorate %17 Location 0", |
| " %8 = OpTypeInt 32 1", |
| "%16 = OpTypePointer Output %8", |
| "%17 = OpVariable %16 Output", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_decoration = ir.find_meta(17); |
| ASSERT_NE(spir_decoration, nullptr); |
| auto& work_offsets = spir_decoration->decoration_word_offset; |
| auto itr = work_offsets.find(spv::DecorationLocation); |
| EXPECT_NE(itr, end(work_offsets)); |
| auto& work_offset = itr->second; |
| EXPECT_EQ(work_offset, 28); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpDecorateInstruction2) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpDecorate %17 Location 0", |
| "OpDecorate %18 Location 1", |
| "OpDecorate %19 Location 2", |
| "OpDecorate %20 Location 3", |
| " %8 = OpTypeInt 32 1", |
| "%16 = OpTypePointer Output %8", |
| "%17 = OpVariable %16 Output", |
| "%18 = OpVariable %16 Output", |
| "%19 = OpVariable %16 Output", |
| "%20 = OpVariable %16 Output" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_decoration = ir.find_meta(20); |
| ASSERT_NE(spir_decoration, nullptr); |
| auto& work_offsets = spir_decoration->decoration_word_offset; |
| auto itr = work_offsets.find(spv::DecorationLocation); |
| EXPECT_NE(itr, end(work_offsets)); |
| auto& work_offset = itr->second; |
| EXPECT_EQ(work_offset, 40); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpGroupDecorateInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpDecorate %11 Offset 3", |
| "OpDecorate %11 Restrict", |
| "%11 = OpDecorationGroup", |
| "OpGroupDecorate %11 %_struct_1 %_struct_2 %30", |
| "%float = OpTypeFloat 32", |
| "%_runtimearr = OpTypeRuntimeArray %float", |
| "%_struct_1 = OpTypeStruct %float %float %float %_runtimearr", |
| "%_struct_2 = OpTypeStruct %float %float %float %_runtimearr", |
| "%30 = OpTypeStruct %float %float %float %_runtimearr" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| EXPECT_EQ(ir.get_decoration(30, spv::DecorationRestrict), 1); |
| EXPECT_EQ(ir.get_decoration(30, spv::DecorationOffset), 3); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpGroupMemberDecorateInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpDecorate %11 Offset 3", |
| "OpDecorate %11 Restrict", |
| "%11 = OpDecorationGroup", |
| "OpGroupMemberDecorate %11 %_struct_1 3 %_struct_2 3 %30 3", |
| "%float = OpTypeFloat 32", |
| "%_runtimearr = OpTypeRuntimeArray %float", |
| "%_struct_1 = OpTypeStruct %float %float %float %_runtimearr", |
| "%_struct_2 = OpTypeStruct %float %float %float %_runtimearr", |
| "%30 = OpTypeStruct %float %float %float %_runtimearr" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| EXPECT_EQ(ir.get_member_decoration(30, 3, spv::DecorationRestrict), 1); |
| EXPECT_EQ(ir.get_member_decoration(30, 3, spv::DecorationOffset), 3); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpMemberDecorateStringInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpCapability Shader", |
| "OpCapability VulkanMemoryModelKHR", |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", |
| "OpExtension \"SPV_GOOGLE_hlsl_functionality1\"", |
| "OpMemoryModel Logical VulkanKHR", |
| "OpEntryPoint Vertex %1 \"shader\"", |
| "OpMemberDecorateStringGOOGLE %30 3 HlslSemanticGOOGLE \"blah\"", |
| "%float = OpTypeFloat 32", |
| "%_runtimearr = OpTypeRuntimeArray %float", |
| "%30 = OpTypeStruct %float %float %float %_runtimearr", |
| "%2 = OpTypeVoid", |
| "%3 = OpTypeFunction %2", |
| "%1 = OpFunction %2 None %3", |
| "%4 = OpLabel", |
| "OpReturn", |
| "OpFunctionEnd", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(middle); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| EXPECT_EQ( |
| ir.get_member_decoration_string(30, 3, spv::DecorationHlslSemanticGOOGLE), |
| "blah"); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpDecorateStringInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpCapability Shader", |
| "OpCapability VulkanMemoryModelKHR", |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", |
| "OpExtension \"SPV_GOOGLE_hlsl_functionality1\"", |
| "OpMemoryModel Logical VulkanKHR", |
| "OpEntryPoint Vertex %1 \"shader\"", |
| "OpDecorateStringGOOGLE %10 HlslSemanticGOOGLE \"blah\"", |
| "%10 = OpTypeFloat 32", |
| "%2 = OpTypeVoid", |
| "%3 = OpTypeFunction %2", |
| "%1 = OpFunction %2 None %3", |
| "%4 = OpLabel", |
| "OpReturn", |
| "OpFunctionEnd", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(middle); |
| spirv_cross::ParsedIR ir; |
| createSpvcIr(&ir, spirv); |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| EXPECT_EQ(ir.get_decoration_string(10, spv::DecorationHlslSemanticGOOGLE), |
| "blah"); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeForwardPointerInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpCapability Shader", |
| "OpCapability VulkanMemoryModelKHR", |
| "OpCapability PhysicalStorageBufferAddressesEXT", |
| "OpExtension \"SPV_EXT_physical_storage_buffer\"", |
| "OpExtension \"SPV_KHR_vulkan_memory_model\"", |
| "OpMemoryModel Logical VulkanKHR", |
| "OpEntryPoint Vertex %1 \"shader\"", |
| "OpTypeForwardPointer %10 PhysicalStorageBuffer", |
| "%int = OpTypeInt 32 1", |
| "%bufStruct = OpTypeStruct %int %int", |
| "%10 = OpTypePointer PhysicalStorageBuffer %bufStruct", |
| "%2 = OpTypeVoid", |
| "%3 = OpTypeFunction %2", |
| "%1 = OpFunction %2 None %3", |
| "%4 = OpLabel", |
| "OpReturn", |
| "OpFunctionEnd", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(middle); |
| spirv_cross::ParsedIR ir; |
| ASSERT_EQ(createSpvcIr(&ir, spirv), true) |
| << "Could not create IRContext for input:\n" + spirv + "\n"; |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| const auto ptrbase = maybe_get<spirv_cross::SPIRType>(10, &ir); |
| ASSERT_NE(ptrbase, nullptr); |
| EXPECT_TRUE(ptrbase->pointer); |
| EXPECT_EQ(ptrbase->pointer_depth, 1); |
| EXPECT_EQ(ptrbase->storage, |
| spv::StorageClass::StorageClassPhysicalStorageBuffer); |
| } |
| |
| |
| TEST_F(SpvcIrParsingTest, OpNameInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "OpDecorate %17 Location 0", |
| "OpName %17 \"var\"" |
| " %8 = OpTypeInt 32 1", |
| "%16 = OpTypePointer Output %8", |
| "%17 = OpVariable %16 Output", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| ASSERT_EQ(createSpvcIr(&ir, spirv), true) |
| << "Could not create IRContext for input:\n" + spirv + "\n"; |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| const auto var_name = ir.get_name(17); |
| EXPECT_EQ(var_name, "var"); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpTypeStructInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| " %8 = OpTypeInt 32 1", |
| "%16 = OpTypePointer Output %8", |
| "%22 = OpTypeStruct %8 %8 %8 %8", |
| "%20 = OpTypeStruct %8 %8 %16", |
| "%21 = OpTypeStruct %8 %8 %16" |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(Concat(before_, middle), after_)); |
| spirv_cross::ParsedIR ir; |
| ASSERT_EQ(createSpvcIr(&ir, spirv), true) |
| << "Could not create IRContext for input:\n" + spirv + "\n"; |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_struct = maybe_get<spirv_cross::SPIRType>(20, &ir); |
| ASSERT_NE(spir_struct, nullptr); |
| EXPECT_EQ(spir_struct->basetype, spirv_cross::SPIRType::Struct); |
| ASSERT_EQ(spir_struct->member_types.size(), 3); |
| EXPECT_EQ(spir_struct->member_types.data()[0], |
| static_cast<spirv_cross::TypeID>(8)); |
| EXPECT_EQ(spir_struct->member_types.data()[1], |
| static_cast<spirv_cross::TypeID>(8)); |
| EXPECT_EQ(spir_struct->member_types.data()[2], |
| static_cast<spirv_cross::TypeID>(16)); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpPhiInstruction) { |
| const std::vector<const char*> middle = { |
| // clang-format off |
| "%2 = OpTypeVoid", |
| "%3 = OpTypeFunction %2", |
| "%10 = OpTypeBool", |
| "%11 = OpConstantFalse %10", |
| "%1 = OpFunction %2 None %3", |
| "%5 = OpLabel", |
| "OpBranch %6", |
| "%6 = OpLabel", |
| "OpLoopMerge %8 %9 None", |
| "OpBranchConditional %11 %9 %7", |
| "%7 = OpLabel", |
| "%21 = OpCopyObject %10 %11", |
| "OpBranchConditional %11 %9 %9", |
| "%9 = OpLabel", |
| "%20 = OpPhi %10 %21 %7 %11 %6", |
| "OpBranchConditional %11 %6 %8", |
| "%8 = OpLabel", |
| "OpReturn", |
| "OpFunctionEnd", |
| // clang-format on |
| }; |
| std::string spirv = JoinAllInsts(Concat(before_, middle)); |
| spirv_cross::ParsedIR ir; |
| ASSERT_EQ(createSpvcIr(&ir, spirv), true) |
| << "Could not create IRContext for input:\n" + spirv + "\n"; |
| |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| spirv, true, true, &ir); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto spir_var = maybe_get<spirv_cross::SPIRVariable>(20, &ir); |
| ASSERT_NE(spir_var, nullptr); |
| EXPECT_EQ(spir_var->basetype, static_cast<spirv_cross::TypeID>(10)); |
| EXPECT_EQ(spir_var->storage, spv::StorageClass::StorageClassFunction); |
| EXPECT_TRUE(spir_var->phi_variable); |
| } |
| |
| TEST_F(SpvcIrParsingTest, OpReturnInstruction) { |
| auto result = SinglePassRunAndDisassemble<SpvcIrPass, spirv_cross::ParsedIR*>( |
| input_, true, false, &ir_); |
| ASSERT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)) |
| << " SinglePassRunAndDisassemble failed on input:\n " |
| << std::get<0>(result); |
| |
| auto block = maybe_get<spirv_cross::SPIRBlock>(4, &ir_); |
| ASSERT_NE(block, nullptr); |
| EXPECT_EQ(block->terminator, spirv_cross::SPIRBlock::Return); |
| } |
| |
| } // namespace |
| } // namespace opt |
| } // namespace spvtools |