From 73876defc8d9bd7ff42d5f71b15eb3db0cf86c65 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Thu, 19 Oct 2023 13:02:46 -0700 Subject: [PATCH] opt: support 64-bit OpAccessChain index in FixStorageClass (#5446) The SPIR-V specification allows any scalar integer type as an index. DXC usually emits indexes as 32-bit integer types, however, in some cases it is possible to make it emit 64-bit indexes instead (as in https://github.com/microsoft/DirectXShaderCompiler/issues/5638). --- source/opt/fix_storage_class.cpp | 8 +++++- test/opt/fix_storage_class_test.cpp | 41 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/source/opt/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp index 5597e825b2..564cd1b8a3 100644 --- a/source/opt/fix_storage_class.cpp +++ b/source/opt/fix_storage_class.cpp @@ -318,7 +318,13 @@ uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) { const analysis::Constant* index_const = context()->get_constant_mgr()->FindDeclaredConstant( inst->GetSingleWordInOperand(i)); - uint32_t index = index_const->GetU32(); + // It is highly unlikely that any type would have more fields than could + // be indexed by a 32-bit integer, and GetSingleWordInOperand only takes + // a 32-bit value, so we would not be able to handle it anyway. But the + // specification does allow any scalar integer type, treated as signed, + // so we simply downcast the index to 32-bits. + uint32_t index = + static_cast(index_const->GetSignExtendedValue()); id = type_inst->GetSingleWordInOperand(index); break; } diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp index 93ce873605..684e006eca 100644 --- a/test/opt/fix_storage_class_test.cpp +++ b/test/opt/fix_storage_class_test.cpp @@ -874,6 +874,47 @@ TEST_F(FixTypeTest, FixPhiInLoop) { SinglePassRunAndMatch(text, false); } +TEST_F(FixStorageClassTest, SupportsU64Index) { + const std::string text = R"( +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_LocalInvocationID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %8 DescriptorSet 0 + OpDecorate %8 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %ulong = OpTypeInt 64 0 + %ulong_0 = OpConstant %ulong 0 + %float = OpTypeFloat 32 + %float_123 = OpConstant %float 123 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %30 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %8 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %30 + %38 = OpLabel + %44 = OpLoad %v3uint %gl_LocalInvocationID + %59 = OpCompositeExtract %uint %44 0 + %60 = OpAccessChain %_ptr_Uniform_float %8 %ulong_0 %59 + OpStore %60 %float_123 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} } // namespace } // namespace opt