mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-13 09:50:06 +00:00
Add unrolling to the legalization passes (#1903)
Adds unrolling to the legalization passes. After enabling unrolling I found a bug when there is a self-referencing phi node. That has been fixed. The test that checks for that the order of optimizations is correct also needed to be updated.
This commit is contained in:
parent
9e99d8b691
commit
9fbcce4ca1
@ -244,6 +244,10 @@ class LoopUnrollerUtilsImpl {
|
|||||||
// ect).
|
// ect).
|
||||||
void AssignNewResultIds(BasicBlock* basic_block);
|
void AssignNewResultIds(BasicBlock* basic_block);
|
||||||
|
|
||||||
|
// Using the map built by AssignNewResultIds, replace the uses in |inst|
|
||||||
|
// by the id that the use maps to.
|
||||||
|
void RemapOperands(Instruction* inst);
|
||||||
|
|
||||||
// Using the map built by AssignNewResultIds, for each instruction in
|
// Using the map built by AssignNewResultIds, for each instruction in
|
||||||
// |basic_block| use
|
// |basic_block| use
|
||||||
// that map to substitute the IDs used by instructions (in the operands) with
|
// that map to substitute the IDs used by instructions (in the operands) with
|
||||||
@ -757,6 +761,11 @@ void LoopUnrollerUtilsImpl::CloseUnrolledLoop(Loop* loop) {
|
|||||||
for (BasicBlock* block : loop_blocks_inorder_) {
|
for (BasicBlock* block : loop_blocks_inorder_) {
|
||||||
RemapOperands(block);
|
RemapOperands(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rewrite the last phis, since they may still reference the original phi.
|
||||||
|
for (Instruction* last_phi : state_.previous_phis_) {
|
||||||
|
RemapOperands(last_phi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses the first loop to create a copy of the loop with new IDs.
|
// Uses the first loop to create a copy of the loop with new IDs.
|
||||||
@ -842,19 +851,21 @@ void LoopUnrollerUtilsImpl::AssignNewResultIds(BasicBlock* basic_block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all instructions in |basic_block| check if the operands used are from a
|
void LoopUnrollerUtilsImpl::RemapOperands(Instruction* inst) {
|
||||||
// copied instruction and if so swap out the operand for the copy of it.
|
auto remap_operands_to_new_ids = [this](uint32_t* id) {
|
||||||
|
auto itr = state_.new_inst.find(*id);
|
||||||
|
|
||||||
|
if (itr != state_.new_inst.end()) {
|
||||||
|
*id = itr->second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inst->ForEachInId(remap_operands_to_new_ids);
|
||||||
|
}
|
||||||
|
|
||||||
void LoopUnrollerUtilsImpl::RemapOperands(BasicBlock* basic_block) {
|
void LoopUnrollerUtilsImpl::RemapOperands(BasicBlock* basic_block) {
|
||||||
for (Instruction& inst : *basic_block) {
|
for (Instruction& inst : *basic_block) {
|
||||||
auto remap_operands_to_new_ids = [this](uint32_t* id) {
|
RemapOperands(&inst);
|
||||||
auto itr = state_.new_inst.find(*id);
|
|
||||||
|
|
||||||
if (itr != state_.new_inst.end()) {
|
|
||||||
*id = itr->second;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inst.ForEachInId(remap_operands_to_new_ids);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +131,7 @@ Optimizer& Optimizer::RegisterLegalizationPasses() {
|
|||||||
// Propagate constants to get as many constant conditions on branches
|
// Propagate constants to get as many constant conditions on branches
|
||||||
// as possible.
|
// as possible.
|
||||||
.RegisterPass(CreateCCPPass())
|
.RegisterPass(CreateCCPPass())
|
||||||
|
.RegisterPass(CreateLoopUnrollPass(true))
|
||||||
.RegisterPass(CreateDeadBranchElimPass())
|
.RegisterPass(CreateDeadBranchElimPass())
|
||||||
// Copy propagate members. Cleans up code sequences generated by
|
// Copy propagate members. Cleans up code sequences generated by
|
||||||
// scalar replacement. Also important for removing OpPhi nodes.
|
// scalar replacement. Also important for removing OpPhi nodes.
|
||||||
|
@ -2952,6 +2952,52 @@ OpFunctionEnd
|
|||||||
EXPECT_NE(loop_2.GetLatchBlock(), loop_2.GetContinueBlock());
|
EXPECT_NE(loop_2.GetLatchBlock(), loop_2.GetContinueBlock());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that a loop with a self-referencing OpPhi instruction is handled
|
||||||
|
// correctly.
|
||||||
|
TEST_F(PassClassTest, OpPhiSelfReference) {
|
||||||
|
const std::string text = R"(
|
||||||
|
; Find the two adds from the unrolled loop
|
||||||
|
; CHECK: OpIAdd
|
||||||
|
; CHECK: OpIAdd
|
||||||
|
; CHECK: OpIAdd %uint %uint_0 %uint_1
|
||||||
|
; CHECK-NEXT: OpReturn
|
||||||
|
OpCapability Shader
|
||||||
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint GLCompute %2 "main"
|
||||||
|
OpExecutionMode %2 LocalSize 8 8 1
|
||||||
|
OpSource HLSL 600
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%5 = OpTypeFunction %void
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%uint_1 = OpConstant %uint 1
|
||||||
|
%bool = OpTypeBool
|
||||||
|
%true = OpConstantTrue %bool
|
||||||
|
%2 = OpFunction %void None %5
|
||||||
|
%10 = OpLabel
|
||||||
|
OpBranch %19
|
||||||
|
%19 = OpLabel
|
||||||
|
%20 = OpPhi %uint %uint_0 %10 %20 %21
|
||||||
|
%22 = OpPhi %uint %uint_0 %10 %23 %21
|
||||||
|
%24 = OpULessThanEqual %bool %22 %uint_1
|
||||||
|
OpLoopMerge %25 %21 Unroll
|
||||||
|
OpBranchConditional %24 %21 %25
|
||||||
|
%21 = OpLabel
|
||||||
|
%23 = OpIAdd %uint %22 %uint_1
|
||||||
|
OpBranch %19
|
||||||
|
%25 = OpLabel
|
||||||
|
%14 = OpIAdd %uint %20 %uint_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
const bool kFullyUnroll = true;
|
||||||
|
const uint32_t kUnrollFactor = 0;
|
||||||
|
SinglePassRunAndMatch<opt::LoopUnroller>(text, true, kFullyUnroll,
|
||||||
|
kUnrollFactor);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace opt
|
} // namespace opt
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
@ -235,6 +235,7 @@ class TestLegalizationPasses(expect.ValidObjectFile1_3,
|
|||||||
'eliminate-local-multi-store',
|
'eliminate-local-multi-store',
|
||||||
'eliminate-dead-code-aggressive',
|
'eliminate-dead-code-aggressive',
|
||||||
'ccp',
|
'ccp',
|
||||||
|
'loop-unroll',
|
||||||
'eliminate-dead-branches',
|
'eliminate-dead-branches',
|
||||||
'simplify-instructions',
|
'simplify-instructions',
|
||||||
'eliminate-dead-code-aggressive',
|
'eliminate-dead-code-aggressive',
|
||||||
|
Loading…
Reference in New Issue
Block a user