mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 08:54:47 +01:00
Move control flow block functions to their own file. (#4921)
context.cpp is getting large, so I'm looking at a few ways to cut out clusters of functions. This felt like a logical cluster of functions to move to their own file. Note this doesn't touch the implementation at all, beyond what's needed to change from `Context` members to context args.
This commit is contained in:
@@ -17,6 +17,7 @@ cc_library(
|
||||
srcs = [
|
||||
"call.cpp",
|
||||
"context.cpp",
|
||||
"control_flow.cpp",
|
||||
"convert.cpp",
|
||||
"decl_name_stack.cpp",
|
||||
"deduce.cpp",
|
||||
@@ -44,6 +45,7 @@ cc_library(
|
||||
hdrs = [
|
||||
"call.h",
|
||||
"context.h",
|
||||
"control_flow.h",
|
||||
"convert.h",
|
||||
"decl_introducer_state.h",
|
||||
"decl_name_stack.h",
|
||||
|
||||
@@ -745,110 +745,6 @@ auto Context::LookupNameInCore(SemIR::LocId loc_id, llvm::StringRef name)
|
||||
return constant_values().GetConstantInstId(scope_result.target_inst_id());
|
||||
}
|
||||
|
||||
template <typename BranchNode, typename... Args>
|
||||
static auto AddDominatedBlockAndBranchImpl(Context& context,
|
||||
Parse::NodeId node_id, Args... args)
|
||||
-> SemIR::InstBlockId {
|
||||
if (!context.inst_block_stack().is_current_block_reachable()) {
|
||||
return SemIR::InstBlockId::Unreachable;
|
||||
}
|
||||
auto block_id = context.inst_blocks().AddDefaultValue();
|
||||
context.AddInst<BranchNode>(node_id, {block_id, args...});
|
||||
return block_id;
|
||||
}
|
||||
|
||||
auto Context::AddDominatedBlockAndBranch(Parse::NodeId node_id)
|
||||
-> SemIR::InstBlockId {
|
||||
return AddDominatedBlockAndBranchImpl<SemIR::Branch>(*this, node_id);
|
||||
}
|
||||
|
||||
auto Context::AddDominatedBlockAndBranchWithArg(Parse::NodeId node_id,
|
||||
SemIR::InstId arg_id)
|
||||
-> SemIR::InstBlockId {
|
||||
return AddDominatedBlockAndBranchImpl<SemIR::BranchWithArg>(*this, node_id,
|
||||
arg_id);
|
||||
}
|
||||
|
||||
auto Context::AddDominatedBlockAndBranchIf(Parse::NodeId node_id,
|
||||
SemIR::InstId cond_id)
|
||||
-> SemIR::InstBlockId {
|
||||
return AddDominatedBlockAndBranchImpl<SemIR::BranchIf>(*this, node_id,
|
||||
cond_id);
|
||||
}
|
||||
|
||||
auto Context::AddConvergenceBlockAndPush(Parse::NodeId node_id, int num_blocks)
|
||||
-> void {
|
||||
CARBON_CHECK(num_blocks >= 2, "no convergence");
|
||||
|
||||
SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
|
||||
for ([[maybe_unused]] auto _ : llvm::seq(num_blocks)) {
|
||||
if (inst_block_stack().is_current_block_reachable()) {
|
||||
if (new_block_id == SemIR::InstBlockId::Unreachable) {
|
||||
new_block_id = inst_blocks().AddDefaultValue();
|
||||
}
|
||||
CARBON_CHECK(node_id.has_value());
|
||||
AddInst<SemIR::Branch>(node_id, {.target_id = new_block_id});
|
||||
}
|
||||
inst_block_stack().Pop();
|
||||
}
|
||||
inst_block_stack().Push(new_block_id);
|
||||
AddToRegion(new_block_id, node_id);
|
||||
}
|
||||
|
||||
auto Context::AddConvergenceBlockWithArgAndPush(
|
||||
Parse::NodeId node_id, std::initializer_list<SemIR::InstId> block_args)
|
||||
-> SemIR::InstId {
|
||||
CARBON_CHECK(block_args.size() >= 2, "no convergence");
|
||||
|
||||
SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
|
||||
for (auto arg_id : block_args) {
|
||||
if (inst_block_stack().is_current_block_reachable()) {
|
||||
if (new_block_id == SemIR::InstBlockId::Unreachable) {
|
||||
new_block_id = inst_blocks().AddDefaultValue();
|
||||
}
|
||||
AddInst<SemIR::BranchWithArg>(
|
||||
node_id, {.target_id = new_block_id, .arg_id = arg_id});
|
||||
}
|
||||
inst_block_stack().Pop();
|
||||
}
|
||||
inst_block_stack().Push(new_block_id);
|
||||
AddToRegion(new_block_id, node_id);
|
||||
|
||||
// Acquire the result value.
|
||||
SemIR::TypeId result_type_id = insts().Get(*block_args.begin()).type_id();
|
||||
return AddInst<SemIR::BlockArg>(
|
||||
node_id, {.type_id = result_type_id, .block_id = new_block_id});
|
||||
}
|
||||
|
||||
auto Context::SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id,
|
||||
SemIR::InstId cond_id,
|
||||
SemIR::InstId if_true,
|
||||
SemIR::InstId if_false)
|
||||
-> void {
|
||||
CARBON_CHECK(insts().Is<SemIR::BlockArg>(select_id));
|
||||
|
||||
// Determine the constant result based on the condition value.
|
||||
SemIR::ConstantId const_id = SemIR::ConstantId::NotConstant;
|
||||
auto cond_const_id = constant_values().Get(cond_id);
|
||||
if (!cond_const_id.is_template()) {
|
||||
// Symbolic or non-constant condition means a non-constant result.
|
||||
} else if (auto literal = insts().TryGetAs<SemIR::BoolLiteral>(
|
||||
constant_values().GetInstId(cond_const_id))) {
|
||||
const_id = constant_values().Get(literal.value().value.ToBool() ? if_true
|
||||
: if_false);
|
||||
} else {
|
||||
CARBON_CHECK(cond_const_id == SemIR::ErrorInst::SingletonConstantId,
|
||||
"Unexpected constant branch condition.");
|
||||
const_id = SemIR::ErrorInst::SingletonConstantId;
|
||||
}
|
||||
|
||||
if (const_id.is_constant()) {
|
||||
CARBON_VLOG("Constant: {0} -> {1}\n", insts().Get(select_id),
|
||||
constant_values().GetInstId(const_id));
|
||||
constant_values().Set(select_id, const_id);
|
||||
}
|
||||
}
|
||||
|
||||
auto Context::AddToRegion(SemIR::InstBlockId block_id, SemIR::LocId loc_id)
|
||||
-> void {
|
||||
if (region_stack_.empty()) {
|
||||
@@ -936,22 +832,6 @@ auto Context::InsertHere(SemIR::ExprRegionId region_id) -> SemIR::InstId {
|
||||
return region.result_id;
|
||||
}
|
||||
|
||||
auto Context::is_current_position_reachable() -> bool {
|
||||
if (!inst_block_stack().is_current_block_reachable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Our current position is at the end of a reachable block. That position is
|
||||
// reachable unless the previous instruction is a terminator instruction.
|
||||
auto block_contents = inst_block_stack().PeekCurrentBlockContents();
|
||||
if (block_contents.empty()) {
|
||||
return true;
|
||||
}
|
||||
const auto& last_inst = insts().Get(block_contents.back());
|
||||
return last_inst.kind().terminator_kind() !=
|
||||
SemIR::TerminatorKind::Terminator;
|
||||
}
|
||||
|
||||
auto Context::Finalize() -> void {
|
||||
// Pop information for the file-level scope.
|
||||
sem_ir().set_top_inst_block_id(inst_block_stack().Pop());
|
||||
|
||||
@@ -314,57 +314,6 @@ class Context {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Adds a `Branch` instruction branching to a new instruction block, and
|
||||
// returns the ID of the new block. All paths to the branch target must go
|
||||
// through the current block, though not necessarily through this branch.
|
||||
auto AddDominatedBlockAndBranch(Parse::NodeId node_id) -> SemIR::InstBlockId;
|
||||
|
||||
// Adds a `Branch` instruction branching to a new instruction block with a
|
||||
// value, and returns the ID of the new block. All paths to the branch target
|
||||
// must go through the current block.
|
||||
auto AddDominatedBlockAndBranchWithArg(Parse::NodeId node_id,
|
||||
SemIR::InstId arg_id)
|
||||
-> SemIR::InstBlockId;
|
||||
|
||||
// Adds a `BranchIf` instruction branching to a new instruction block, and
|
||||
// returns the ID of the new block. All paths to the branch target must go
|
||||
// through the current block.
|
||||
auto AddDominatedBlockAndBranchIf(Parse::NodeId node_id,
|
||||
SemIR::InstId cond_id)
|
||||
-> SemIR::InstBlockId;
|
||||
|
||||
// Handles recovergence of control flow. Adds branches from the top
|
||||
// `num_blocks` on the instruction block stack to a new block, pops the
|
||||
// existing blocks, pushes the new block onto the instruction block stack,
|
||||
// and adds it to the most recently pushed region.
|
||||
auto AddConvergenceBlockAndPush(Parse::NodeId node_id, int num_blocks)
|
||||
-> void;
|
||||
|
||||
// Handles recovergence of control flow with a result value. Adds branches
|
||||
// from the top few blocks on the instruction block stack to a new block, pops
|
||||
// the existing blocks, pushes the new block onto the instruction block
|
||||
// stack, and adds it to the most recently pushed region. The number of blocks
|
||||
// popped is the size of `block_args`, and the corresponding result values are
|
||||
// the elements of `block_args`. Returns an instruction referring to the
|
||||
// result value.
|
||||
auto AddConvergenceBlockWithArgAndPush(
|
||||
Parse::NodeId node_id, std::initializer_list<SemIR::InstId> block_args)
|
||||
-> SemIR::InstId;
|
||||
|
||||
// Sets the constant value of a block argument created as the result of a
|
||||
// branch. `select_id` should be a `BlockArg` that selects between two
|
||||
// values. `cond_id` is the condition, `if_false` is the value to use if the
|
||||
// condition is false, and `if_true` is the value to use if the condition is
|
||||
// true. We don't track enough information in the `BlockArg` inst for
|
||||
// `TryEvalInst` to do this itself.
|
||||
auto SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id,
|
||||
SemIR::InstId cond_id,
|
||||
SemIR::InstId if_true,
|
||||
SemIR::InstId if_false) -> void;
|
||||
|
||||
// Returns whether the current position in the current block is reachable.
|
||||
auto is_current_position_reachable() -> bool;
|
||||
|
||||
// Returns the type ID for a constant of type `type`.
|
||||
auto GetTypeIdForTypeConstant(SemIR::ConstantId constant_id) -> SemIR::TypeId;
|
||||
|
||||
@@ -489,6 +438,8 @@ class Context {
|
||||
return parse_tree().tokens();
|
||||
}
|
||||
|
||||
auto vlog_stream() -> llvm::raw_ostream* { return vlog_stream_; }
|
||||
|
||||
auto node_stack() -> NodeStack& { return node_stack_; }
|
||||
|
||||
auto inst_block_stack() -> InstBlockStack& { return inst_block_stack_; }
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/check/control_flow.h"
|
||||
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
template <typename BranchNode, typename... Args>
|
||||
static auto AddDominatedBlockAndBranchImpl(Context& context,
|
||||
Parse::NodeId node_id, Args... args)
|
||||
-> SemIR::InstBlockId {
|
||||
if (!context.inst_block_stack().is_current_block_reachable()) {
|
||||
return SemIR::InstBlockId::Unreachable;
|
||||
}
|
||||
auto block_id = context.inst_blocks().AddDefaultValue();
|
||||
context.AddInst<BranchNode>(node_id, {block_id, args...});
|
||||
return block_id;
|
||||
}
|
||||
|
||||
auto AddDominatedBlockAndBranch(Context& context, Parse::NodeId node_id)
|
||||
-> SemIR::InstBlockId {
|
||||
return AddDominatedBlockAndBranchImpl<SemIR::Branch>(context, node_id);
|
||||
}
|
||||
|
||||
auto AddDominatedBlockAndBranchWithArg(Context& context, Parse::NodeId node_id,
|
||||
SemIR::InstId arg_id)
|
||||
-> SemIR::InstBlockId {
|
||||
return AddDominatedBlockAndBranchImpl<SemIR::BranchWithArg>(context, node_id,
|
||||
arg_id);
|
||||
}
|
||||
|
||||
auto AddDominatedBlockAndBranchIf(Context& context, Parse::NodeId node_id,
|
||||
SemIR::InstId cond_id) -> SemIR::InstBlockId {
|
||||
return AddDominatedBlockAndBranchImpl<SemIR::BranchIf>(context, node_id,
|
||||
cond_id);
|
||||
}
|
||||
|
||||
auto AddConvergenceBlockAndPush(Context& context, Parse::NodeId node_id,
|
||||
int num_blocks) -> void {
|
||||
CARBON_CHECK(num_blocks >= 2, "no convergence");
|
||||
|
||||
SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
|
||||
for ([[maybe_unused]] auto _ : llvm::seq(num_blocks)) {
|
||||
if (context.inst_block_stack().is_current_block_reachable()) {
|
||||
if (new_block_id == SemIR::InstBlockId::Unreachable) {
|
||||
new_block_id = context.inst_blocks().AddDefaultValue();
|
||||
}
|
||||
CARBON_CHECK(node_id.has_value());
|
||||
context.AddInst<SemIR::Branch>(node_id, {.target_id = new_block_id});
|
||||
}
|
||||
context.inst_block_stack().Pop();
|
||||
}
|
||||
context.inst_block_stack().Push(new_block_id);
|
||||
context.AddToRegion(new_block_id, node_id);
|
||||
}
|
||||
|
||||
auto AddConvergenceBlockWithArgAndPush(
|
||||
Context& context, Parse::NodeId node_id,
|
||||
std::initializer_list<SemIR::InstId> block_args) -> SemIR::InstId {
|
||||
CARBON_CHECK(block_args.size() >= 2, "no convergence");
|
||||
|
||||
SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
|
||||
for (auto arg_id : block_args) {
|
||||
if (context.inst_block_stack().is_current_block_reachable()) {
|
||||
if (new_block_id == SemIR::InstBlockId::Unreachable) {
|
||||
new_block_id = context.inst_blocks().AddDefaultValue();
|
||||
}
|
||||
context.AddInst<SemIR::BranchWithArg>(
|
||||
node_id, {.target_id = new_block_id, .arg_id = arg_id});
|
||||
}
|
||||
context.inst_block_stack().Pop();
|
||||
}
|
||||
context.inst_block_stack().Push(new_block_id);
|
||||
context.AddToRegion(new_block_id, node_id);
|
||||
|
||||
// Acquire the result value.
|
||||
SemIR::TypeId result_type_id =
|
||||
context.insts().Get(*block_args.begin()).type_id();
|
||||
return context.AddInst<SemIR::BlockArg>(
|
||||
node_id, {.type_id = result_type_id, .block_id = new_block_id});
|
||||
}
|
||||
|
||||
auto SetBlockArgResultBeforeConstantUse(Context& context,
|
||||
SemIR::InstId select_id,
|
||||
SemIR::InstId cond_id,
|
||||
SemIR::InstId if_true,
|
||||
SemIR::InstId if_false) -> void {
|
||||
CARBON_CHECK(context.insts().Is<SemIR::BlockArg>(select_id));
|
||||
|
||||
// Determine the constant result based on the condition value.
|
||||
SemIR::ConstantId const_id = SemIR::ConstantId::NotConstant;
|
||||
auto cond_const_id = context.constant_values().Get(cond_id);
|
||||
if (!cond_const_id.is_template()) {
|
||||
// Symbolic or non-constant condition means a non-constant result.
|
||||
} else if (auto literal = context.insts().TryGetAs<SemIR::BoolLiteral>(
|
||||
context.constant_values().GetInstId(cond_const_id))) {
|
||||
const_id = context.constant_values().Get(
|
||||
literal.value().value.ToBool() ? if_true : if_false);
|
||||
} else {
|
||||
CARBON_CHECK(cond_const_id == SemIR::ErrorInst::SingletonConstantId,
|
||||
"Unexpected constant branch condition.");
|
||||
const_id = SemIR::ErrorInst::SingletonConstantId;
|
||||
}
|
||||
|
||||
if (const_id.is_constant()) {
|
||||
CARBON_VLOG_TO(context.vlog_stream(), "Constant: {0} -> {1}\n",
|
||||
context.insts().Get(select_id),
|
||||
context.constant_values().GetInstId(const_id));
|
||||
context.constant_values().Set(select_id, const_id);
|
||||
}
|
||||
}
|
||||
|
||||
auto IsCurrentPositionReachable(Context& context) -> bool {
|
||||
if (!context.inst_block_stack().is_current_block_reachable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Our current position is at the end of a reachable block. That position is
|
||||
// reachable unless the previous instruction is a terminator instruction.
|
||||
auto block_contents = context.inst_block_stack().PeekCurrentBlockContents();
|
||||
if (block_contents.empty()) {
|
||||
return true;
|
||||
}
|
||||
const auto& last_inst = context.insts().Get(block_contents.back());
|
||||
return last_inst.kind().terminator_kind() !=
|
||||
SemIR::TerminatorKind::Terminator;
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
@@ -0,0 +1,67 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef CARBON_TOOLCHAIN_CHECK_CONTROL_FLOW_H_
|
||||
#define CARBON_TOOLCHAIN_CHECK_CONTROL_FLOW_H_
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
// Adds a `Branch` instruction branching to a new instruction block, and
|
||||
// returns the ID of the new block. All paths to the branch target must go
|
||||
// through the current block, though not necessarily through this branch.
|
||||
auto AddDominatedBlockAndBranch(Context& context, Parse::NodeId node_id)
|
||||
-> SemIR::InstBlockId;
|
||||
|
||||
// Adds a `Branch` instruction branching to a new instruction block with a
|
||||
// value, and returns the ID of the new block. All paths to the branch target
|
||||
// must go through the current block.
|
||||
auto AddDominatedBlockAndBranchWithArg(Context& context, Parse::NodeId node_id,
|
||||
SemIR::InstId arg_id)
|
||||
-> SemIR::InstBlockId;
|
||||
|
||||
// Adds a `BranchIf` instruction branching to a new instruction block, and
|
||||
// returns the ID of the new block. All paths to the branch target must go
|
||||
// through the current block.
|
||||
auto AddDominatedBlockAndBranchIf(Context& context, Parse::NodeId node_id,
|
||||
SemIR::InstId cond_id) -> SemIR::InstBlockId;
|
||||
|
||||
// Handles recovergence of control flow. Adds branches from the top
|
||||
// `num_blocks` on the instruction block stack to a new block, pops the
|
||||
// existing blocks, pushes the new block onto the instruction block stack,
|
||||
// and adds it to the most recently pushed region.
|
||||
auto AddConvergenceBlockAndPush(Context& context, Parse::NodeId node_id,
|
||||
int num_blocks) -> void;
|
||||
|
||||
// Handles recovergence of control flow with a result value. Adds branches
|
||||
// from the top few blocks on the instruction block stack to a new block, pops
|
||||
// the existing blocks, pushes the new block onto the instruction block
|
||||
// stack, and adds it to the most recently pushed region. The number of blocks
|
||||
// popped is the size of `block_args`, and the corresponding result values are
|
||||
// the elements of `block_args`. Returns an instruction referring to the
|
||||
// result value.
|
||||
auto AddConvergenceBlockWithArgAndPush(
|
||||
Context& context, Parse::NodeId node_id,
|
||||
std::initializer_list<SemIR::InstId> block_args) -> SemIR::InstId;
|
||||
|
||||
// Sets the constant value of a block argument created as the result of a
|
||||
// branch. `select_id` should be a `BlockArg` that selects between two
|
||||
// values. `cond_id` is the condition, `if_false` is the value to use if the
|
||||
// condition is false, and `if_true` is the value to use if the condition is
|
||||
// true. We don't track enough information in the `BlockArg` inst for
|
||||
// `TryEvalInst` to do this itself.
|
||||
auto SetBlockArgResultBeforeConstantUse(Context& context,
|
||||
SemIR::InstId select_id,
|
||||
SemIR::InstId cond_id,
|
||||
SemIR::InstId if_true,
|
||||
SemIR::InstId if_false) -> void;
|
||||
|
||||
// Returns whether the current position in the current block is reachable.
|
||||
auto IsCurrentPositionReachable(Context& context) -> bool;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_CONTROL_FLOW_H_
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/control_flow.h"
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/decl_introducer_state.h"
|
||||
#include "toolchain/check/decl_name_stack.h"
|
||||
@@ -445,7 +446,7 @@ auto HandleParseNode(Context& context, Parse::FunctionDefinitionId node_id)
|
||||
|
||||
// If the `}` of the function is reachable, reject if we need a return value
|
||||
// and otherwise add an implicit `return;`.
|
||||
if (context.is_current_position_reachable()) {
|
||||
if (IsCurrentPositionReachable(context)) {
|
||||
if (context.functions()
|
||||
.Get(function_id)
|
||||
.return_slot_pattern_id.has_value()) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/control_flow.h"
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/literal.h"
|
||||
@@ -19,8 +20,8 @@ auto HandleParseNode(Context& context, Parse::IfExprIfId node_id) -> bool {
|
||||
cond_value_id = ConvertToBoolValue(context, if_node, cond_value_id);
|
||||
context.node_stack().Push(cond_node, cond_value_id);
|
||||
auto then_block_id =
|
||||
context.AddDominatedBlockAndBranchIf(if_node, cond_value_id);
|
||||
auto else_block_id = context.AddDominatedBlockAndBranch(if_node);
|
||||
AddDominatedBlockAndBranchIf(context, if_node, cond_value_id);
|
||||
auto else_block_id = AddDominatedBlockAndBranch(context, if_node);
|
||||
|
||||
// Start emitting the `then` block.
|
||||
context.inst_block_stack().Pop();
|
||||
@@ -85,10 +86,10 @@ auto HandleParseNode(Context& context, Parse::IfExprElseId node_id) -> bool {
|
||||
ConvertToValueOfType(context, else_node, else_value_id, result_type_id);
|
||||
|
||||
// Create a resumption block and branches to it.
|
||||
auto chosen_value_id = context.AddConvergenceBlockWithArgAndPush(
|
||||
if_node, {else_value_id, then_value_id});
|
||||
context.SetBlockArgResultBeforeConstantUse(chosen_value_id, cond_value_id,
|
||||
then_value_id, else_value_id);
|
||||
auto chosen_value_id = AddConvergenceBlockWithArgAndPush(
|
||||
context, if_node, {else_value_id, then_value_id});
|
||||
SetBlockArgResultBeforeConstantUse(context, chosen_value_id, cond_value_id,
|
||||
then_value_id, else_value_id);
|
||||
|
||||
// Push the result value.
|
||||
context.node_stack().Push(else_node, chosen_value_id);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/control_flow.h"
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
|
||||
@@ -22,8 +23,8 @@ auto HandleParseNode(Context& context, Parse::IfConditionId node_id) -> bool {
|
||||
// there is no `else`, the then block will terminate with a branch to the
|
||||
// else block, which will be reused as the resumption block.
|
||||
auto then_block_id =
|
||||
context.AddDominatedBlockAndBranchIf(node_id, cond_value_id);
|
||||
auto else_block_id = context.AddDominatedBlockAndBranch(node_id);
|
||||
AddDominatedBlockAndBranchIf(context, node_id, cond_value_id);
|
||||
auto else_block_id = AddDominatedBlockAndBranch(context, node_id);
|
||||
|
||||
// Start emitting the `then` block.
|
||||
context.inst_block_stack().Pop();
|
||||
@@ -64,7 +65,7 @@ auto HandleParseNode(Context& context, Parse::IfStatementId node_id) -> bool {
|
||||
// Branch from the then and else blocks to a new resumption block.
|
||||
context.node_stack()
|
||||
.PopAndDiscardSoloNodeId<Parse::NodeKind::IfStatementElse>();
|
||||
context.AddConvergenceBlockAndPush(node_id, /*num_blocks=*/2);
|
||||
AddConvergenceBlockAndPush(context, node_id, /*num_blocks=*/2);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/control_flow.h"
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
|
||||
@@ -16,7 +17,7 @@ auto HandleParseNode(Context& context, Parse::WhileConditionStartId node_id)
|
||||
// Branch to the loop header block. Note that we create a new block here even
|
||||
// if the current block is empty; this ensures that the loop always has a
|
||||
// preheader block.
|
||||
auto loop_header_id = context.AddDominatedBlockAndBranch(node_id);
|
||||
auto loop_header_id = AddDominatedBlockAndBranch(context, node_id);
|
||||
context.inst_block_stack().Pop();
|
||||
|
||||
// Start emitting the loop header block.
|
||||
@@ -36,8 +37,8 @@ auto HandleParseNode(Context& context, Parse::WhileConditionId node_id)
|
||||
|
||||
// Branch to either the loop body or the loop exit block.
|
||||
auto loop_body_id =
|
||||
context.AddDominatedBlockAndBranchIf(node_id, cond_value_id);
|
||||
auto loop_exit_id = context.AddDominatedBlockAndBranch(node_id);
|
||||
AddDominatedBlockAndBranchIf(context, node_id, cond_value_id);
|
||||
auto loop_exit_id = AddDominatedBlockAndBranch(context, node_id);
|
||||
context.inst_block_stack().Pop();
|
||||
|
||||
// Start emitting the loop body.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/control_flow.h"
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/operator.h"
|
||||
@@ -349,9 +350,9 @@ static auto HandleShortCircuitOperand(Context& context, Parse::NodeId node_id,
|
||||
|
||||
// Create a block for the right-hand side and for the continuation.
|
||||
auto rhs_block_id =
|
||||
context.AddDominatedBlockAndBranchIf(node_id, branch_value_id);
|
||||
auto end_block_id = context.AddDominatedBlockAndBranchWithArg(
|
||||
node_id, short_circuit_result_id);
|
||||
AddDominatedBlockAndBranchIf(context, node_id, branch_value_id);
|
||||
auto end_block_id = AddDominatedBlockAndBranchWithArg(
|
||||
context, node_id, short_circuit_result_id);
|
||||
|
||||
// Push the branch condition and result for use when handling the complete
|
||||
// expression.
|
||||
@@ -410,8 +411,8 @@ static auto HandleShortCircuitOperator(Context& context, Parse::NodeId node_id)
|
||||
auto result_id = context.AddInst<SemIR::BlockArg>(
|
||||
node_id, {.type_id = context.insts().Get(rhs_id).type_id(),
|
||||
.block_id = resume_block_id});
|
||||
context.SetBlockArgResultBeforeConstantUse(result_id, branch_value_id, rhs_id,
|
||||
short_circuit_result_id);
|
||||
SetBlockArgResultBeforeConstantUse(context, result_id, branch_value_id,
|
||||
rhs_id, short_circuit_result_id);
|
||||
context.node_stack().Push(node_id, result_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user