[spirv-reader] Refine selection construct concept
Distinguish between selections constructs starting with with OpBranchConditional and those starting with OpSwitch. We'll use this in a followup CL to track break from a switch. Bug: tint:3 Change-Id: I8d000cb42325535a4937c84f83a83c98a9b8d4c5 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/21080 Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
parent
054927d7eb
commit
920bdcd0aa
|
@ -31,10 +31,16 @@ namespace spirv {
|
||||||
struct Construct {
|
struct Construct {
|
||||||
/// Enumeration for the kinds of structured constructs.
|
/// Enumeration for the kinds of structured constructs.
|
||||||
enum Kind {
|
enum Kind {
|
||||||
kFunction, // The whole function.
|
/// The whole function.
|
||||||
kSelection, // A SPIR-V selection construct
|
kFunction,
|
||||||
kLoop, // A SPIR-V loop construct
|
/// A SPIR-V selection construct, header ending in OpBrancConditional
|
||||||
kContinue, // A SPIR-V continue construct
|
kIfSelection,
|
||||||
|
/// A SPIR-V selection construct, header ending in OpSwitch
|
||||||
|
kSwitchSelection,
|
||||||
|
/// A SPIR-V loop construct
|
||||||
|
kLoop,
|
||||||
|
/// A SPIR-V continue construct
|
||||||
|
kContinue,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
@ -94,8 +100,10 @@ inline std::string ToString(Construct::Kind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case Construct::kFunction:
|
case Construct::kFunction:
|
||||||
return "Function";
|
return "Function";
|
||||||
case Construct::kSelection:
|
case Construct::kIfSelection:
|
||||||
return "Selection";
|
return "IfSelection";
|
||||||
|
case Construct::kSwitchSelection:
|
||||||
|
return "SwitchSelection";
|
||||||
case Construct::kLoop:
|
case Construct::kLoop:
|
||||||
return "Loop";
|
return "Loop";
|
||||||
case Construct::kContinue:
|
case Construct::kContinue:
|
||||||
|
|
|
@ -791,7 +791,12 @@ bool FunctionEmitter::LabelControlFlowConstructs() {
|
||||||
// From the interval rule, the selection construct consists of blocks
|
// From the interval rule, the selection construct consists of blocks
|
||||||
// in the block order, starting at the header, until just before the
|
// in the block order, starting at the header, until just before the
|
||||||
// merge block.
|
// merge block.
|
||||||
top = push_construct(depth, Construct::kSelection, header, merge);
|
const auto branch_opcode =
|
||||||
|
header_info->basic_block->terminator()->opcode();
|
||||||
|
const auto kind = (branch_opcode == SpvOpBranchConditional)
|
||||||
|
? Construct::kIfSelection
|
||||||
|
: Construct::kSwitchSelection;
|
||||||
|
top = push_construct(depth, kind, header, merge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,14 +824,11 @@ bool FunctionEmitter::FindSwitchCaseHeaders() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (auto& construct : constructs_) {
|
for (auto& construct : constructs_) {
|
||||||
if (construct->kind != Construct::kSelection) {
|
if (construct->kind != Construct::kSwitchSelection) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto* branch =
|
const auto* branch =
|
||||||
GetBlockInfo(construct->begin_id)->basic_block->terminator();
|
GetBlockInfo(construct->begin_id)->basic_block->terminator();
|
||||||
if (branch->opcode() != SpvOpSwitch) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the default block
|
// Mark the default block
|
||||||
const auto default_id = branch->GetSingleWordInOperand(1);
|
const auto default_id = branch->GetSingleWordInOperand(1);
|
||||||
|
|
|
@ -43,17 +43,24 @@ enum class EdgeKind {
|
||||||
// A back-edge: An edge from a node to one of its ancestors in a depth-first
|
// A back-edge: An edge from a node to one of its ancestors in a depth-first
|
||||||
// search from the entry block.
|
// search from the entry block.
|
||||||
kBack,
|
kBack,
|
||||||
// An edge from a node to the merge block of the nearest enclosing structured
|
// An edge from a node to the merge block of the nearest enclosing switch,
|
||||||
// construct. We write "ToMerge" to make it clear the destination block is
|
// where there is no intervening loop.
|
||||||
// the merge block, not the source block.
|
kSwitchBreak,
|
||||||
kToMerge,
|
// An edge from a node to the merge block of the nearest enclosing loop, where
|
||||||
// An edge from a node to the merge block of the nearest enclosing loop.
|
// there is no intervening switch.
|
||||||
// The source block is a "break block" as defined by SPIR-V.
|
// The source block is a "break block" as defined by SPIR-V.
|
||||||
kLoopBreak,
|
kLoopBreak,
|
||||||
// An edge from a node in a loop body to the associated continue target, where
|
// An edge from a node in a loop body to the associated continue target, where
|
||||||
// there are no other intervening loops or switches.
|
// there are no other intervening loops or switches.
|
||||||
// The source block is a "continue block" as defined by SPIR-V.
|
// The source block is a "continue block" as defined by SPIR-V.
|
||||||
kLoopContinue,
|
kLoopContinue,
|
||||||
|
// An edge from a node to the merge block of the nearest enclosing structured
|
||||||
|
// construct, but which is neither a kSwitchBreak or a kLoopBreak.
|
||||||
|
// This can only occur for an "if" selection, i.e. where the selection
|
||||||
|
// header ends in OpBranchConditional.
|
||||||
|
// TODO(dneto): Rename this to kIfBreak after we correctly classify edges
|
||||||
|
// as kSwitchBreak.
|
||||||
|
kToMerge,
|
||||||
// An edge from one switch case to the next sibling switch case.
|
// An edge from one switch case to the next sibling switch case.
|
||||||
kCaseFallThrough,
|
kCaseFallThrough,
|
||||||
// None of the above. By structured control flow rules, there can be at most
|
// None of the above. By structured control flow rules, there can be at most
|
||||||
|
|
|
@ -2847,7 +2847,7 @@ TEST_F(SpvParserTest,
|
||||||
EXPECT_EQ(constructs.size(), 2u);
|
EXPECT_EQ(constructs.size(), 2u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
||||||
|
@ -2894,7 +2894,7 @@ TEST_F(
|
||||||
EXPECT_EQ(constructs.size(), 2u);
|
EXPECT_EQ(constructs.size(), 2u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,6) begin_id:5 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,6) begin_id:5 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [1,4) begin_id:10 end_id:99 depth:1 parent:Function@5 }
|
Construct{ IfSelection [1,4) begin_id:10 end_id:99 depth:1 parent:Function@5 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(5)->construct, constructs[0].get());
|
EXPECT_EQ(fe.GetBlockInfo(5)->construct, constructs[0].get());
|
||||||
|
@ -2938,7 +2938,7 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_SwitchSelection) {
|
||||||
EXPECT_EQ(constructs.size(), 2u);
|
EXPECT_EQ(constructs.size(), 2u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
Construct{ SwitchSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
||||||
|
@ -3070,7 +3070,7 @@ TEST_F(SpvParserTest,
|
||||||
// it.
|
// it.
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
|
Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
|
||||||
Construct{ Continue [2,3) begin_id:50 end_id:99 depth:1 parent:Function@10 in-c:Continue@50 }
|
Construct{ Continue [2,3) begin_id:50 end_id:99 depth:1 parent:Function@10 in-c:Continue@50 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
|
@ -3117,7 +3117,7 @@ TEST_F(SpvParserTest,
|
||||||
EXPECT_EQ(constructs.size(), 4u);
|
EXPECT_EQ(constructs.size(), 4u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
|
Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
|
||||||
Construct{ Continue [3,4) begin_id:60 end_id:99 depth:1 parent:Function@10 in-c:Continue@60 }
|
Construct{ Continue [3,4) begin_id:60 end_id:99 depth:1 parent:Function@10 in-c:Continue@60 }
|
||||||
Construct{ Loop [2,3) begin_id:50 end_id:60 depth:1 parent:Function@10 in-c-l:Loop@50 }
|
Construct{ Loop [2,3) begin_id:50 end_id:60 depth:1 parent:Function@10 in-c-l:Loop@50 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
|
@ -3176,9 +3176,9 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_Nest_If_If) {
|
||||||
EXPECT_EQ(constructs.size(), 4u);
|
EXPECT_EQ(constructs.size(), 4u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,9) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,9) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,8) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
Construct{ IfSelection [0,8) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
||||||
Construct{ Selection [1,3) begin_id:20 end_id:40 depth:2 parent:Selection@10 }
|
Construct{ IfSelection [1,3) begin_id:20 end_id:40 depth:2 parent:IfSelection@10 }
|
||||||
Construct{ Selection [5,7) begin_id:50 end_id:89 depth:2 parent:Selection@10 }
|
Construct{ IfSelection [5,7) begin_id:50 end_id:89 depth:2 parent:IfSelection@10 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
||||||
|
@ -3237,9 +3237,9 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_Nest_Switch_If) {
|
||||||
// The ordering among siblings depends on the computed block order.
|
// The ordering among siblings depends on the computed block order.
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,7) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
Construct{ SwitchSelection [0,7) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
||||||
Construct{ Selection [1,3) begin_id:50 end_id:89 depth:2 parent:Selection@10 }
|
Construct{ IfSelection [1,3) begin_id:50 end_id:89 depth:2 parent:SwitchSelection@10 }
|
||||||
Construct{ Selection [4,6) begin_id:20 end_id:49 depth:2 parent:Selection@10 }
|
Construct{ IfSelection [4,6) begin_id:20 end_id:49 depth:2 parent:SwitchSelection@10 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
||||||
|
@ -3286,8 +3286,8 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_Nest_If_Switch) {
|
||||||
EXPECT_EQ(constructs.size(), 3u);
|
EXPECT_EQ(constructs.size(), 3u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
Construct{ IfSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
||||||
Construct{ Selection [1,3) begin_id:20 end_id:89 depth:2 parent:Selection@10 }
|
Construct{ SwitchSelection [1,3) begin_id:20 end_id:89 depth:2 parent:IfSelection@10 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
||||||
|
@ -3397,7 +3397,7 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_Nest_Loop_If) {
|
||||||
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Continue [5,6) begin_id:80 end_id:99 depth:1 parent:Function@10 in-c:Continue@80 }
|
Construct{ Continue [5,6) begin_id:80 end_id:99 depth:1 parent:Function@10 in-c:Continue@80 }
|
||||||
Construct{ Loop [1,5) begin_id:20 end_id:80 depth:1 parent:Function@10 in-c-l:Loop@20 }
|
Construct{ Loop [1,5) begin_id:20 end_id:80 depth:1 parent:Function@10 in-c-l:Loop@20 }
|
||||||
Construct{ Selection [2,4) begin_id:30 end_id:49 depth:2 parent:Loop@20 in-c-l:Loop@20 }
|
Construct{ IfSelection [2,4) begin_id:30 end_id:49 depth:2 parent:Loop@20 in-c-l:Loop@20 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
|
||||||
|
@ -3448,7 +3448,7 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_Nest_LoopContinue_If) {
|
||||||
Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Continue [2,5) begin_id:30 end_id:99 depth:1 parent:Function@10 in-c:Continue@30 }
|
Construct{ Continue [2,5) begin_id:30 end_id:99 depth:1 parent:Function@10 in-c:Continue@30 }
|
||||||
Construct{ Loop [1,2) begin_id:20 end_id:30 depth:1 parent:Function@10 in-c-l:Loop@20 }
|
Construct{ Loop [1,2) begin_id:20 end_id:30 depth:1 parent:Function@10 in-c-l:Loop@20 }
|
||||||
Construct{ Selection [2,4) begin_id:30 end_id:49 depth:2 parent:Continue@30 in-c:Continue@30 }
|
Construct{ IfSelection [2,4) begin_id:30 end_id:49 depth:2 parent:Continue@30 in-c:Continue@30 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
|
||||||
|
@ -3490,8 +3490,8 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_Nest_If_SingleBlockLoop) {
|
||||||
EXPECT_EQ(constructs.size(), 3u);
|
EXPECT_EQ(constructs.size(), 3u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
||||||
Construct{ Continue [1,2) begin_id:20 end_id:89 depth:2 parent:Selection@10 in-c:Continue@20 }
|
Construct{ Continue [1,2) begin_id:20 end_id:89 depth:2 parent:IfSelection@10 in-c:Continue@20 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
||||||
|
@ -3539,9 +3539,9 @@ TEST_F(SpvParserTest, LabelControlFlowConstructs_Nest_If_MultiBlockLoop) {
|
||||||
EXPECT_EQ(constructs.size(), 4u);
|
EXPECT_EQ(constructs.size(), 4u);
|
||||||
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
|
||||||
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
|
Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
|
||||||
Construct{ Selection [0,6) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
Construct{ IfSelection [0,6) begin_id:10 end_id:99 depth:1 parent:Function@10 }
|
||||||
Construct{ Continue [3,5) begin_id:40 end_id:89 depth:2 parent:Selection@10 in-c:Continue@40 }
|
Construct{ Continue [3,5) begin_id:40 end_id:89 depth:2 parent:IfSelection@10 in-c:Continue@40 }
|
||||||
Construct{ Loop [1,3) begin_id:20 end_id:40 depth:2 parent:Selection@10 in-c-l:Loop@20 }
|
Construct{ Loop [1,3) begin_id:20 end_id:40 depth:2 parent:IfSelection@10 in-c-l:Loop@20 }
|
||||||
})")) << constructs;
|
})")) << constructs;
|
||||||
// The block records the nearest enclosing construct.
|
// The block records the nearest enclosing construct.
|
||||||
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
|
||||||
|
|
Loading…
Reference in New Issue