opt: allow aggressive DCE to optimize untyped_pointers (#6602)
This will be required to allow DXC generating descriptor heaps code
which uses untyped pointers/descriptor_heap
diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp
index b8f239d..479ba79 100644
--- a/source/opt/aggressive_dead_code_elim_pass.cpp
+++ b/source/opt/aggressive_dead_code_elim_pass.cpp
@@ -128,6 +128,7 @@
switch (user->opcode()) {
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
+ case spv::Op::OpUntypedAccessChainKHR:
case spv::Op::OpCopyObject:
this->AddStores(func, user->result_id());
break;
@@ -1123,6 +1124,7 @@
"SPV_EXT_demote_to_helper_invocation",
"SPV_EXT_descriptor_indexing",
"SPV_EXT_descriptor_heap",
+ "SPV_KHR_untyped_pointers",
"SPV_NV_fragment_shader_barycentric",
"SPV_NV_compute_shader_derivatives",
"SPV_NV_shader_image_footprint",
diff --git a/source/opt/instruction.cpp b/source/opt/instruction.cpp
index 6ec4c65..2bfd491 100644
--- a/source/opt/instruction.cpp
+++ b/source/opt/instruction.cpp
@@ -252,6 +252,7 @@
switch (base_inst->opcode()) {
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
+ case spv::Op::OpUntypedAccessChainKHR:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
case spv::Op::OpImageTexelPointer:
diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp
index 7327a2c..6a66d2b 100644
--- a/source/opt/ir_context.cpp
+++ b/source/opt/ir_context.cpp
@@ -580,6 +580,7 @@
(uint32_t)spv::Op::OpTypeStruct,
(uint32_t)spv::Op::OpTypeOpaque,
(uint32_t)spv::Op::OpTypePointer,
+ (uint32_t)spv::Op::OpTypeUntypedPointerKHR,
(uint32_t)spv::Op::OpTypeFunction,
(uint32_t)spv::Op::OpTypeEvent,
(uint32_t)spv::Op::OpTypeDeviceEvent,
@@ -588,10 +589,12 @@
(uint32_t)spv::Op::OpTypePipe,
(uint32_t)spv::Op::OpTypeForwardPointer,
(uint32_t)spv::Op::OpVariable,
+ (uint32_t)spv::Op::OpUntypedVariableKHR,
(uint32_t)spv::Op::OpImageTexelPointer,
(uint32_t)spv::Op::OpLoad,
(uint32_t)spv::Op::OpAccessChain,
(uint32_t)spv::Op::OpInBoundsAccessChain,
+ (uint32_t)spv::Op::OpUntypedAccessChainKHR,
(uint32_t)spv::Op::OpArrayLength,
(uint32_t)spv::Op::OpVectorExtractDynamic,
(uint32_t)spv::Op::OpVectorInsertDynamic,
diff --git a/source/opt/mem_pass.cpp b/source/opt/mem_pass.cpp
index 8da0668..4d061ff 100644
--- a/source/opt/mem_pass.cpp
+++ b/source/opt/mem_pass.cpp
@@ -72,7 +72,8 @@
bool MemPass::IsNonPtrAccessChain(const spv::Op opcode) const {
return opcode == spv::Op::OpAccessChain ||
- opcode == spv::Op::OpInBoundsAccessChain;
+ opcode == spv::Op::OpInBoundsAccessChain ||
+ opcode == spv::Op::OpUntypedAccessChainKHR;
}
bool MemPass::IsPtr(uint32_t ptrId) {
@@ -88,11 +89,14 @@
ptrInst = get_def_use_mgr()->GetDef(varId);
}
const spv::Op op = ptrInst->opcode();
- if (op == spv::Op::OpVariable || IsNonPtrAccessChain(op)) return true;
+ if (op == spv::Op::OpVariable || op == spv::Op::OpUntypedVariableKHR ||
+ IsNonPtrAccessChain(op))
+ return true;
const uint32_t varTypeId = ptrInst->type_id();
if (varTypeId == 0) return false;
const Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId);
- return varTypeInst->opcode() == spv::Op::OpTypePointer;
+ return varTypeInst->opcode() == spv::Op::OpTypePointer ||
+ varTypeInst->opcode() == spv::Op::OpTypeUntypedPointerKHR;
}
Instruction* MemPass::GetPtr(uint32_t ptrId, uint32_t* varId) {
@@ -102,11 +106,13 @@
switch (ptrInst->opcode()) {
case spv::Op::OpVariable:
+ case spv::Op::OpUntypedVariableKHR:
case spv::Op::OpFunctionParameter:
varInst = ptrInst;
break;
case spv::Op::OpAccessChain:
case spv::Op::OpInBoundsAccessChain:
+ case spv::Op::OpUntypedAccessChainKHR:
case spv::Op::OpPtrAccessChain:
case spv::Op::OpInBoundsPtrAccessChain:
case spv::Op::OpImageTexelPointer:
@@ -119,7 +125,8 @@
break;
}
- if (varInst->opcode() == spv::Op::OpVariable) {
+ if (varInst->opcode() == spv::Op::OpVariable ||
+ varInst->opcode() == spv::Op::OpUntypedVariableKHR) {
*varId = varInst->result_id();
} else {
*varId = 0;
diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp
index e5990d4..a3a75e3 100644
--- a/test/opt/aggressive_dead_code_elim_test.cpp
+++ b/test/opt/aggressive_dead_code_elim_test.cpp
@@ -9025,6 +9025,199 @@
SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
}
+TEST_F(AggressiveDCETest, EliminateUntypedAccessChain) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability Sampled1D
+ OpCapability DescriptorHeapEXT
+ OpCapability UntypedPointersKHR
+ OpExtension "SPV_EXT_descriptor_heap"
+ OpExtension "SPV_KHR_untyped_pointers"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpName %main "main"
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%type_untyped_pointer = OpTypeUntypedPointerKHR Uniform
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %10 = OpTypeFunction %void
+%type_1d_image = OpTypeImage %float 1D 2 0 0 1 Unknown
+%_ptr_Function_type_1d_image = OpTypePointer Function %type_1d_image
+%type_buffer_ext = OpTypeBufferEXT StorageBuffer
+%_runtimearr_type_buffer_ext = OpTypeRuntimeArray %type_buffer_ext
+%resource_heap = OpUntypedVariableKHR %type_untyped_pointer Uniform
+ %main = OpFunction %void None %10
+ %20 = OpLabel
+ %t1d = OpVariable %_ptr_Function_type_1d_image Function
+; CHECK-NOT: OpUntypedAccessChainKHR
+ %21 = OpUntypedAccessChainKHR %type_untyped_pointer %_runtimearr_type_buffer_ext %resource_heap %uint_0
+; CHECK-NOT: OpLoad %type_1d_image
+ %22 = OpLoad %type_1d_image %21
+; CHECK-NOT: OpStore %t1d
+ OpStore %t1d %22
+ OpReturn
+ OpFunctionEnd
+ )";
+ SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
+}
+
+TEST_F(AggressiveDCETest, NoEliminateLiveUntypedAccessChain) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability DescriptorHeapEXT
+ OpCapability UntypedPointersKHR
+ OpExtension "SPV_EXT_descriptor_heap"
+ OpExtension "SPV_KHR_untyped_pointers"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %outColor
+ OpExecutionMode %main OriginUpperLeft
+ OpName %main "main"
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%type_untyped_pointer = OpTypeUntypedPointerKHR Uniform
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %outColor = OpVariable %_ptr_Output_v4float Output
+ %10 = OpTypeFunction %void
+%type_buffer_ext = OpTypeBufferEXT StorageBuffer
+%_runtimearr_type_buffer_ext = OpTypeRuntimeArray %type_buffer_ext
+%resource_heap = OpUntypedVariableKHR %type_untyped_pointer Uniform
+ %main = OpFunction %void None %10
+ %20 = OpLabel
+; CHECK: OpUntypedAccessChainKHR
+ %21 = OpUntypedAccessChainKHR %type_untyped_pointer %_runtimearr_type_buffer_ext %resource_heap %uint_0
+; CHECK: OpLoad
+ %22 = OpLoad %v4float %21
+ OpStore %outColor %22
+ OpReturn
+ OpFunctionEnd
+ )";
+ SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
+}
+
+TEST_F(AggressiveDCETest, EliminateUntypedAccessChainWithCopyObject) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability Sampled1D
+ OpCapability DescriptorHeapEXT
+ OpCapability UntypedPointersKHR
+ OpExtension "SPV_EXT_descriptor_heap"
+ OpExtension "SPV_KHR_untyped_pointers"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ OpName %main "main"
+ OpName %type_1d_image "type_1d_image"
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%type_untyped_pointer = OpTypeUntypedPointerKHR Uniform
+ %void = OpTypeVoid
+ %float = OpTypeFloat 32
+ %10 = OpTypeFunction %void
+%type_1d_image = OpTypeImage %float 1D 2 0 0 1 Unknown
+%_ptr_Function_type_1d_image = OpTypePointer Function %type_1d_image
+%type_buffer_ext = OpTypeBufferEXT StorageBuffer
+%_runtimearr_type_buffer_ext = OpTypeRuntimeArray %type_buffer_ext
+%resource_heap = OpUntypedVariableKHR %type_untyped_pointer Uniform
+ %main = OpFunction %void None %10
+ %20 = OpLabel
+ %t1d = OpVariable %_ptr_Function_type_1d_image Function
+; CHECK-NOT: OpUntypedAccessChainKHR
+ %21 = OpUntypedAccessChainKHR %type_untyped_pointer %_runtimearr_type_buffer_ext %resource_heap %uint_0
+; CHECK-NOT: OpCopyObject
+ %22 = OpCopyObject %type_untyped_pointer %21
+; CHECK-NOT: OpLoad %type_1d_image
+ %23 = OpLoad %type_1d_image %22
+; CHECK-NOT: OpStore %t1d
+ OpStore %t1d %23
+ OpReturn
+ OpFunctionEnd
+ )";
+ SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
+}
+
+// For now, aggressive DCE does not optimizes this pattern. If you implement
+// it, remove this test.
+TEST_F(AggressiveDCETest, EliminateUntypedAtomic) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability Int64
+ OpCapability DescriptorHeapEXT
+ OpCapability UntypedPointersKHR
+ OpExtension "SPV_EXT_descriptor_heap"
+ OpExtension "SPV_KHR_untyped_pointers"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%type_untyped_pointer = OpTypeUntypedPointerKHR Uniform
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void
+%type_buffer_ext = OpTypeBufferEXT StorageBuffer
+%_runtimearr_type_buffer_ext = OpTypeRuntimeArray %type_buffer_ext
+%resource_heap = OpUntypedVariableKHR %type_untyped_pointer Uniform
+ %main = OpFunction %void None %10
+ %20 = OpLabel
+ %21 = OpUntypedAccessChainKHR %type_untyped_pointer %_runtimearr_type_buffer_ext %resource_heap %uint_0
+; CHECK: [[ptr:%\w+]] = OpUntypedAccessChainKHR
+ %22 = OpAtomicLoad %uint %21 %uint_0 %uint_0
+; CHECK: OpAtomicLoad %uint [[ptr]]
+ OpReturn
+ OpFunctionEnd
+ )";
+ SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
+}
+
+TEST_F(AggressiveDCETest, EliminateUntypedAccessChainLoop) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability Sampled1D
+ OpCapability DescriptorHeapEXT
+ OpCapability UntypedPointersKHR
+ OpExtension "SPV_EXT_descriptor_heap"
+ OpExtension "SPV_KHR_untyped_pointers"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main"
+ OpExecutionMode %main OriginUpperLeft
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+ %uint_1 = OpConstant %uint 1
+ %uint_10 = OpConstant %uint 10
+%type_untyped_pointer = OpTypeUntypedPointerKHR Uniform
+ %void = OpTypeVoid
+ %bool = OpTypeBool
+ %10 = OpTypeFunction %void
+%type_1d_image = OpTypeImage %uint 1D 2 0 0 1 Unknown
+%type_buffer_ext = OpTypeBufferEXT StorageBuffer
+%_runtimearr_type_buffer_ext = OpTypeRuntimeArray %type_buffer_ext
+%resource_heap = OpUntypedVariableKHR %type_untyped_pointer Uniform
+ %main = OpFunction %void None %10
+ %20 = OpLabel
+ OpBranch %header
+ %header = OpLabel
+ %count = OpPhi %uint %uint_0 %20 %next %loop
+ %cond = OpULessThan %bool %count %uint_10
+ OpLoopMerge %exit %loop None
+ OpBranchConditional %cond %loop %exit
+ %loop = OpLabel
+; CHECK-NOT: OpUntypedAccessChainKHR
+ %21 = OpUntypedAccessChainKHR %type_untyped_pointer %_runtimearr_type_buffer_ext %resource_heap %count
+; CHECK-NOT: OpLoad
+ %22 = OpLoad %type_1d_image %21
+ %next = OpIAdd %uint %count %uint_1
+ OpBranch %header
+ %exit = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+ SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
+}
+
} // namespace
} // namespace opt
} // namespace spvtools