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:
Alan Baker 2018-02-21 08:51:21 -05:00
parent 51ecc7318f
commit 01760d2f0f
2 changed files with 141 additions and 5 deletions

View File

@ -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;
}

View File

@ -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