[tint][ir][ToProgram] Begin flow node traversal
Traverse the block nodes, and if statements. Bug: tint:1902 Change-Id: Ie5533acdc65378bfea91b46a62090c4d3216b303 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/133100 Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Ben Clayton <bclayton@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
0b9cb101bf
commit
1ea1e1a375
|
@ -19,6 +19,7 @@
|
|||
#include "src/tint/ir/block.h"
|
||||
#include "src/tint/ir/call.h"
|
||||
#include "src/tint/ir/constant.h"
|
||||
#include "src/tint/ir/function_terminator.h"
|
||||
#include "src/tint/ir/if.h"
|
||||
#include "src/tint/ir/instruction.h"
|
||||
#include "src/tint/ir/module.h"
|
||||
|
@ -67,55 +68,75 @@ class State {
|
|||
// TODO(crbug.com/tint/1915): Properly implement this when we've fleshed out Function
|
||||
utils::Vector<const ast::Parameter*, 1> params{};
|
||||
ast::Type ret_ty;
|
||||
auto* body = Block(fn->start_target);
|
||||
auto* body = FlowNodeGraph(fn->start_target, fn->end_target);
|
||||
utils::Vector<const ast::Attribute*, 1> attrs{};
|
||||
utils::Vector<const ast::Attribute*, 1> ret_attrs{};
|
||||
b.Func(name, std::move(params), ret_ty, body, std::move(attrs), std::move(ret_attrs));
|
||||
}
|
||||
|
||||
const ast::BlockStatement* Block(const ir::Block* block) {
|
||||
const ast::BlockStatement* FlowNodeGraph(const ir::FlowNode* node,
|
||||
const ir::FlowNode* stop_at) {
|
||||
// TODO(crbug.com/tint/1902): Check if the block is dead
|
||||
utils::Vector<const ast::Statement*, decltype(ir::Block::instructions)::static_length>
|
||||
utils::Vector<const ast::Statement*,
|
||||
decltype(ast::BlockStatement::statements)::static_length>
|
||||
stmts;
|
||||
for (auto* inst : block->instructions) {
|
||||
auto* stmt = Stmt(inst);
|
||||
if (!stmt) {
|
||||
while (node != stop_at) {
|
||||
if (!node) {
|
||||
return nullptr;
|
||||
}
|
||||
stmts.Push(stmt);
|
||||
node = Switch(
|
||||
node, //
|
||||
[&](const ir::Block* block) -> const ir::FlowNode* {
|
||||
for (auto* inst : block->instructions) {
|
||||
if (auto* stmt = Stmt(inst); TINT_LIKELY(stmt)) {
|
||||
stmts.Push(stmt);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return block->branch.target;
|
||||
},
|
||||
[&](const ir::If* if_) -> const ir::FlowNode* {
|
||||
if (auto* stmt = If(if_); TINT_LIKELY(stmt)) {
|
||||
stmts.Push(stmt);
|
||||
return if_->merge.target;
|
||||
}
|
||||
return nullptr;
|
||||
},
|
||||
[&](Default) {
|
||||
TINT_UNIMPLEMENTED(IR, b.Diagnostics())
|
||||
<< "unhandled case in Switch(): " << node->TypeInfo().name;
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
return b.Block(std::move(stmts));
|
||||
}
|
||||
|
||||
const ast::Statement* FlowNode(const ir::FlowNode* node) {
|
||||
// TODO(crbug.com/tint/1902): Check the node is connected
|
||||
return Switch(
|
||||
node, //
|
||||
[&](const ir::If* i) {
|
||||
auto* cond = Expr(i->condition);
|
||||
auto* t = Branch(i->true_);
|
||||
if (auto* f = Branch(i->false_)) {
|
||||
return b.If(cond, t, b.Else(f));
|
||||
}
|
||||
// TODO(crbug.com/tint/1902): Emit merge block
|
||||
return b.If(cond, t);
|
||||
},
|
||||
[&](Default) {
|
||||
TINT_UNIMPLEMENTED(IR, b.Diagnostics())
|
||||
<< "unhandled case in Switch(): " << node->TypeInfo().name;
|
||||
return nullptr;
|
||||
});
|
||||
const ast::IfStatement* If(const ir::If* i) {
|
||||
auto* cond = Expr(i->condition);
|
||||
auto* t = FlowNodeGraph(i->true_.target, i->merge.target);
|
||||
if (!IsEmpty(i->false_.target, i->merge.target)) {
|
||||
// TODO(crbug.com/tint/1902): Merge if else
|
||||
auto* f = FlowNodeGraph(i->false_.target, i->merge.target);
|
||||
return b.If(cond, t, b.Else(f));
|
||||
}
|
||||
return b.If(cond, t);
|
||||
}
|
||||
|
||||
const ast::BlockStatement* Branch(const ir::Branch& branch) {
|
||||
auto* stmt = FlowNode(branch.target);
|
||||
if (!stmt) {
|
||||
return nullptr;
|
||||
/// @return true if there are no instructions between @p node and and @p stop_at
|
||||
bool IsEmpty(const ir::FlowNode* node, const ir::FlowNode* stop_at) {
|
||||
while (node != stop_at) {
|
||||
if (auto* block = node->As<ir::Block>()) {
|
||||
if (block->instructions.Length() > 0) {
|
||||
return false;
|
||||
}
|
||||
node = block->branch.target;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (auto* block = stmt->As<ast::BlockStatement>()) {
|
||||
return block;
|
||||
}
|
||||
return b.Block(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
const ast::Statement* Stmt(const ir::Instruction* inst) {
|
||||
|
|
|
@ -67,6 +67,9 @@ fn f() {
|
|||
)");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Function-scope var
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
TEST_F(IRToProgramRoundtripTest, FunctionScopeVar_i32) {
|
||||
Test(R"(
|
||||
fn f() {
|
||||
|
@ -93,5 +96,85 @@ fn f() {
|
|||
)");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// If
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
TEST_F(IRToProgramRoundtripTest, If_CallFn) {
|
||||
Test(R"(
|
||||
fn a() {
|
||||
}
|
||||
|
||||
fn f() {
|
||||
var cond : bool = true;
|
||||
if (cond) {
|
||||
a();
|
||||
}
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(IRToProgramRoundtripTest, If_CallFn_Else_CallFn) {
|
||||
Test(R"(
|
||||
fn a() {
|
||||
}
|
||||
|
||||
fn b() {
|
||||
}
|
||||
|
||||
fn f() {
|
||||
var cond : bool = true;
|
||||
if (cond) {
|
||||
a();
|
||||
} else {
|
||||
b();
|
||||
}
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_F(IRToProgramRoundtripTest, If_CallFn_ElseIf_CallFn) {
|
||||
Test(R"(
|
||||
fn a() {
|
||||
}
|
||||
|
||||
fn b() {
|
||||
}
|
||||
|
||||
fn c() {
|
||||
}
|
||||
|
||||
fn f() {
|
||||
var cond_a : bool = true;
|
||||
var cond_b : bool = true;
|
||||
if (cond_a) {
|
||||
a();
|
||||
} else if (cond_b) {
|
||||
b();
|
||||
}
|
||||
}
|
||||
)",
|
||||
R"(
|
||||
fn a() {
|
||||
}
|
||||
|
||||
fn b() {
|
||||
}
|
||||
|
||||
fn c() {
|
||||
}
|
||||
|
||||
fn f() {
|
||||
var cond_a : bool = true;
|
||||
var cond_b : bool = true;
|
||||
if (cond_a) {
|
||||
a();
|
||||
} else {
|
||||
if (cond_b) {
|
||||
b();
|
||||
}
|
||||
}
|
||||
}
|
||||
)");
|
||||
}
|
||||
} // namespace
|
||||
} // namespace tint::ir
|
||||
|
|
Loading…
Reference in New Issue