mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-27 02:10:15 +00:00
Fixes #1338. Handle OpConstantNull in branch/switch conditions
* No longer assume the branch/switch condition must be bool or int constants (respectively) * Added a couple unit tests for each case
This commit is contained in:
parent
51ecc7318f
commit
01760d2f0f
@ -183,9 +183,15 @@ SSAPropagator::PropStatus CCPPass::VisitBranch(ir::Instruction* instr,
|
||||
uint32_t pred_val_id = it->second;
|
||||
const analysis::Constant* c = const_mgr_->FindDeclaredConstant(pred_val_id);
|
||||
assert(c && "Expected to find a constant declaration for a known value.");
|
||||
const analysis::BoolConstant* val = c->AsBoolConstant();
|
||||
dest_label = val->value() ? instr->GetSingleWordOperand(1)
|
||||
: instr->GetSingleWordOperand(2);
|
||||
// Undef values should have returned as varying above.
|
||||
assert(c->AsBoolConstant() || c->AsNullConstant());
|
||||
if (c->AsNullConstant()) {
|
||||
dest_label = instr->GetSingleWordOperand(2u);
|
||||
} else {
|
||||
const analysis::BoolConstant* val = c->AsBoolConstant();
|
||||
dest_label = val->value() ? instr->GetSingleWordOperand(1)
|
||||
: instr->GetSingleWordOperand(2);
|
||||
}
|
||||
} else {
|
||||
// For an OpSwitch, extract the value taken by the switch selector and check
|
||||
// which of the target literals it matches. The branch associated with that
|
||||
@ -209,12 +215,20 @@ SSAPropagator::PropStatus CCPPass::VisitBranch(ir::Instruction* instr,
|
||||
const analysis::Constant* c =
|
||||
const_mgr_->FindDeclaredConstant(select_val_id);
|
||||
assert(c && "Expected to find a constant declaration for a known value.");
|
||||
const analysis::IntConstant* val = c->AsIntConstant();
|
||||
// TODO: support 64-bit integer switches.
|
||||
uint32_t constant_cond = 0;
|
||||
if (const analysis::IntConstant* val = c->AsIntConstant()) {
|
||||
constant_cond = val->words()[0];
|
||||
} else {
|
||||
// Undef values should have returned varying above.
|
||||
assert(c->AsNullConstant());
|
||||
constant_cond = 0;
|
||||
}
|
||||
|
||||
// Start assuming that the selector will take the default value;
|
||||
dest_label = instr->GetSingleWordOperand(1);
|
||||
for (uint32_t i = 2; i < instr->NumOperands(); i += 2) {
|
||||
if (val->words()[0] == instr->GetSingleWordOperand(i)) {
|
||||
if (constant_cond == instr->GetSingleWordOperand(i)) {
|
||||
dest_label = instr->GetSingleWordOperand(i + 1);
|
||||
break;
|
||||
}
|
||||
|
@ -733,6 +733,128 @@ OpFunctionEnd
|
||||
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunToBinary<opt::CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, NullBranchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%int = OpTypeInt 32 1
|
||||
%null = OpConstantNull %bool
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpBranchConditional %null %2 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, UndefBranchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[phi:%\w+]] = OpPhi
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%int = OpTypeInt 32 1
|
||||
%undef = OpUndef %bool
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpBranchConditional %undef %2 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, NullSwitchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 1
|
||||
%null = OpConstantNull %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpSwitch %null %2 0 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, UndefSwitchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[phi:%\w+]] = OpPhi
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 1
|
||||
%undef = OpUndef %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpSwitch %undef %2 0 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<opt::CCPPass>(text, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
Loading…
Reference in New Issue
Block a user