spirv-reader: CFG tests: make valid SPIR-V

Bug: tint:765
Change-Id: I84ea018478feafc4a5c03052832acae8cf3f15b9
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49940
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: Alan Baker <alanbaker@google.com>
This commit is contained in:
David Neto 2021-05-07 20:33:05 +00:00 committed by Commit Bot service account
parent 74490e118e
commit 6732e8561c
1 changed files with 139 additions and 44 deletions

View File

@ -46,6 +46,8 @@ std::string CommonTypes() {
return R"(
OpCapability Shader
OpMemoryModel Logical Simple
OpEntryPoint Fragment %100 "main"
OpExecutionMode %100 OriginUpperLeft
OpName %var "var"
@ -1078,13 +1080,17 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_ReorderSequence) {
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
OpSelectionMerge %99 None
OpBranchConditional %cond %20 %30
%30 = OpLabel
OpReturn
%20 = OpLabel
OpBranch %30 ; backtrack
OpBranch %30 ; backtrack, but does dominate %30
%99 = OpLabel
OpReturn
OpFunctionEnd
)"));
@ -1093,7 +1099,7 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_ReorderSequence) {
fe.RegisterBasicBlocks();
fe.ComputeBlockOrderAndPositions();
EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30));
EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 99));
const auto* bi10 = fe.GetBlockInfo(10);
ASSERT_NE(bi10, nullptr);
@ -1104,6 +1110,9 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_ReorderSequence) {
const auto* bi30 = fe.GetBlockInfo(30);
ASSERT_NE(bi30, nullptr);
EXPECT_EQ(bi30->pos, 2u);
const auto* bi99 = fe.GetBlockInfo(99);
ASSERT_NE(bi99, nullptr);
EXPECT_EQ(bi99->pos, 3u);
}
TEST_F(SpvParserCFGTest, ComputeBlockOrder_DupConditionalBranch) {
@ -1114,12 +1123,12 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_DupConditionalBranch) {
OpSelectionMerge %99 None
OpBranchConditional %cond %20 %20
%99 = OpLabel
OpReturn
%20 = OpLabel
OpBranch %99
%99 = OpLabel
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
@ -1138,15 +1147,15 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectConditionalBranchOrder) {
OpSelectionMerge %99 None
OpBranchConditional %cond %20 %30
%99 = OpLabel
OpReturn
%30 = OpLabel
OpReturn
%20 = OpLabel
OpBranch %99
%99 = OpLabel ; dominated by %20, so follow %20
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
@ -1299,7 +1308,9 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectSwitchCaseFallthrough) {
%10 = OpLabel
OpSelectionMerge %99 None
OpSwitch %selector %99 20 %20 30 %30 40 %40 50 %50
; SPIR-V validation requires a fallthrough destination to immediately
; follow the source. So %20 -> %40, %30 -> %50
OpSwitch %selector %99 20 %20 40 %40 30 %30 50 %50
%50 = OpLabel
OpBranch %99
@ -1373,9 +1384,6 @@ TEST_F(SpvParserCFGTest,
OpSelectionMerge %99 None
OpSwitch %selector %80 20 %20 30 %30
%99 = OpLabel
OpReturn
%20 = OpLabel
OpBranch %80 ; fallthrough to default
@ -1385,6 +1393,9 @@ TEST_F(SpvParserCFGTest,
%30 = OpLabel
OpBranch %99
%99 = OpLabel ; dominated by %30, so follow %30
OpReturn
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
@ -1432,6 +1443,9 @@ TEST_F(SpvParserCFGTest,
EXPECT_THAT(fe.block_order(), ElementsAre(10, 50, 40, 20, 30, 99))
<< assembly;
// We're deliberately testing a case that SPIR-V doesn't allow.
p->DeliberatelyInvalidSpirv();
}
TEST_F(SpvParserCFGTest,
@ -1441,7 +1455,9 @@ TEST_F(SpvParserCFGTest,
%10 = OpLabel
OpSelectionMerge %99 None
OpSwitch %selector %99 20 %20 30 %30 40 %40 50 %50
; SPIR-V validation requires a fallthrough destination to immediately
; follow the source. So %20 -> %40
OpSwitch %selector %99 20 %20 40 %40 30 %30 50 %50
%99 = OpLabel
OpReturn
@ -1641,22 +1657,22 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_IfBreak_In_SwitchCase) {
OpSelectionMerge %49 None
OpBranchConditional %cond %99 %40 ; break-if
%49 = OpLabel
OpBranch %99
%40 = OpLabel
OpBranch %49
%49 = OpLabel
OpBranch %99
%50 = OpLabel
OpSelectionMerge %79 None
OpBranchConditional %cond %60 %99 ; break-unless
%79 = OpLabel
OpBranch %99
%60 = OpLabel
OpBranch %79
%79 = OpLabel ; dominated by 60, so must follow 60
OpBranch %99
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
@ -2184,6 +2200,11 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch_CaseBreaks) {
EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99))
<< assembly;
// Fails SPIR-V validation:
// Branch from block 40 to block 99 is an invalid exit from construct starting
// at block 30; branch bypasses merge block 49
p->DeliberatelyInvalidSpirv();
}
TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch_CaseContinues) {
@ -2240,6 +2261,7 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasSwitchContinueBreak) {
OpBranchConditional %cond %30 %99
%30 = OpLabel
; OpSwitch must be preceded by a selection merge
OpSwitch %selector %99 50 %50 ; default is break, 50 is continue
%40 = OpLabel
@ -2254,12 +2276,10 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasSwitchContinueBreak) {
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
auto fe = p->function_emitter(100);
fe.RegisterBasicBlocks();
fe.ComputeBlockOrderAndPositions();
EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
EXPECT_FALSE(p->Parse());
EXPECT_FALSE(p->success());
EXPECT_THAT(p->error(),
HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
}
TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_Sequence) {
@ -2414,7 +2434,9 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_SwitchBreak) {
OpBranch %50
%50 = OpLabel
OpSwitch %selector %20 99 %99 ; yes, this is obtuse but valid
; Updated SPIR-V rule:
; OpSwitch must be preceded by a selection.
OpSwitch %selector %20 99 %99
%99 = OpLabel
OpReturn
@ -2422,12 +2444,10 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_SwitchBreak) {
OpFunctionEnd
)";
auto p = parser(test::Assemble(assembly));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
auto fe = p->function_emitter(100);
fe.RegisterBasicBlocks();
fe.ComputeBlockOrderAndPositions();
EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
EXPECT_FALSE(p->Parse());
EXPECT_FALSE(p->success());
EXPECT_THAT(p->error(),
HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
}
TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop) {
@ -2653,6 +2673,11 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerContinueContinues) {
EXPECT_THAT(fe.block_order(),
ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
p->DeliberatelyInvalidSpirv();
// SPIR-V validation fails:
// block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
// via a structured exit"
}
TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_SwitchBackedgeBreakContinue) {
@ -2703,6 +2728,11 @@ TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_SwitchBackedgeBreakContinue
EXPECT_THAT(fe.block_order(),
ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
p->DeliberatelyInvalidSpirv();
// SPIR-V validation fails:
// block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
// via a structured exit"
}
TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_Selection_Good) {
@ -3178,7 +3208,7 @@ TEST_F(SpvParserCFGTest,
%20 = OpLabel
OpLoopMerge %99 %20 None
OpBranchConditional %cond %30 %99
OpBranch %30
%30 = OpLabel
OpBranch %40
@ -3187,7 +3217,7 @@ TEST_F(SpvParserCFGTest,
OpBranch %50
%50 = OpLabel
OpBranch %20
OpBranchConditional %cond %20 %99
%99 = OpLabel
OpReturn
@ -3487,7 +3517,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_Loop) {
%20 = OpLabel
OpLoopMerge %89 %50 None
OpBranchConditional %cond %30 %99
OpBranchConditional %cond %30 %89
%30 = OpLabel ; single block loop
OpLoopMerge %40 %30 None
@ -3650,7 +3680,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_SingleBlockLoop) {
%20 = OpLabel
OpLoopMerge %89 %20 None
OpBranchConditional %cond %20 %99
OpBranchConditional %cond %20 %89
%89 = OpLabel
OpBranch %99
@ -3702,7 +3732,7 @@ TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_MultiBlockLoop) {
OpBranch %20
%89 = OpLabel ; merge for the loop
OpBranch %20
OpBranch %99
%99 = OpLabel ; merge for the if
OpReturn
@ -4050,6 +4080,9 @@ TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseCanBeSwitchMerge) {
fe.RegisterMerges();
fe.LabelControlFlowConstructs();
EXPECT_TRUE(fe.FindSwitchCaseHeaders());
// TODO(crbug.com/tint/774) Re-enable after codegen bug fixed.
p->DeliberatelyInvalidSpirv();
}
TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseCantEscapeSwitch) {
@ -7493,6 +7526,10 @@ TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_WithForwardToPremerge) {
EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
EXPECT_THAT(p->error(), Eq(""));
// TODO(crbug.com/tint/775): The SPIR-V reader errors out on this case.
// Remove this when it's fixed.
p->DeliberatelyInvalidSpirv();
}
TEST_F(
@ -10460,7 +10497,7 @@ Return{
TEST_F(SpvParserCFGTest, EmitBody_ReturnValue_Loop) {
auto p = parser(test::Assemble(CommonTypes() + R"(
%200 = OpFunction %void None %voidfn
%200 = OpFunction %uint None %uintfn
%210 = OpLabel
OpBranch %220
@ -11002,8 +11039,9 @@ TEST_F(
"(violates post-dominance rule)"));
}
TEST_F(SpvParserCFGTest,
EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd) {
TEST_F(
SpvParserCFGTest,
EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Unconditional) {
auto p = parser(test::Assemble(CommonTypes() + R"(
%100 = OpFunction %void None %voidfn
@ -11017,6 +11055,52 @@ TEST_F(SpvParserCFGTest,
%80 = OpLabel ; continue target
OpStore %var %uint_1
OpBranch %99 ; should be a backedge
; This is invalid as there must be a backedge to the loop header.
; The SPIR-V allows this and understands how to emit it, even if it's not
; permitted by the SPIR-V validator.
%99 = OpLabel
OpReturn
OpFunctionEnd
)"));
p->DeliberatelyInvalidSpirv();
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
auto fe = p->function_emitter(100);
EXPECT_TRUE(fe.EmitBody()) << p->error();
auto got = ToString(p->builder(), fe.ast_body());
auto* expect = R"(Loop{
continuing {
Assignment{
Identifier[not set]{var_1}
ScalarConstructor[not set]{1u}
}
Break{}
}
}
Return{}
)";
ASSERT_EQ(expect, got);
}
TEST_F(
SpvParserCFGTest,
EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Conditional) {
auto p = parser(test::Assemble(CommonTypes() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
%20 = OpLabel
OpLoopMerge %99 %80 None
OpBranch %80
%80 = OpLabel ; continue target
OpStore %var %uint_1
OpBranchConditional %cond %20 %99 ; backedge, and exit
%99 = OpLabel
OpReturn
@ -11033,7 +11117,18 @@ TEST_F(SpvParserCFGTest,
Identifier[not set]{var_1}
ScalarConstructor[not set]{1u}
}
Break{}
If{
(
ScalarConstructor[not set]{false}
)
{
}
}
Else{
{
Break{}
}
}
}
}
Return{}
@ -14198,10 +14293,10 @@ TEST_F(SpvParserCFGTest, SiblingLoopConstruct_ContinueIsWholeMultiBlockLoop) {
%20 = OpLabel
OpLoopMerge %99 %20 None ; continue target is also loop header
OpBranchConditional %cond %30 %99
OpBranch %30
%30 = OpLabel
OpBranch %20
OpBranchConditional %cond %20 %99
%99 = OpLabel
OpReturn