[tint][ir] Shuffle and refactor from_program.cc

Change-Id: Ibbeceb2410e7b3598fd9a92f3871603ee26b69b2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/132961
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2023-05-16 12:31:46 +00:00 committed by Dawn LUCI CQ
parent 8d98977a30
commit 34c794e2e9
1 changed files with 194 additions and 177 deletions

View File

@ -88,7 +88,7 @@ namespace tint::ir {
namespace { namespace {
using ResultType = utils::Result<Module>; using ResultType = utils::Result<Module, diag::List>;
bool IsBranched(const Block* b) { bool IsBranched(const Block* b) {
return b->branch.target != nullptr; return b->branch.target != nullptr;
@ -109,74 +109,51 @@ bool IsConnected(const FlowNode* b) {
return false; return false;
} }
/// Impl is the private-implementation of FromProgram().
class Impl { class Impl {
public: public:
explicit Impl(const Program* program) /// Constructor
: program_(program), /// @param program the program to convert to IR
clone_ctx_{ explicit Impl(const Program* program) : program_(program) {}
type::CloneContext{{&program->Symbols()}, {&builder.ir.symbols, &builder.ir.types}},
{&builder.ir.constants}} {}
ResultType Build() { /// Builds an IR module from the program passed to the constructor.
auto* sem = program_->Sem().Module(); /// @return the IR module or an error.
ResultType Build() { return EmitModule(); }
for (auto* decl : sem->DependencyOrderedDeclarations()) {
tint::Switch(
decl, //
[&](const ast::Struct*) {
// Will be encoded into the `type::Struct` when used. We will then hoist all
// used structs up to module scope when converting IR.
},
[&](const ast::Alias*) {
// Folded away and doesn't appear in the IR.
},
[&](const ast::Variable* var) {
// Setup the current flow node to be the root block for the module. The builder
// will handle creating it if it doesn't exist already.
TINT_SCOPED_ASSIGNMENT(current_flow_block, builder.CreateRootBlockIfNeeded());
EmitVariable(var);
},
[&](const ast::Function* func) { EmitFunction(func); },
[&](const ast::Enable*) {
// TODO(dsinclair): Implement? I think these need to be passed along so further
// stages know what is enabled.
},
[&](const ast::ConstAssert*) {
// Evaluated by the resolver, drop from the IR.
},
[&](Default) {
add_error(decl->source, "unknown type: " + std::string(decl->TypeInfo().name));
});
}
if (!diagnostics_.empty()) {
return utils::Failure;
}
return ResultType{std::move(mod)};
}
/// @returns the diagnostics
diag::List Diagnostics() const { return diagnostics_; }
private: private:
enum class ControlFlags { kNone, kExcludeSwitch }; enum class ControlFlags { kNone, kExcludeSwitch };
/// The stack of flow control blocks. // The input Program
utils::Vector<FlowNode*, 8> flow_stack; const Program* program_ = nullptr;
/// The IR module being built /// The IR module being built
Module mod; Module mod;
/// The IR builder being used by the impl. /// The IR builder being used by the impl.
Builder builder{mod}; Builder builder_{mod};
/// The current flow block for expressions // The clone context used to clone data from #program_
Block* current_flow_block = nullptr; constant::CloneContext clone_ctx_{
/* type_ctx */ type::CloneContext{
/* src */ {&program_->Symbols()},
/* dst */ {&builder_.ir.symbols, &builder_.ir.types},
},
/* dst */ {&builder_.ir.constants},
};
const Program* program_ = nullptr; /// The stack of flow control blocks.
utils::Vector<FlowNode*, 8> flow_stack_;
/// The current flow block for expressions.
Block* current_flow_block_ = nullptr;
/// The current function being processed.
Function* current_function_ = nullptr; Function* current_function_ = nullptr;
/// The current stack of scopes being processed.
ScopeStack<Symbol, Value*> scopes_; ScopeStack<Symbol, Value*> scopes_;
constant::CloneContext clone_ctx_;
/// The diagnostic that have been raised.
diag::List diagnostics_; diag::List diagnostics_;
/// Map from ast nodes to flow nodes, used to retrieve the flow node for a given AST node. /// Map from ast nodes to flow nodes, used to retrieve the flow node for a given AST node.
@ -185,9 +162,9 @@ class Impl {
class FlowStackScope { class FlowStackScope {
public: public:
FlowStackScope(Impl* impl, FlowNode* node) : impl_(impl) { impl_->flow_stack.Push(node); } FlowStackScope(Impl* impl, FlowNode* node) : impl_(impl) { impl_->flow_stack_.Push(node); }
~FlowStackScope() { impl_->flow_stack.Pop(); } ~FlowStackScope() { impl_->flow_stack_.Pop(); }
private: private:
Impl* impl_; Impl* impl_;
@ -198,22 +175,22 @@ class Impl {
} }
void BranchTo(FlowNode* node, utils::VectorRef<Value*> args = {}) { void BranchTo(FlowNode* node, utils::VectorRef<Value*> args = {}) {
TINT_ASSERT(IR, current_flow_block); TINT_ASSERT(IR, current_flow_block_);
TINT_ASSERT(IR, !IsBranched(current_flow_block)); TINT_ASSERT(IR, !IsBranched(current_flow_block_));
builder.Branch(current_flow_block, node, args); builder_.Branch(current_flow_block_, node, args);
current_flow_block = nullptr; current_flow_block_ = nullptr;
} }
void BranchToIfNeeded(FlowNode* node) { void BranchToIfNeeded(FlowNode* node) {
if (!current_flow_block || IsBranched(current_flow_block)) { if (!current_flow_block_ || IsBranched(current_flow_block_)) {
return; return;
} }
BranchTo(node); BranchTo(node);
} }
FlowNode* FindEnclosingControl(ControlFlags flags) { FlowNode* FindEnclosingControl(ControlFlags flags) {
for (auto it = flow_stack.rbegin(); it != flow_stack.rend(); ++it) { for (auto it = flow_stack_.rbegin(); it != flow_stack_.rend(); ++it) {
if ((*it)->Is<Loop>()) { if ((*it)->Is<Loop>()) {
return *it; return *it;
} }
@ -231,21 +208,60 @@ class Impl {
return clone_ctx_.type_ctx.dst.st->Register(sym.Name()); return clone_ctx_.type_ctx.dst.st->Register(sym.Name());
} }
ResultType EmitModule() {
auto* sem = program_->Sem().Module();
for (auto* decl : sem->DependencyOrderedDeclarations()) {
tint::Switch(
decl, //
[&](const ast::Struct*) {
// Will be encoded into the `type::Struct` when used. We will then hoist all
// used structs up to module scope when converting IR.
},
[&](const ast::Alias*) {
// Folded away and doesn't appear in the IR.
},
[&](const ast::Variable* var) {
// Setup the current flow node to be the root block for the module. The builder
// will handle creating it if it doesn't exist already.
TINT_SCOPED_ASSIGNMENT(current_flow_block_, builder_.CreateRootBlockIfNeeded());
EmitVariable(var);
},
[&](const ast::Function* func) { EmitFunction(func); },
[&](const ast::Enable*) {
// TODO(dsinclair): Implement? I think these need to be passed along so further
// stages know what is enabled.
},
[&](const ast::ConstAssert*) {
// Evaluated by the resolver, drop from the IR.
},
[&](Default) {
add_error(decl->source, "unknown type: " + std::string(decl->TypeInfo().name));
});
}
if (diagnostics_.contains_errors()) {
return ResultType(std::move(diagnostics_));
}
return ResultType{std::move(mod)};
}
void EmitFunction(const ast::Function* ast_func) { void EmitFunction(const ast::Function* ast_func) {
// The flow stack should have been emptied when the previous function finished building. // The flow stack should have been emptied when the previous function finished building.
TINT_ASSERT(IR, flow_stack.IsEmpty()); TINT_ASSERT(IR, flow_stack_.IsEmpty());
const auto* sem = program_->Sem().Get(ast_func); const auto* sem = program_->Sem().Get(ast_func);
auto* ir_func = builder.CreateFunction(CloneSymbol(ast_func->name->symbol), auto* ir_func = builder_.CreateFunction(CloneSymbol(ast_func->name->symbol),
sem->ReturnType()->Clone(clone_ctx_.type_ctx)); sem->ReturnType()->Clone(clone_ctx_.type_ctx));
current_function_ = ir_func; current_function_ = ir_func;
builder.ir.functions.Push(ir_func); builder_.ir.functions.Push(ir_func);
ast_to_flow_[ast_func] = ir_func; ast_to_flow_[ast_func] = ir_func;
if (ast_func->IsEntryPoint()) { if (ast_func->IsEntryPoint()) {
builder.ir.entry_points.Push(ir_func); builder_.ir.entry_points.Push(ir_func);
switch (ast_func->PipelineStage()) { switch (ast_func->PipelineStage()) {
case ast::PipelineStage::kVertex: case ast::PipelineStage::kVertex:
@ -316,7 +332,7 @@ class Impl {
{ {
FlowStackScope scope(this, ir_func); FlowStackScope scope(this, ir_func);
current_flow_block = ir_func->start_target; current_flow_block_ = ir_func->start_target;
EmitBlock(ast_func->body); EmitBlock(ast_func->body);
// TODO(dsinclair): Store return type and attributes // TODO(dsinclair): Store return type and attributes
@ -327,8 +343,8 @@ class Impl {
BranchToIfNeeded(current_function_->end_target); BranchToIfNeeded(current_function_->end_target);
} }
TINT_ASSERT(IR, flow_stack.IsEmpty()); TINT_ASSERT(IR, flow_stack_.IsEmpty());
current_flow_block = nullptr; current_flow_block_ = nullptr;
current_function_ = nullptr; current_function_ = nullptr;
} }
@ -338,7 +354,7 @@ class Impl {
// If the current flow block has a branch target then the rest of the statements in this // If the current flow block has a branch target then the rest of the statements in this
// block are dead code. Skip them. // block are dead code. Skip them.
if (!current_flow_block || IsBranched(current_flow_block)) { if (!current_flow_block_ || IsBranched(current_flow_block_)) {
break; break;
} }
} }
@ -381,8 +397,8 @@ class Impl {
if (!rhs) { if (!rhs) {
return; return;
} }
auto store = builder.Store(lhs.Get(), rhs.Get()); auto store = builder_.Store(lhs.Get(), rhs.Get());
current_flow_block->instructions.Push(store); current_flow_block_->instructions.Push(store);
} }
void EmitCompoundAssignment(const ast::CompoundAssignmentStatement* stmt) { void EmitCompoundAssignment(const ast::CompoundAssignmentStatement* stmt) {
@ -400,34 +416,34 @@ class Impl {
Binary* inst = nullptr; Binary* inst = nullptr;
switch (stmt->op) { switch (stmt->op) {
case ast::BinaryOp::kAnd: case ast::BinaryOp::kAnd:
inst = builder.And(ty, lhs.Get(), rhs.Get()); inst = builder_.And(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kOr: case ast::BinaryOp::kOr:
inst = builder.Or(ty, lhs.Get(), rhs.Get()); inst = builder_.Or(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kXor: case ast::BinaryOp::kXor:
inst = builder.Xor(ty, lhs.Get(), rhs.Get()); inst = builder_.Xor(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kShiftLeft: case ast::BinaryOp::kShiftLeft:
inst = builder.ShiftLeft(ty, lhs.Get(), rhs.Get()); inst = builder_.ShiftLeft(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kShiftRight: case ast::BinaryOp::kShiftRight:
inst = builder.ShiftRight(ty, lhs.Get(), rhs.Get()); inst = builder_.ShiftRight(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kAdd: case ast::BinaryOp::kAdd:
inst = builder.Add(ty, lhs.Get(), rhs.Get()); inst = builder_.Add(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kSubtract: case ast::BinaryOp::kSubtract:
inst = builder.Subtract(ty, lhs.Get(), rhs.Get()); inst = builder_.Subtract(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kMultiply: case ast::BinaryOp::kMultiply:
inst = builder.Multiply(ty, lhs.Get(), rhs.Get()); inst = builder_.Multiply(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kDivide: case ast::BinaryOp::kDivide:
inst = builder.Divide(ty, lhs.Get(), rhs.Get()); inst = builder_.Divide(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kModulo: case ast::BinaryOp::kModulo:
inst = builder.Modulo(ty, lhs.Get(), rhs.Get()); inst = builder_.Modulo(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kLessThanEqual: case ast::BinaryOp::kLessThanEqual:
case ast::BinaryOp::kGreaterThanEqual: case ast::BinaryOp::kGreaterThanEqual:
@ -443,10 +459,10 @@ class Impl {
TINT_ICE(IR, diagnostics_) << "missing binary operand type"; TINT_ICE(IR, diagnostics_) << "missing binary operand type";
return; return;
} }
current_flow_block->instructions.Push(inst); current_flow_block_->instructions.Push(inst);
auto store = builder.Store(lhs.Get(), inst); auto store = builder_.Store(lhs.Get(), inst);
current_flow_block->instructions.Push(store); current_flow_block_->instructions.Push(store);
} }
void EmitBlock(const ast::BlockStatement* block) { void EmitBlock(const ast::BlockStatement* block) {
@ -465,7 +481,7 @@ class Impl {
if (!reg) { if (!reg) {
return; return;
} }
auto* if_node = builder.CreateIf(reg.Get()); auto* if_node = builder_.CreateIf(reg.Get());
BranchTo(if_node); BranchTo(if_node);
@ -474,13 +490,13 @@ class Impl {
{ {
FlowStackScope scope(this, if_node); FlowStackScope scope(this, if_node);
current_flow_block = if_node->true_.target->As<Block>(); current_flow_block_ = if_node->true_.target->As<Block>();
EmitBlock(stmt->body); EmitBlock(stmt->body);
// If the true branch did not execute control flow, then go to the merge target // If the true branch did not execute control flow, then go to the merge target
BranchToIfNeeded(if_node->merge.target); BranchToIfNeeded(if_node->merge.target);
current_flow_block = if_node->false_.target->As<Block>(); current_flow_block_ = if_node->false_.target->As<Block>();
if (stmt->else_statement) { if (stmt->else_statement) {
EmitStatement(stmt->else_statement); EmitStatement(stmt->else_statement);
} }
@ -488,18 +504,18 @@ class Impl {
// If the false branch did not execute control flow, then go to the merge target // If the false branch did not execute control flow, then go to the merge target
BranchToIfNeeded(if_node->merge.target); BranchToIfNeeded(if_node->merge.target);
} }
current_flow_block = nullptr; current_flow_block_ = nullptr;
// If both branches went somewhere, then they both returned, continued or broke. So, there // If both branches went somewhere, then they both returned, continued or broke. So, there
// is no need for the if merge-block and there is nothing to branch to the merge block // is no need for the if merge-block and there is nothing to branch to the merge block
// anyway. // anyway.
if (IsConnected(if_node->merge.target)) { if (IsConnected(if_node->merge.target)) {
current_flow_block = if_node->merge.target->As<Block>(); current_flow_block_ = if_node->merge.target->As<Block>();
} }
} }
void EmitLoop(const ast::LoopStatement* stmt) { void EmitLoop(const ast::LoopStatement* stmt) {
auto* loop_node = builder.CreateLoop(); auto* loop_node = builder_.CreateLoop();
BranchTo(loop_node); BranchTo(loop_node);
@ -508,13 +524,13 @@ class Impl {
{ {
FlowStackScope scope(this, loop_node); FlowStackScope scope(this, loop_node);
current_flow_block = loop_node->start.target->As<Block>(); current_flow_block_ = loop_node->start.target->As<Block>();
EmitBlock(stmt->body); EmitBlock(stmt->body);
// The current block didn't `break`, `return` or `continue`, go to the continuing block. // The current block didn't `break`, `return` or `continue`, go to the continuing block.
BranchToIfNeeded(loop_node->continuing.target); BranchToIfNeeded(loop_node->continuing.target);
current_flow_block = loop_node->continuing.target->As<Block>(); current_flow_block_ = loop_node->continuing.target->As<Block>();
if (stmt->continuing) { if (stmt->continuing) {
EmitBlock(stmt->continuing); EmitBlock(stmt->continuing);
} }
@ -525,17 +541,17 @@ class Impl {
// The loop merge can get disconnected if the loop returns directly, or the continuing // The loop merge can get disconnected if the loop returns directly, or the continuing
// target branches, eventually, to the merge, but nothing branched to the continuing target. // target branches, eventually, to the merge, but nothing branched to the continuing target.
current_flow_block = loop_node->merge.target->As<Block>(); current_flow_block_ = loop_node->merge.target->As<Block>();
if (!IsConnected(loop_node->merge.target)) { if (!IsConnected(loop_node->merge.target)) {
current_flow_block = nullptr; current_flow_block_ = nullptr;
} }
} }
void EmitWhile(const ast::WhileStatement* stmt) { void EmitWhile(const ast::WhileStatement* stmt) {
auto* loop_node = builder.CreateLoop(); auto* loop_node = builder_.CreateLoop();
// Continue is always empty, just go back to the start // Continue is always empty, just go back to the start
TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>()); TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>());
builder.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target, builder_.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
utils::Empty); utils::Empty);
BranchTo(loop_node); BranchTo(loop_node);
@ -545,7 +561,7 @@ class Impl {
{ {
FlowStackScope scope(this, loop_node); FlowStackScope scope(this, loop_node);
current_flow_block = loop_node->start.target->As<Block>(); current_flow_block_ = loop_node->start.target->As<Block>();
// Emit the while condition into the start target of the loop // Emit the while condition into the start target of the loop
auto reg = EmitExpression(stmt->condition); auto reg = EmitExpression(stmt->condition);
@ -554,30 +570,31 @@ class Impl {
} }
// Create an `if (cond) {} else {break;}` control flow // Create an `if (cond) {} else {break;}` control flow
auto* if_node = builder.CreateIf(reg.Get()); auto* if_node = builder_.CreateIf(reg.Get());
TINT_ASSERT(IR, if_node->true_.target->Is<Block>()); TINT_ASSERT(IR, if_node->true_.target->Is<Block>());
builder.Branch(if_node->true_.target->As<Block>(), if_node->merge.target, utils::Empty); builder_.Branch(if_node->true_.target->As<Block>(), if_node->merge.target,
utils::Empty);
TINT_ASSERT(IR, if_node->false_.target->Is<Block>()); TINT_ASSERT(IR, if_node->false_.target->Is<Block>());
builder.Branch(if_node->false_.target->As<Block>(), loop_node->merge.target, builder_.Branch(if_node->false_.target->As<Block>(), loop_node->merge.target,
utils::Empty); utils::Empty);
BranchTo(if_node); BranchTo(if_node);
current_flow_block = if_node->merge.target->As<Block>(); current_flow_block_ = if_node->merge.target->As<Block>();
EmitBlock(stmt->body); EmitBlock(stmt->body);
BranchToIfNeeded(loop_node->continuing.target); BranchToIfNeeded(loop_node->continuing.target);
} }
// The while loop always has a path to the merge target as the break statement comes before // The while loop always has a path to the merge target as the break statement comes before
// anything inside the loop. // anything inside the loop.
current_flow_block = loop_node->merge.target->As<Block>(); current_flow_block_ = loop_node->merge.target->As<Block>();
} }
void EmitForLoop(const ast::ForLoopStatement* stmt) { void EmitForLoop(const ast::ForLoopStatement* stmt) {
auto* loop_node = builder.CreateLoop(); auto* loop_node = builder_.CreateLoop();
TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>()); TINT_ASSERT(IR, loop_node->continuing.target->Is<Block>());
builder.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target, builder_.Branch(loop_node->continuing.target->As<Block>(), loop_node->start.target,
utils::Empty); utils::Empty);
// Make sure the initializer ends up in a contained scope // Make sure the initializer ends up in a contained scope
@ -596,7 +613,7 @@ class Impl {
{ {
FlowStackScope scope(this, loop_node); FlowStackScope scope(this, loop_node);
current_flow_block = loop_node->start.target->As<Block>(); current_flow_block_ = loop_node->start.target->As<Block>();
if (stmt->condition) { if (stmt->condition) {
// Emit the condition into the target target of the loop // Emit the condition into the target target of the loop
@ -606,31 +623,31 @@ class Impl {
} }
// Create an `if (cond) {} else {break;}` control flow // Create an `if (cond) {} else {break;}` control flow
auto* if_node = builder.CreateIf(reg.Get()); auto* if_node = builder_.CreateIf(reg.Get());
TINT_ASSERT(IR, if_node->true_.target->Is<Block>()); TINT_ASSERT(IR, if_node->true_.target->Is<Block>());
builder.Branch(if_node->true_.target->As<Block>(), if_node->merge.target, builder_.Branch(if_node->true_.target->As<Block>(), if_node->merge.target,
utils::Empty); utils::Empty);
TINT_ASSERT(IR, if_node->false_.target->Is<Block>()); TINT_ASSERT(IR, if_node->false_.target->Is<Block>());
builder.Branch(if_node->false_.target->As<Block>(), loop_node->merge.target, builder_.Branch(if_node->false_.target->As<Block>(), loop_node->merge.target,
utils::Empty); utils::Empty);
BranchTo(if_node); BranchTo(if_node);
current_flow_block = if_node->merge.target->As<Block>(); current_flow_block_ = if_node->merge.target->As<Block>();
} }
EmitBlock(stmt->body); EmitBlock(stmt->body);
BranchToIfNeeded(loop_node->continuing.target); BranchToIfNeeded(loop_node->continuing.target);
if (stmt->continuing) { if (stmt->continuing) {
current_flow_block = loop_node->continuing.target->As<Block>(); current_flow_block_ = loop_node->continuing.target->As<Block>();
EmitStatement(stmt->continuing); EmitStatement(stmt->continuing);
} }
} }
// The while loop always has a path to the merge target as the break statement comes before // The while loop always has a path to the merge target as the break statement comes before
// anything inside the loop. // anything inside the loop.
current_flow_block = loop_node->merge.target->As<Block>(); current_flow_block_ = loop_node->merge.target->As<Block>();
} }
void EmitSwitch(const ast::SwitchStatement* stmt) { void EmitSwitch(const ast::SwitchStatement* stmt) {
@ -639,7 +656,7 @@ class Impl {
if (!reg) { if (!reg) {
return; return;
} }
auto* switch_node = builder.CreateSwitch(reg.Get()); auto* switch_node = builder_.CreateSwitch(reg.Get());
BranchTo(switch_node); BranchTo(switch_node);
@ -655,20 +672,20 @@ class Impl {
if (selector->IsDefault()) { if (selector->IsDefault()) {
selectors.Push({nullptr}); selectors.Push({nullptr});
} else { } else {
selectors.Push({builder.Constant(selector->Value()->Clone(clone_ctx_))}); selectors.Push({builder_.Constant(selector->Value()->Clone(clone_ctx_))});
} }
} }
current_flow_block = builder.CreateCase(switch_node, selectors); current_flow_block_ = builder_.CreateCase(switch_node, selectors);
EmitBlock(c->Body()->Declaration()); EmitBlock(c->Body()->Declaration());
BranchToIfNeeded(switch_node->merge.target); BranchToIfNeeded(switch_node->merge.target);
} }
} }
current_flow_block = nullptr; current_flow_block_ = nullptr;
if (IsConnected(switch_node->merge.target)) { if (IsConnected(switch_node->merge.target)) {
current_flow_block = switch_node->merge.target->As<Block>(); current_flow_block_ = switch_node->merge.target->As<Block>();
} }
} }
@ -714,8 +731,8 @@ class Impl {
// terminating discard that would probably make sense as a FlowNode but would then require // terminating discard that would probably make sense as a FlowNode but would then require
// figuring out the multi-level exit that is triggered. // figuring out the multi-level exit that is triggered.
void EmitDiscard(const ast::DiscardStatement*) { void EmitDiscard(const ast::DiscardStatement*) {
auto* inst = builder.Discard(); auto* inst = builder_.Discard();
current_flow_block->instructions.Push(inst); current_flow_block_->instructions.Push(inst);
} }
void EmitBreakIf(const ast::BreakIfStatement* stmt) { void EmitBreakIf(const ast::BreakIfStatement* stmt) {
@ -724,7 +741,7 @@ class Impl {
if (!reg) { if (!reg) {
return; return;
} }
auto* if_node = builder.CreateIf(reg.Get()); auto* if_node = builder_.CreateIf(reg.Get());
BranchTo(if_node); BranchTo(if_node);
@ -736,13 +753,13 @@ class Impl {
auto* loop = current_control->As<Loop>(); auto* loop = current_control->As<Loop>();
current_flow_block = if_node->true_.target->As<Block>(); current_flow_block_ = if_node->true_.target->As<Block>();
BranchTo(loop->merge.target); BranchTo(loop->merge.target);
current_flow_block = if_node->false_.target->As<Block>(); current_flow_block_ = if_node->false_.target->As<Block>();
BranchTo(if_node->merge.target); BranchTo(if_node->merge.target);
current_flow_block = if_node->merge.target->As<Block>(); current_flow_block_ = if_node->merge.target->As<Block>();
// The `break-if` has to be the last item in the continuing block. The false branch of the // The `break-if` has to be the last item in the continuing block. The false branch of the
// `break-if` will always take us back to the start of the loop. // `break-if` will always take us back to the start of the loop.
@ -754,7 +771,7 @@ class Impl {
if (auto* sem = program_->Sem().Get(expr)->As<sem::ValueExpression>()) { if (auto* sem = program_->Sem().Get(expr)->As<sem::ValueExpression>()) {
if (auto* v = sem->ConstantValue()) { if (auto* v = sem->ConstantValue()) {
if (auto* cv = v->Clone(clone_ctx_)) { if (auto* cv = v->Clone(clone_ctx_)) {
return builder.Constant(cv); return builder_.Constant(cv);
} }
} }
} }
@ -793,8 +810,8 @@ class Impl {
var, var,
[&](const ast::Var* v) { [&](const ast::Var* v) {
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx); auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
auto* val = builder.Declare(ty, sem->AddressSpace(), sem->Access()); auto* val = builder_.Declare(ty, sem->AddressSpace(), sem->Access());
current_flow_block->instructions.Push(val); current_flow_block_->instructions.Push(val);
if (v->initializer) { if (v->initializer) {
auto init = EmitExpression(v->initializer); auto init = EmitExpression(v->initializer);
@ -807,7 +824,7 @@ class Impl {
scopes_.Set(v->name->symbol, val); scopes_.Set(v->name->symbol, val);
// Record the original name of the var // Record the original name of the var
builder.ir.SetName(val, v->name->symbol.Name()); builder_.ir.SetName(val, v->name->symbol.Name());
}, },
[&](const ast::Let* l) { [&](const ast::Let* l) {
// A `let` doesn't exist as a standalone item in the IR, it's just the result of the // A `let` doesn't exist as a standalone item in the IR, it's just the result of the
@ -821,7 +838,7 @@ class Impl {
scopes_.Set(l->name->symbol, init.Get()); scopes_.Set(l->name->symbol, init.Get());
// Record the original name of the let // Record the original name of the let
builder.ir.SetName(init.Get(), l->name->symbol.Name()); builder_.ir.SetName(init.Get(), l->name->symbol.Name());
}, },
[&](const ast::Override*) { [&](const ast::Override*) {
add_error(var->source, add_error(var->source,
@ -854,23 +871,23 @@ class Impl {
Instruction* inst = nullptr; Instruction* inst = nullptr;
switch (expr->op) { switch (expr->op) {
case ast::UnaryOp::kAddressOf: case ast::UnaryOp::kAddressOf:
inst = builder.AddressOf(ty, val.Get()); inst = builder_.AddressOf(ty, val.Get());
break; break;
case ast::UnaryOp::kComplement: case ast::UnaryOp::kComplement:
inst = builder.Complement(ty, val.Get()); inst = builder_.Complement(ty, val.Get());
break; break;
case ast::UnaryOp::kIndirection: case ast::UnaryOp::kIndirection:
inst = builder.Indirection(ty, val.Get()); inst = builder_.Indirection(ty, val.Get());
break; break;
case ast::UnaryOp::kNegation: case ast::UnaryOp::kNegation:
inst = builder.Negation(ty, val.Get()); inst = builder_.Negation(ty, val.Get());
break; break;
case ast::UnaryOp::kNot: case ast::UnaryOp::kNot:
inst = builder.Not(ty, val.Get()); inst = builder_.Not(ty, val.Get());
break; break;
} }
current_flow_block->instructions.Push(inst); current_flow_block_->instructions.Push(inst);
return inst; return inst;
} }
@ -894,15 +911,15 @@ class Impl {
} }
// Generate a variable to store the short-circut into // Generate a variable to store the short-circut into
auto* ty = builder.ir.types.Get<type::Bool>(); auto* ty = builder_.ir.types.Get<type::Bool>();
auto* result_var = auto* result_var =
builder.Declare(ty, builtin::AddressSpace::kFunction, builtin::Access::kReadWrite); builder_.Declare(ty, builtin::AddressSpace::kFunction, builtin::Access::kReadWrite);
current_flow_block->instructions.Push(result_var); current_flow_block_->instructions.Push(result_var);
auto* lhs_store = builder.Store(result_var, lhs.Get()); auto* lhs_store = builder_.Store(result_var, lhs.Get());
current_flow_block->instructions.Push(lhs_store); current_flow_block_->instructions.Push(lhs_store);
auto* if_node = builder.CreateIf(lhs.Get()); auto* if_node = builder_.CreateIf(lhs.Get());
BranchTo(if_node); BranchTo(if_node);
utils::Result<Value*> rhs; utils::Result<Value*> rhs;
@ -912,21 +929,21 @@ class Impl {
// If this is an `&&` then we only evaluate the RHS expression in the true block. // If this is an `&&` then we only evaluate the RHS expression in the true block.
// If this is an `||` then we only evaluate the RHS expression in the false block. // If this is an `||` then we only evaluate the RHS expression in the false block.
if (expr->op == ast::BinaryOp::kLogicalAnd) { if (expr->op == ast::BinaryOp::kLogicalAnd) {
current_flow_block = if_node->true_.target->As<Block>(); current_flow_block_ = if_node->true_.target->As<Block>();
} else { } else {
current_flow_block = if_node->false_.target->As<Block>(); current_flow_block_ = if_node->false_.target->As<Block>();
} }
rhs = EmitExpression(expr->rhs); rhs = EmitExpression(expr->rhs);
if (!rhs) { if (!rhs) {
return utils::Failure; return utils::Failure;
} }
auto* rhs_store = builder.Store(result_var, rhs.Get()); auto* rhs_store = builder_.Store(result_var, rhs.Get());
current_flow_block->instructions.Push(rhs_store); current_flow_block_->instructions.Push(rhs_store);
BranchTo(if_node->merge.target); BranchTo(if_node->merge.target);
} }
current_flow_block = if_node->merge.target->As<Block>(); current_flow_block_ = if_node->merge.target->As<Block>();
return result_var; return result_var;
} }
@ -952,52 +969,52 @@ class Impl {
Binary* inst = nullptr; Binary* inst = nullptr;
switch (expr->op) { switch (expr->op) {
case ast::BinaryOp::kAnd: case ast::BinaryOp::kAnd:
inst = builder.And(ty, lhs.Get(), rhs.Get()); inst = builder_.And(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kOr: case ast::BinaryOp::kOr:
inst = builder.Or(ty, lhs.Get(), rhs.Get()); inst = builder_.Or(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kXor: case ast::BinaryOp::kXor:
inst = builder.Xor(ty, lhs.Get(), rhs.Get()); inst = builder_.Xor(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kEqual: case ast::BinaryOp::kEqual:
inst = builder.Equal(ty, lhs.Get(), rhs.Get()); inst = builder_.Equal(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kNotEqual: case ast::BinaryOp::kNotEqual:
inst = builder.NotEqual(ty, lhs.Get(), rhs.Get()); inst = builder_.NotEqual(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kLessThan: case ast::BinaryOp::kLessThan:
inst = builder.LessThan(ty, lhs.Get(), rhs.Get()); inst = builder_.LessThan(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kGreaterThan: case ast::BinaryOp::kGreaterThan:
inst = builder.GreaterThan(ty, lhs.Get(), rhs.Get()); inst = builder_.GreaterThan(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kLessThanEqual: case ast::BinaryOp::kLessThanEqual:
inst = builder.LessThanEqual(ty, lhs.Get(), rhs.Get()); inst = builder_.LessThanEqual(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kGreaterThanEqual: case ast::BinaryOp::kGreaterThanEqual:
inst = builder.GreaterThanEqual(ty, lhs.Get(), rhs.Get()); inst = builder_.GreaterThanEqual(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kShiftLeft: case ast::BinaryOp::kShiftLeft:
inst = builder.ShiftLeft(ty, lhs.Get(), rhs.Get()); inst = builder_.ShiftLeft(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kShiftRight: case ast::BinaryOp::kShiftRight:
inst = builder.ShiftRight(ty, lhs.Get(), rhs.Get()); inst = builder_.ShiftRight(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kAdd: case ast::BinaryOp::kAdd:
inst = builder.Add(ty, lhs.Get(), rhs.Get()); inst = builder_.Add(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kSubtract: case ast::BinaryOp::kSubtract:
inst = builder.Subtract(ty, lhs.Get(), rhs.Get()); inst = builder_.Subtract(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kMultiply: case ast::BinaryOp::kMultiply:
inst = builder.Multiply(ty, lhs.Get(), rhs.Get()); inst = builder_.Multiply(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kDivide: case ast::BinaryOp::kDivide:
inst = builder.Divide(ty, lhs.Get(), rhs.Get()); inst = builder_.Divide(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kModulo: case ast::BinaryOp::kModulo:
inst = builder.Modulo(ty, lhs.Get(), rhs.Get()); inst = builder_.Modulo(ty, lhs.Get(), rhs.Get());
break; break;
case ast::BinaryOp::kLogicalAnd: case ast::BinaryOp::kLogicalAnd:
case ast::BinaryOp::kLogicalOr: case ast::BinaryOp::kLogicalOr:
@ -1008,7 +1025,7 @@ class Impl {
return utils::Failure; return utils::Failure;
} }
current_flow_block->instructions.Push(inst); current_flow_block_->instructions.Push(inst);
return inst; return inst;
} }
@ -1020,9 +1037,9 @@ class Impl {
auto* sem = program_->Sem().Get(expr); auto* sem = program_->Sem().Get(expr);
auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx); auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
auto* inst = builder.Bitcast(ty, val.Get()); auto* inst = builder_.Bitcast(ty, val.Get());
current_flow_block->instructions.Push(inst); current_flow_block_->instructions.Push(inst);
return inst; return inst;
} }
@ -1038,7 +1055,7 @@ class Impl {
std::string(expr->TypeInfo().name)); std::string(expr->TypeInfo().name));
return utils::Failure; return utils::Failure;
} }
return builder.Constant(cv); return builder_.Constant(cv);
} }
} }
@ -1068,24 +1085,24 @@ class Impl {
// If this is a builtin function, emit the specific builtin value // If this is a builtin function, emit the specific builtin value
if (auto* b = sem->Target()->As<sem::Builtin>()) { if (auto* b = sem->Target()->As<sem::Builtin>()) {
inst = builder.Builtin(ty, b->Type(), args); inst = builder_.Builtin(ty, b->Type(), args);
} else if (sem->Target()->As<sem::ValueConstructor>()) { } else if (sem->Target()->As<sem::ValueConstructor>()) {
inst = builder.Construct(ty, std::move(args)); inst = builder_.Construct(ty, std::move(args));
} else if (auto* conv = sem->Target()->As<sem::ValueConversion>()) { } else if (auto* conv = sem->Target()->As<sem::ValueConversion>()) {
auto* from = conv->Source()->Clone(clone_ctx_.type_ctx); auto* from = conv->Source()->Clone(clone_ctx_.type_ctx);
inst = builder.Convert(ty, from, std::move(args)); inst = builder_.Convert(ty, from, std::move(args));
} else if (expr->target->identifier->Is<ast::TemplatedIdentifier>()) { } else if (expr->target->identifier->Is<ast::TemplatedIdentifier>()) {
TINT_UNIMPLEMENTED(IR, diagnostics_) << "missing templated ident support"; TINT_UNIMPLEMENTED(IR, diagnostics_) << "missing templated ident support";
return utils::Failure; return utils::Failure;
} else { } else {
// Not a builtin and not a templated call, so this is a user function. // Not a builtin and not a templated call, so this is a user function.
auto name = CloneSymbol(expr->target->identifier->symbol); auto name = CloneSymbol(expr->target->identifier->symbol);
inst = builder.UserCall(ty, name, std::move(args)); inst = builder_.UserCall(ty, name, std::move(args));
} }
if (inst == nullptr) { if (inst == nullptr) {
return utils::Failure; return utils::Failure;
} }
current_flow_block->instructions.Push(inst); current_flow_block_->instructions.Push(inst);
return inst; return inst;
} }
@ -1103,7 +1120,7 @@ class Impl {
"failed to get constant value for node " + std::string(lit->TypeInfo().name)); "failed to get constant value for node " + std::string(lit->TypeInfo().name));
return utils::Failure; return utils::Failure;
} }
return builder.Constant(cv); return builder_.Constant(cv);
} }
// void EmitAttributes(utils::VectorRef<const ast::Attribute*> attrs) { // void EmitAttributes(utils::VectorRef<const ast::Attribute*> attrs) {
@ -1178,7 +1195,7 @@ utils::Result<Module, std::string> FromProgram(const Program* program) {
Impl b(program); Impl b(program);
auto r = b.Build(); auto r = b.Build();
if (!r) { if (!r) {
return b.Diagnostics().str(); return r.Failure().str();
} }
return r.Move(); return r.Move();