[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:
Ben Clayton 2023-05-17 10:40:41 +00:00 committed by Dawn LUCI CQ
parent 0b9cb101bf
commit 1ea1e1a375
2 changed files with 137 additions and 33 deletions

View File

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

View File

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