Teach array copy propagation about OpImageTexelPointer.

OpImageTexelPointer acts like a special kind of load.  It is not an
array load, but it also cannot be removed the same way a regular
load can.  The type of propagation that needs to be done is similar
to what we do for arrays, so I want to merge that code into that
optmization.

Contributers to #1445.
This commit is contained in:
Steven Perron 2018-04-02 16:13:25 -04:00 committed by Steven Perron
parent e64a4656b3
commit c33af63264
2 changed files with 98 additions and 3 deletions

View File

@ -134,6 +134,10 @@ ir::Instruction* CopyPropagateArrays::BuildNewAccessChain(
ir::IRContext::kAnalysisDefUse |
ir::IRContext::kAnalysisInstrToBlockMapping);
if (source->AccessChain().size() == 0) {
return source->GetVariable();
}
return builder.AddAccessChain(source->GetPointerTypeId(),
source->GetVariable()->result_id(),
source->AccessChain());
@ -150,6 +154,8 @@ bool CopyPropagateArrays::HasNoStores(ir::Instruction* ptr_inst) {
return true;
} else if (use->opcode() == SpvOpStore) {
return false;
} else if (use->opcode() == SpvOpImageTexelPointer) {
return true;
}
// Some other instruction. Be conservative.
return false;
@ -165,7 +171,8 @@ bool CopyPropagateArrays::HasValidReferencesOnly(ir::Instruction* ptr_inst,
return get_def_use_mgr()->WhileEachUser(
ptr_inst,
[this, store_inst, dominator_analysis, ptr_inst](ir::Instruction* use) {
if (use->opcode() == SpvOpLoad) {
if (use->opcode() == SpvOpLoad ||
use->opcode() == SpvOpImageTexelPointer) {
// TODO: If there are many load in the same BB as |store_inst| the
// time to do the multiple traverses can add up. Consider collecting
// those loads and doing a single traversal.
@ -455,7 +462,8 @@ bool CopyPropagateArrays::IsPointerToArrayType(uint32_t type_id) {
analysis::TypeManager* type_mgr = context()->get_type_mgr();
analysis::Pointer* pointer_type = type_mgr->GetType(type_id)->AsPointer();
if (pointer_type) {
return pointer_type->pointee_type()->AsArray() != nullptr;
return pointer_type->pointee_type()->kind() == analysis::Type::kArray ||
pointer_type->pointee_type()->kind() == analysis::Type::kImage;
}
return false;
}
@ -544,6 +552,8 @@ bool CopyPropagateArrays::CanUpdateUses(ir::Instruction* original_ptr_inst,
// TODO (s-perron): This can be handled by expanding the store into
// a series of extracts, composite constructs, and a store.
return true;
case SpvOpImageTexelPointer:
return true;
default:
return false;
}
@ -673,7 +683,16 @@ void CopyPropagateArrays::UpdateUses(ir::Instruction* original_ptr_inst,
context()->AnalyzeUses(use);
}
break;
case SpvOpImageTexelPointer:
// We treat an OpImageTexelPointer as a load. The result type should
// always have the Image storage class, and should not need to be
// updated.
// Replace the actual use.
context()->ForgetUses(use);
use->SetOperand(index, {new_ptr_inst->result_id()});
context()->AnalyzeUses(use);
break;
default:
assert(false && "Don't know how to rewrite instruction");
break;

View File

@ -22,8 +22,8 @@
namespace {
using namespace spvtools;
using ir::IRContext;
using ir::Instruction;
using ir::IRContext;
using opt::PassManager;
using CopyPropArrayPassTest = PassTest<::testing::Test>;
@ -1025,4 +1025,80 @@ OpFunctionEnd
EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
}
TEST_F(CopyPropArrayPassTest, AtomicAdd) {
const std::string before = R"(OpCapability SampledBuffer
OpCapability StorageImageExtendedFormats
OpCapability ImageBuffer
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
OpExecutionMode %2 LocalSize 64 1 1
OpSource HLSL 600
OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
OpDecorate %4 DescriptorSet 4
OpDecorate %4 Binding 70
%uint = OpTypeInt 32 0
%6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
%_ptr_Function_6 = OpTypePointer Function %6
%void = OpTypeVoid
%10 = OpTypeFunction %void
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%_ptr_Image_uint = OpTypePointer Image %uint
%4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
%2 = OpFunction %void None %10
%17 = OpLabel
%16 = OpVariable %_ptr_Function_6 Function
%18 = OpLoad %6 %4
OpStore %16 %18
%19 = OpImageTexelPointer %_ptr_Image_uint %16 %uint_0 %uint_0
%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
OpReturn
OpFunctionEnd
)";
const std::string after = R"(OpCapability SampledBuffer
OpCapability StorageImageExtendedFormats
OpCapability ImageBuffer
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
OpExecutionMode %2 LocalSize 64 1 1
OpSource HLSL 600
OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
OpDecorate %4 DescriptorSet 4
OpDecorate %4 Binding 70
%uint = OpTypeInt 32 0
%6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
%_ptr_Function_6 = OpTypePointer Function %6
%void = OpTypeVoid
%10 = OpTypeFunction %void
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%_ptr_Image_uint = OpTypePointer Image %uint
%4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
%2 = OpFunction %void None %10
%17 = OpLabel
%16 = OpVariable %_ptr_Function_6 Function
%18 = OpLoad %6 %4
OpStore %16 %18
%19 = OpImageTexelPointer %_ptr_Image_uint %4 %uint_0 %uint_0
%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
OpReturn
OpFunctionEnd
)";
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
SinglePassRunAndCheck<opt::CopyPropagateArrays>(before, after, true, true);
}
} // namespace