diff --git a/toolchain/lowering/BUILD b/toolchain/lowering/BUILD index 29af8767c534..c21983f81ea9 100644 --- a/toolchain/lowering/BUILD +++ b/toolchain/lowering/BUILD @@ -27,6 +27,7 @@ cc_library( "lowering_handle.cpp", ], hdrs = [ + "lowering_block_worklist.h", "lowering_context.h", "lowering_function_context.h", ], diff --git a/toolchain/lowering/lowering_block_worklist.h b/toolchain/lowering/lowering_block_worklist.h new file mode 100644 index 000000000000..cfb734dd7709 --- /dev/null +++ b/toolchain/lowering/lowering_block_worklist.h @@ -0,0 +1,52 @@ +// 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_LOWERING_LOWERING_BLOCK_WORKLIST_H_ +#define CARBON_TOOLCHAIN_LOWERING_LOWERING_BLOCK_WORKLIST_H_ + +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "toolchain/semantics/semantics_node.h" + +namespace Carbon { + +// A worklist for blocks that need to be lowered. +// +// The blocks form a tree, where the sequence of blocks that are pushed +// following a `Pop` that returned block B are the children of B. Blocks are +// popped in a preorder depth-first traversal over this tree, where blocks that +// are children of the same block are popped in the same order in which they +// were pushed. +// +// This traversal order is intended to produce readable IR: +// +// - In the absence of control flow back-edges, branches will typically branch +// to blocks emitted later, although this is not guaranteed. +// - A branch and the blocks that it branches to will typically be placed close +// together. +class LoweringBlockWorklist { + public: + // Add a block to the work list. + auto Push(SemanticsNodeBlockId id) -> void { worklist_.push_back(id); } + + // Pop the next block to lower. + auto Pop() -> SemanticsNodeBlockId { + // Reverse the order of the blocks added since the last `Pop`, so that we + // pop them in the order that they were `Pushed` in. + std::reverse(worklist_.begin() + size_after_last_pop_, worklist_.end()); + SemanticsNodeBlockId result = worklist_.pop_back_val(); + size_after_last_pop_ = worklist_.size(); + return result; + } + + auto empty() -> bool { return worklist_.empty(); } + + private: + llvm::SmallVector worklist_; + int size_after_last_pop_ = 0; +}; + +} // namespace Carbon + +#endif // CARBON_TOOLCHAIN_LOWERING_LOWERING_BLOCK_WORKLIST_H_ diff --git a/toolchain/lowering/lowering_context.cpp b/toolchain/lowering/lowering_context.cpp index 3eb130504ba4..b92d58342bf5 100644 --- a/toolchain/lowering/lowering_context.cpp +++ b/toolchain/lowering/lowering_context.cpp @@ -103,16 +103,24 @@ auto LoweringContext::BuildFunctionDefinition(SemanticsFunctionId function_id) function_lowering.SetLocal(param_storage, llvm_function->getArg(i)); } - CARBON_VLOG() << "Lowering " << function.body_id << "\n"; - for (const auto& node_id : semantics_ir().GetNodeBlock(function.body_id)) { - auto node = semantics_ir().GetNode(node_id); - CARBON_VLOG() << "Lowering " << node_id << ": " << node << "\n"; - switch (node.kind()) { + // Add the entry block to the worklist. + function_lowering.GetBlock(function.body_id); + + while (!function_lowering.block_worklist().empty()) { + SemanticsNodeBlockId block = function_lowering.block_worklist().Pop(); + CARBON_VLOG() << "Lowering " << block << "\n"; + function_lowering.builder().SetInsertPoint( + function_lowering.GetBlock(block)); + for (const auto& node_id : semantics_ir().GetNodeBlock(block)) { + auto node = semantics_ir().GetNode(node_id); + CARBON_VLOG() << "Lowering " << node_id << ": " << node << "\n"; + switch (node.kind()) { #define CARBON_SEMANTICS_NODE_KIND(Name) \ case SemanticsNodeKind::Name: \ LoweringHandle##Name(function_lowering, node_id, node); \ break; #include "toolchain/semantics/semantics_node_kind.def" + } } } } diff --git a/toolchain/lowering/lowering_function_context.cpp b/toolchain/lowering/lowering_function_context.cpp index 4b068c8b2f7f..e9a04150f2ad 100644 --- a/toolchain/lowering/lowering_function_context.cpp +++ b/toolchain/lowering/lowering_function_context.cpp @@ -14,9 +14,54 @@ LoweringFunctionContext::LoweringFunctionContext( LoweringContext& lowering_context, llvm::Function* function) : lowering_context_(&lowering_context), function_(function), - builder_(lowering_context.llvm_context()) { - builder_.SetInsertPoint( - llvm::BasicBlock::Create(llvm_context(), "entry", function_)); + builder_(lowering_context.llvm_context()) {} + +auto LoweringFunctionContext::GetBlock(SemanticsNodeBlockId block_id) + -> llvm::BasicBlock* { + llvm::BasicBlock*& entry = blocks_[block_id]; + if (!entry) { + entry = llvm::BasicBlock::Create(llvm_context(), "", function_); + block_worklist().Push(block_id); + } + return entry; +} + +auto LoweringFunctionContext::TryToReuseBlock(SemanticsNodeBlockId block_id, + llvm::BasicBlock* block) -> bool { + if (!blocks_.insert({block_id, block}).second) { + return false; + } + block_worklist().Push(block_id); + if (block == synthetic_block_) { + synthetic_block_ = nullptr; + } + return true; +} + +auto LoweringFunctionContext::GetBlockArg(SemanticsNodeBlockId block_id, + SemanticsTypeId type_id) + -> llvm::PHINode* { + llvm::BasicBlock* block = GetBlock(block_id); + + // Find the existing phi, if any. + auto phis = block->phis(); + if (!phis.empty()) { + CARBON_CHECK(std::next(phis.begin()) == phis.end()) + << "Expected at most one phi, found " + << std::distance(phis.begin(), phis.end()); + return &*phis.begin(); + } + + // The number of predecessor slots to reserve. + static constexpr unsigned NumReservedPredecessors = 2; + auto* phi = llvm::PHINode::Create(GetType(type_id), NumReservedPredecessors); + phi->insertInto(block, block->begin()); + return phi; +} + +auto LoweringFunctionContext::CreateSyntheticBlock() -> llvm::BasicBlock* { + synthetic_block_ = llvm::BasicBlock::Create(llvm_context(), "", function_); + return synthetic_block_; } auto LoweringFunctionContext::GetLocalLoaded(SemanticsNodeId node_id) diff --git a/toolchain/lowering/lowering_function_context.h b/toolchain/lowering/lowering_function_context.h index c1bf2abf43fb..8f688a3e2fc8 100644 --- a/toolchain/lowering/lowering_function_context.h +++ b/toolchain/lowering/lowering_function_context.h @@ -5,9 +5,12 @@ #ifndef CARBON_TOOLCHAIN_LOWERING_LOWERING_FUNCTION_CONTEXT_H_ #define CARBON_TOOLCHAIN_LOWERING_LOWERING_FUNCTION_CONTEXT_H_ +#include + #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "toolchain/lowering/lowering_block_worklist.h" #include "toolchain/lowering/lowering_context.h" #include "toolchain/semantics/semantics_ir.h" #include "toolchain/semantics/semantics_node.h" @@ -21,6 +24,21 @@ class LoweringFunctionContext { explicit LoweringFunctionContext(LoweringContext& lowering_context, llvm::Function* function); + // Returns a basic block corresponding to the start of the given semantics + // block, and enqueues it for emission. + auto GetBlock(SemanticsNodeBlockId block_id) -> llvm::BasicBlock*; + + // If we have not yet allocated a `BasicBlock` for this `block_id`, set it to + // `block`, and enqueue `block_id` for emission. Returns whether we set the + // block. + auto TryToReuseBlock(SemanticsNodeBlockId block_id, llvm::BasicBlock* block) + -> bool; + + // Returns a phi node corresponding to the block argument of the given basic + // block. + auto GetBlockArg(SemanticsNodeBlockId block_id, SemanticsTypeId type_id) + -> llvm::PHINode*; + // Returns a local (versus global) value for the given node. auto GetLocal(SemanticsNodeId node_id) -> llvm::Value* { auto it = locals_.find(node_id); @@ -48,6 +66,17 @@ class LoweringFunctionContext { return lowering_context_->GetType(type_id); } + // Create a synthetic block that corresponds to no SemanticsNodeBlockId. Such + // a block should only ever have a single predecessor, and is used when we + // need multiple `llvm::BasicBlock`s to model the linear control flow in a + // single SemanticsIR block. + auto CreateSyntheticBlock() -> llvm::BasicBlock*; + + // Determine whether block is the most recently created synthetic block. + auto IsCurrentSyntheticBlock(llvm::BasicBlock* block) -> bool { + return synthetic_block_ == block; + } + auto llvm_context() -> llvm::LLVMContext& { return lowering_context_->llvm_context(); } @@ -55,6 +84,7 @@ class LoweringFunctionContext { return lowering_context_->llvm_module(); } auto builder() -> llvm::IRBuilder<>& { return builder_; } + auto block_worklist() -> LoweringBlockWorklist& { return block_worklist_; } auto semantics_ir() -> const SemanticsIR& { return lowering_context_->semantics_ir(); } @@ -68,6 +98,16 @@ class LoweringFunctionContext { llvm::IRBuilder<> builder_; + // A worklist for blocks we need to lower. + LoweringBlockWorklist block_worklist_; + + // Maps a function's SemanticsIR blocks to lowered blocks. + llvm::DenseMap blocks_; + + // The synthetic block we most recently created. May be null if there is no + // such block. + llvm::BasicBlock* synthetic_block_ = nullptr; + // Maps a function's SemanticsIR nodes to lowered values. // TODO: Handle nested scopes. Right now this is just cleared at the end of // every block. diff --git a/toolchain/lowering/lowering_handle.cpp b/toolchain/lowering/lowering_handle.cpp index 4977072b7a98..4b9a795465e2 100644 --- a/toolchain/lowering/lowering_handle.cpp +++ b/toolchain/lowering/lowering_handle.cpp @@ -38,10 +38,11 @@ auto LoweringHandleBindName(LoweringFunctionContext& /*context*/, // Probably need to do something here, but not necessary for now. } -auto LoweringHandleBlockArg(LoweringFunctionContext& /*context*/, - SemanticsNodeId /*node_id*/, SemanticsNode node) +auto LoweringHandleBlockArg(LoweringFunctionContext& context, + SemanticsNodeId node_id, SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + SemanticsNodeBlockId block_id = node.GetAsBlockArg(); + context.SetLocal(node_id, context.GetBlockArg(block_id, node.type_id())); } auto LoweringHandleBoolLiteral(LoweringFunctionContext& context, @@ -52,22 +53,60 @@ auto LoweringHandleBoolLiteral(LoweringFunctionContext& context, context.SetLocal(node_id, v); } -auto LoweringHandleBranch(LoweringFunctionContext& /*context*/, +auto LoweringHandleBranch(LoweringFunctionContext& context, SemanticsNodeId /*node_id*/, SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + SemanticsNodeBlockId target_block_id = node.GetAsBranch(); + + // Opportunistically avoid creating a BasicBlock that contains just a branch. + llvm::BasicBlock* block = context.builder().GetInsertBlock(); + if (block->empty() && context.TryToReuseBlock(target_block_id, block)) { + // Reuse this block as the branch target. + } else { + context.builder().CreateBr(context.GetBlock(target_block_id)); + } + + context.builder().ClearInsertionPoint(); } -auto LoweringHandleBranchIf(LoweringFunctionContext& /*context*/, +auto LoweringHandleBranchIf(LoweringFunctionContext& context, SemanticsNodeId /*node_id*/, SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + auto [target_block_id, cond_id] = node.GetAsBranchIf(); + llvm::Value* cond = context.GetLocalLoaded(cond_id); + llvm::BasicBlock* then_block = context.GetBlock(target_block_id); + llvm::BasicBlock* else_block = context.CreateSyntheticBlock(); + context.builder().CreateCondBr(cond, then_block, else_block); + context.builder().SetInsertPoint(else_block); } -auto LoweringHandleBranchWithArg(LoweringFunctionContext& /*context*/, +auto LoweringHandleBranchWithArg(LoweringFunctionContext& context, SemanticsNodeId /*node_id*/, SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; + auto [target_block_id, arg_id] = node.GetAsBranchWithArg(); + llvm::Value* arg = context.GetLocalLoaded(arg_id); + SemanticsTypeId arg_type_id = + context.semantics_ir().GetNode(arg_id).type_id(); + + // Opportunistically avoid creating a BasicBlock that contains just a branch. + // We only do this for a block that we know will only have a single + // predecessor, so that we can correctly populate the predecessors of the + // PHINode. + llvm::BasicBlock* block = context.builder().GetInsertBlock(); + llvm::BasicBlock* phi_predecessor = block; + if (block->empty() && context.IsCurrentSyntheticBlock(block) && + context.TryToReuseBlock(target_block_id, block)) { + // Reuse this block as the branch target. + phi_predecessor = block->getSinglePredecessor(); + CARBON_CHECK(phi_predecessor) + << "Synthetic block did not have a single predecessor"; + } else { + context.builder().CreateBr(context.GetBlock(target_block_id)); + } + + context.GetBlockArg(target_block_id, arg_type_id) + ->addIncoming(arg, phi_predecessor); + context.builder().ClearInsertionPoint(); } auto LoweringHandleBuiltin(LoweringFunctionContext& /*context*/, diff --git a/toolchain/lowering/testdata/basics/false_true.carbon b/toolchain/lowering/testdata/basics/false_true.carbon index 27e4f0f3d534..0ad9040a9cd7 100644 --- a/toolchain/lowering/testdata/basics/false_true.carbon +++ b/toolchain/lowering/testdata/basics/false_true.carbon @@ -7,12 +7,10 @@ // CHECK:STDOUT: source_filename = "false_true.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i1 @F() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: ret i1 false // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define i1 @T() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: ret i1 true // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/basics/zero.carbon b/toolchain/lowering/testdata/basics/zero.carbon index 71b8f654fab7..3371b57c1d82 100644 --- a/toolchain/lowering/testdata/basics/zero.carbon +++ b/toolchain/lowering/testdata/basics/zero.carbon @@ -7,7 +7,6 @@ // CHECK:STDOUT: source_filename = "zero.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/call/empty_struct.carbon b/toolchain/lowering/testdata/function/call/empty_struct.carbon index 17c7a229742e..8d83682b0c27 100644 --- a/toolchain/lowering/testdata/function/call/empty_struct.carbon +++ b/toolchain/lowering/testdata/function/call/empty_struct.carbon @@ -10,19 +10,17 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %StructLiteralType @Echo(%StructLiteralType %a) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %StructLiteralValue = alloca %StructLiteralType, align 8 -// CHECK:STDOUT: %0 = load %StructLiteralType, ptr %StructLiteralValue, align 1 -// CHECK:STDOUT: ret %StructLiteralType %0 +// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %StructLiteralValue, align 1 +// CHECK:STDOUT: ret %StructLiteralType %1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %StructLiteralValue = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %var = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %StructLiteralValue1 = alloca %StructLiteralType, align 8 -// CHECK:STDOUT: %0 = load %StructLiteralType, ptr %StructLiteralValue1, align 1 -// CHECK:STDOUT: %Echo = call %StructLiteralType @Echo(%StructLiteralType %0) +// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %StructLiteralValue1, align 1 +// CHECK:STDOUT: %Echo = call %StructLiteralType @Echo(%StructLiteralType %1) // CHECK:STDOUT: store %StructLiteralType %Echo, ptr %var, align 1 // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/call/i32.carbon b/toolchain/lowering/testdata/function/call/i32.carbon index 9b580317edf7..79c2bc6a76ef 100644 --- a/toolchain/lowering/testdata/function/call/i32.carbon +++ b/toolchain/lowering/testdata/function/call/i32.carbon @@ -9,12 +9,10 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Echo(i32 %a) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: ret i32 %a // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %var = alloca i32, align 4 // CHECK:STDOUT: %Echo = call i32 @Echo(i32 1) // CHECK:STDOUT: store i32 %Echo, ptr %var, align 4 diff --git a/toolchain/lowering/testdata/function/call/params_one.carbon b/toolchain/lowering/testdata/function/call/params_one.carbon index bf3e48666aa8..87f8392c15b8 100644 --- a/toolchain/lowering/testdata/function/call/params_one.carbon +++ b/toolchain/lowering/testdata/function/call/params_one.carbon @@ -9,11 +9,9 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo(i32 %a) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %Foo = call %EmptyTupleType @Foo(i32 1) // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/call/params_one_comma.carbon b/toolchain/lowering/testdata/function/call/params_one_comma.carbon index 9694a56047b6..c529c36e118d 100644 --- a/toolchain/lowering/testdata/function/call/params_one_comma.carbon +++ b/toolchain/lowering/testdata/function/call/params_one_comma.carbon @@ -9,11 +9,9 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo(i32 %a) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %Foo = call %EmptyTupleType @Foo(i32 1) // CHECK:STDOUT: %Foo1 = call %EmptyTupleType @Foo(i32 1) // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/call/params_two.carbon b/toolchain/lowering/testdata/function/call/params_two.carbon index 02bae1eb7c5f..c40e4605459d 100644 --- a/toolchain/lowering/testdata/function/call/params_two.carbon +++ b/toolchain/lowering/testdata/function/call/params_two.carbon @@ -9,11 +9,9 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo(i32 %a, i32 %b) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %Foo = call %EmptyTupleType @Foo(i32 1, i32 2) // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/call/params_two_comma.carbon b/toolchain/lowering/testdata/function/call/params_two_comma.carbon index 73f545ae4b6e..883024e23a4c 100644 --- a/toolchain/lowering/testdata/function/call/params_two_comma.carbon +++ b/toolchain/lowering/testdata/function/call/params_two_comma.carbon @@ -9,11 +9,9 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo(i32 %a, i32 %b) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %Foo = call %EmptyTupleType @Foo(i32 1, i32 2) // CHECK:STDOUT: %Foo1 = call %EmptyTupleType @Foo(i32 1, i32 2) // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/call/params_zero.carbon b/toolchain/lowering/testdata/function/call/params_zero.carbon index 88a37913ea28..7c0a6bd3cb2f 100644 --- a/toolchain/lowering/testdata/function/call/params_zero.carbon +++ b/toolchain/lowering/testdata/function/call/params_zero.carbon @@ -9,11 +9,9 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %Foo = call %EmptyTupleType @Foo() // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/function/call/var_param.carbon b/toolchain/lowering/testdata/function/call/var_param.carbon index 8b7ca9353656..2cac6168de68 100644 --- a/toolchain/lowering/testdata/function/call/var_param.carbon +++ b/toolchain/lowering/testdata/function/call/var_param.carbon @@ -9,15 +9,13 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @DoNothing(i32 %a) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %var = alloca i32, align 4 // CHECK:STDOUT: store i32 0, ptr %var, align 4 -// CHECK:STDOUT: %0 = load i32, ptr %var, align 4 -// CHECK:STDOUT: %DoNothing = call %EmptyTupleType @DoNothing(i32 %0) +// CHECK:STDOUT: %1 = load i32, ptr %var, align 4 +// CHECK:STDOUT: %DoNothing = call %EmptyTupleType @DoNothing(i32 %1) // CHECK:STDOUT: } fn DoNothing(a: i32) {} diff --git a/toolchain/lowering/testdata/function/definition/empty_struct.carbon b/toolchain/lowering/testdata/function/definition/empty_struct.carbon index c303a6cac0ae..6661561e27d3 100644 --- a/toolchain/lowering/testdata/function/definition/empty_struct.carbon +++ b/toolchain/lowering/testdata/function/definition/empty_struct.carbon @@ -10,7 +10,6 @@ // CHECK:STDOUT: %StructLiteralType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Echo(%StructLiteralType %a) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } fn Echo(a: {}) { diff --git a/toolchain/lowering/testdata/function/definition/params_one.carbon b/toolchain/lowering/testdata/function/definition/params_one.carbon index 018202a312ec..ee5842ebaa0d 100644 --- a/toolchain/lowering/testdata/function/definition/params_one.carbon +++ b/toolchain/lowering/testdata/function/definition/params_one.carbon @@ -9,7 +9,6 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo(i32 %a) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } fn Foo(a: i32) {} diff --git a/toolchain/lowering/testdata/function/definition/params_two.carbon b/toolchain/lowering/testdata/function/definition/params_two.carbon index 21d8dfa120fc..d65d5f612811 100644 --- a/toolchain/lowering/testdata/function/definition/params_two.carbon +++ b/toolchain/lowering/testdata/function/definition/params_two.carbon @@ -9,7 +9,6 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo(i32 %a, i32 %b) { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } fn Foo(a: i32, b: i32) {} diff --git a/toolchain/lowering/testdata/function/definition/params_zero.carbon b/toolchain/lowering/testdata/function/definition/params_zero.carbon index 18b5082bb6ee..32c5109a3b0a 100644 --- a/toolchain/lowering/testdata/function/definition/params_zero.carbon +++ b/toolchain/lowering/testdata/function/definition/params_zero.carbon @@ -9,7 +9,6 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Foo() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: } fn Foo() {} diff --git a/toolchain/lowering/testdata/if_expression/basic.carbon b/toolchain/lowering/testdata/if_expression/basic.carbon new file mode 100644 index 000000000000..9e94ef708dda --- /dev/null +++ b/toolchain/lowering/testdata/if_expression/basic.carbon @@ -0,0 +1,38 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'basic.carbon' +// CHECK:STDOUT: source_filename = "basic.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @F() { +// CHECK:STDOUT: ret i32 1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @G() { +// CHECK:STDOUT: ret i32 2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @Select(i1 %b) { +// CHECK:STDOUT: br i1 %b, label %1, label %2 +// CHECK:STDOUT: +// CHECK:STDOUT: 1: ; preds = %0 +// CHECK:STDOUT: %F = call i32 @F() +// CHECK:STDOUT: br label %3 +// CHECK:STDOUT: +// CHECK:STDOUT: 2: ; preds = %0 +// CHECK:STDOUT: %G = call i32 @G() +// CHECK:STDOUT: br label %3 +// CHECK:STDOUT: +// CHECK:STDOUT: 3: ; preds = %2, %1 +// CHECK:STDOUT: %4 = phi i32 [ %F, %1 ], [ %G, %2 ] +// CHECK:STDOUT: ret i32 %4 +// CHECK:STDOUT: } + +fn F() -> i32 { return 1; } +fn G() -> i32 { return 2; } + +fn Select(b: bool) -> i32 { + return if b then F() else G(); +} diff --git a/toolchain/lowering/testdata/if_expression/empty_block.carbon b/toolchain/lowering/testdata/if_expression/empty_block.carbon new file mode 100644 index 000000000000..db2dc4e3d414 --- /dev/null +++ b/toolchain/lowering/testdata/if_expression/empty_block.carbon @@ -0,0 +1,45 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'empty_block.carbon' +// CHECK:STDOUT: source_filename = "empty_block.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @Select(i1 %b, i1 %c, i1 %d) { +// CHECK:STDOUT: br i1 %b, label %1, label %2 +// CHECK:STDOUT: +// CHECK:STDOUT: 1: ; preds = %0 +// CHECK:STDOUT: br i1 %c, label %3, label %4 +// CHECK:STDOUT: +// CHECK:STDOUT: 2: ; preds = %0 +// CHECK:STDOUT: br i1 %d, label %9, label %10 +// CHECK:STDOUT: +// CHECK:STDOUT: 3: ; preds = %1 +// CHECK:STDOUT: br label %5 +// CHECK:STDOUT: +// CHECK:STDOUT: 4: ; preds = %1 +// CHECK:STDOUT: br label %5 +// CHECK:STDOUT: +// CHECK:STDOUT: 5: ; preds = %4, %3 +// CHECK:STDOUT: %6 = phi i32 [ 1, %3 ], [ 2, %4 ] +// CHECK:STDOUT: br label %7 +// CHECK:STDOUT: +// CHECK:STDOUT: 7: ; preds = %11, %5 +// CHECK:STDOUT: %8 = phi i32 [ %6, %5 ], [ %12, %11 ] +// CHECK:STDOUT: ret i32 %8 +// CHECK:STDOUT: +// CHECK:STDOUT: 9: ; preds = %2 +// CHECK:STDOUT: br label %11 +// CHECK:STDOUT: +// CHECK:STDOUT: 10: ; preds = %2 +// CHECK:STDOUT: br label %11 +// CHECK:STDOUT: +// CHECK:STDOUT: 11: ; preds = %10, %9 +// CHECK:STDOUT: %12 = phi i32 [ 3, %9 ], [ 4, %10 ] +// CHECK:STDOUT: br label %7 +// CHECK:STDOUT: } + +fn Select(b: bool, c: bool, d: bool) -> i32 { + return if b then if c then 1 else 2 else if d then 3 else 4; +} diff --git a/toolchain/lowering/testdata/operators/and.carbon b/toolchain/lowering/testdata/operators/and.carbon new file mode 100644 index 000000000000..9f446d0dcb39 --- /dev/null +++ b/toolchain/lowering/testdata/operators/and.carbon @@ -0,0 +1,35 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'and.carbon' +// CHECK:STDOUT: source_filename = "and.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @F() { +// CHECK:STDOUT: ret i1 true +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @G() { +// CHECK:STDOUT: ret i1 true +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @And() { +// CHECK:STDOUT: %F = call i1 @F() +// CHECK:STDOUT: br i1 %F, label %1, label %2 +// CHECK:STDOUT: +// CHECK:STDOUT: 1: ; preds = %0 +// CHECK:STDOUT: %G = call i1 @G() +// CHECK:STDOUT: br label %2 +// CHECK:STDOUT: +// CHECK:STDOUT: 2: ; preds = %1, %0 +// CHECK:STDOUT: %3 = phi i1 [ false, %0 ], [ %G, %1 ] +// CHECK:STDOUT: ret i1 %3 +// CHECK:STDOUT: } + +fn F() -> bool { return true; } +fn G() -> bool { return true; } + +fn And() -> bool { + return F() and G(); +} diff --git a/toolchain/lowering/testdata/operators/and_empty_block.carbon b/toolchain/lowering/testdata/operators/and_empty_block.carbon new file mode 100644 index 000000000000..dddb66340053 --- /dev/null +++ b/toolchain/lowering/testdata/operators/and_empty_block.carbon @@ -0,0 +1,24 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'and_empty_block.carbon' +// CHECK:STDOUT: source_filename = "and_empty_block.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @And(i1 %b, i1 %c) { +// CHECK:STDOUT: br i1 %b, label %1, label %2 +// CHECK:STDOUT: +// CHECK:STDOUT: 1: ; preds = %0 +// CHECK:STDOUT: br label %2 +// CHECK:STDOUT: +// CHECK:STDOUT: 2: ; preds = %1, %0 +// CHECK:STDOUT: %3 = phi i1 [ false, %0 ], [ %c, %1 ] +// CHECK:STDOUT: ret i1 %3 +// CHECK:STDOUT: } + +fn And(b: bool, c: bool) -> bool { + // Note that in this case, we must generate an empty block so that the `phi` + // has two distinct predecessors. + return b and c; +} diff --git a/toolchain/lowering/testdata/operators/not.carbon b/toolchain/lowering/testdata/operators/not.carbon index 470b4e3f1494..4a01e698dc2d 100644 --- a/toolchain/lowering/testdata/operators/not.carbon +++ b/toolchain/lowering/testdata/operators/not.carbon @@ -7,9 +7,8 @@ // CHECK:STDOUT: source_filename = "not.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i1 @Not(i1 %b) { -// CHECK:STDOUT: entry: -// CHECK:STDOUT: %0 = xor i1 %b, true -// CHECK:STDOUT: ret i1 %0 +// CHECK:STDOUT: %1 = xor i1 %b, true +// CHECK:STDOUT: ret i1 %1 // CHECK:STDOUT: } fn Not(b: bool) -> bool { diff --git a/toolchain/lowering/testdata/operators/or.carbon b/toolchain/lowering/testdata/operators/or.carbon new file mode 100644 index 000000000000..0db082c5928e --- /dev/null +++ b/toolchain/lowering/testdata/operators/or.carbon @@ -0,0 +1,36 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'or.carbon' +// CHECK:STDOUT: source_filename = "or.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @F() { +// CHECK:STDOUT: ret i1 true +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @G() { +// CHECK:STDOUT: ret i1 true +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @Or() { +// CHECK:STDOUT: %F = call i1 @F() +// CHECK:STDOUT: %1 = xor i1 %F, true +// CHECK:STDOUT: br i1 %1, label %2, label %3 +// CHECK:STDOUT: +// CHECK:STDOUT: 2: ; preds = %0 +// CHECK:STDOUT: %G = call i1 @G() +// CHECK:STDOUT: br label %3 +// CHECK:STDOUT: +// CHECK:STDOUT: 3: ; preds = %2, %0 +// CHECK:STDOUT: %4 = phi i1 [ true, %0 ], [ %G, %2 ] +// CHECK:STDOUT: ret i1 %4 +// CHECK:STDOUT: } + +fn F() -> bool { return true; } +fn G() -> bool { return true; } + +fn Or() -> bool { + return F() or G(); +} diff --git a/toolchain/lowering/testdata/operators/or_empty_block.carbon b/toolchain/lowering/testdata/operators/or_empty_block.carbon new file mode 100644 index 000000000000..e509831c1ff7 --- /dev/null +++ b/toolchain/lowering/testdata/operators/or_empty_block.carbon @@ -0,0 +1,25 @@ +// 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 +// +// AUTOUPDATE +// CHECK:STDOUT: ; ModuleID = 'or_empty_block.carbon' +// CHECK:STDOUT: source_filename = "or_empty_block.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define i1 @Or(i1 %b, i1 %c) { +// CHECK:STDOUT: %1 = xor i1 %b, true +// CHECK:STDOUT: br i1 %1, label %2, label %3 +// CHECK:STDOUT: +// CHECK:STDOUT: 2: ; preds = %0 +// CHECK:STDOUT: br label %3 +// CHECK:STDOUT: +// CHECK:STDOUT: 3: ; preds = %2, %0 +// CHECK:STDOUT: %4 = phi i1 [ true, %0 ], [ %c, %2 ] +// CHECK:STDOUT: ret i1 %4 +// CHECK:STDOUT: } + +fn Or(b: bool, c: bool) -> bool { + // Note that in this case, we must generate an empty block so that the `phi` + // has two distinct predecessors. + return b or c; +} diff --git a/toolchain/lowering/testdata/return/no_value.carbon b/toolchain/lowering/testdata/return/no_value.carbon index e8b26e61f33d..d7bb9afbc8f6 100644 --- a/toolchain/lowering/testdata/return/no_value.carbon +++ b/toolchain/lowering/testdata/return/no_value.carbon @@ -9,7 +9,6 @@ // CHECK:STDOUT: %EmptyTupleType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define %EmptyTupleType @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/return/value.carbon b/toolchain/lowering/testdata/return/value.carbon index 41602f972ac1..ce78329f247d 100644 --- a/toolchain/lowering/testdata/return/value.carbon +++ b/toolchain/lowering/testdata/return/value.carbon @@ -7,7 +7,6 @@ // CHECK:STDOUT: source_filename = "value.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/return/var.carbon b/toolchain/lowering/testdata/return/var.carbon index 05606674dbaa..918498b714c7 100644 --- a/toolchain/lowering/testdata/return/var.carbon +++ b/toolchain/lowering/testdata/return/var.carbon @@ -7,11 +7,10 @@ // CHECK:STDOUT: source_filename = "var.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Main() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %var = alloca i32, align 4 // CHECK:STDOUT: store i32 0, ptr %var, align 4 -// CHECK:STDOUT: %0 = load i32, ptr %var, align 4 -// CHECK:STDOUT: ret i32 %0 +// CHECK:STDOUT: %1 = load i32, ptr %var, align 4 +// CHECK:STDOUT: ret i32 %1 // CHECK:STDOUT: } fn Main() -> i32 { diff --git a/toolchain/lowering/testdata/struct/empty.carbon b/toolchain/lowering/testdata/struct/empty.carbon index bef9a7ad3512..423e3bc37d09 100644 --- a/toolchain/lowering/testdata/struct/empty.carbon +++ b/toolchain/lowering/testdata/struct/empty.carbon @@ -9,16 +9,15 @@ // CHECK:STDOUT: %StructLiteralType = type {} // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Run() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %StructLiteralValue = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %var = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %StructLiteralValue1 = alloca %StructLiteralType, align 8 -// CHECK:STDOUT: %0 = load %StructLiteralType, ptr %StructLiteralValue1, align 1 -// CHECK:STDOUT: store %StructLiteralType %0, ptr %var, align 1 +// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %StructLiteralValue1, align 1 +// CHECK:STDOUT: store %StructLiteralType %1, ptr %var, align 1 // CHECK:STDOUT: %StructLiteralValue2 = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %var3 = alloca %StructLiteralType, align 8 -// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %var, align 1 -// CHECK:STDOUT: store %StructLiteralType %1, ptr %var3, align 1 +// CHECK:STDOUT: %2 = load %StructLiteralType, ptr %var, align 1 +// CHECK:STDOUT: store %StructLiteralType %2, ptr %var3, align 1 // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/struct/member_access.carbon b/toolchain/lowering/testdata/struct/member_access.carbon index 353a391023be..db84f3c27268 100644 --- a/toolchain/lowering/testdata/struct/member_access.carbon +++ b/toolchain/lowering/testdata/struct/member_access.carbon @@ -9,22 +9,21 @@ // CHECK:STDOUT: %StructLiteralType = type { double, i32 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Run() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %var = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %StructLiteralValue = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %a = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 0 // CHECK:STDOUT: store double 0.000000e+00, ptr %a, align 8 // CHECK:STDOUT: %b = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 1 // CHECK:STDOUT: store i32 1, ptr %b, align 4 -// CHECK:STDOUT: %0 = load %StructLiteralType, ptr %StructLiteralValue, align 8 -// CHECK:STDOUT: store %StructLiteralType %0, ptr %var, align 8 +// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %StructLiteralValue, align 8 +// CHECK:STDOUT: store %StructLiteralType %1, ptr %var, align 8 // CHECK:STDOUT: %var1 = alloca i32, align 4 // CHECK:STDOUT: %b2 = getelementptr inbounds %StructLiteralType, ptr %var, i32 0, i32 1 -// CHECK:STDOUT: %1 = load i32, ptr %b2, align 4 -// CHECK:STDOUT: store i32 %1, ptr %var1, align 4 +// CHECK:STDOUT: %2 = load i32, ptr %b2, align 4 +// CHECK:STDOUT: store i32 %2, ptr %var1, align 4 // CHECK:STDOUT: %var3 = alloca i32, align 4 -// CHECK:STDOUT: %2 = load i32, ptr %var1, align 4 -// CHECK:STDOUT: store i32 %2, ptr %var3, align 4 +// CHECK:STDOUT: %3 = load i32, ptr %var1, align 4 +// CHECK:STDOUT: store i32 %3, ptr %var3, align 4 // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/struct/one_entry.carbon b/toolchain/lowering/testdata/struct/one_entry.carbon index e0c5541ed9c8..a7f96e668312 100644 --- a/toolchain/lowering/testdata/struct/one_entry.carbon +++ b/toolchain/lowering/testdata/struct/one_entry.carbon @@ -9,16 +9,15 @@ // CHECK:STDOUT: %StructLiteralType = type { i32 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Run() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %var = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %StructLiteralValue = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %a = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 0 // CHECK:STDOUT: store i32 4, ptr %a, align 4 -// CHECK:STDOUT: %0 = load %StructLiteralType, ptr %StructLiteralValue, align 4 -// CHECK:STDOUT: store %StructLiteralType %0, ptr %var, align 4 +// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %StructLiteralValue, align 4 +// CHECK:STDOUT: store %StructLiteralType %1, ptr %var, align 4 // CHECK:STDOUT: %var1 = alloca %StructLiteralType, align 8 -// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %var, align 4 -// CHECK:STDOUT: store %StructLiteralType %1, ptr %var1, align 4 +// CHECK:STDOUT: %2 = load %StructLiteralType, ptr %var, align 4 +// CHECK:STDOUT: store %StructLiteralType %2, ptr %var1, align 4 // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/struct/two_entries.carbon b/toolchain/lowering/testdata/struct/two_entries.carbon index 46087677bafa..0cb32243153a 100644 --- a/toolchain/lowering/testdata/struct/two_entries.carbon +++ b/toolchain/lowering/testdata/struct/two_entries.carbon @@ -9,18 +9,17 @@ // CHECK:STDOUT: %StructLiteralType = type { i32, i32 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Run() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %var = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %StructLiteralValue = alloca %StructLiteralType, align 8 // CHECK:STDOUT: %a = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 0 // CHECK:STDOUT: store i32 1, ptr %a, align 4 // CHECK:STDOUT: %b = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 1 // CHECK:STDOUT: store i32 2, ptr %b, align 4 -// CHECK:STDOUT: %0 = load %StructLiteralType, ptr %StructLiteralValue, align 4 -// CHECK:STDOUT: store %StructLiteralType %0, ptr %var, align 4 +// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %StructLiteralValue, align 4 +// CHECK:STDOUT: store %StructLiteralType %1, ptr %var, align 4 // CHECK:STDOUT: %var1 = alloca %StructLiteralType, align 8 -// CHECK:STDOUT: %1 = load %StructLiteralType, ptr %var, align 4 -// CHECK:STDOUT: store %StructLiteralType %1, ptr %var1, align 4 +// CHECK:STDOUT: %2 = load %StructLiteralType, ptr %var, align 4 +// CHECK:STDOUT: store %StructLiteralType %2, ptr %var1, align 4 // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } diff --git a/toolchain/lowering/testdata/var/local.carbon b/toolchain/lowering/testdata/var/local.carbon index f98b51ab6d3a..d857c0c89a13 100644 --- a/toolchain/lowering/testdata/var/local.carbon +++ b/toolchain/lowering/testdata/var/local.carbon @@ -7,11 +7,10 @@ // CHECK:STDOUT: source_filename = "local.carbon" // CHECK:STDOUT: // CHECK:STDOUT: define i32 @Run() { -// CHECK:STDOUT: entry: // CHECK:STDOUT: %var = alloca i32, align 4 // CHECK:STDOUT: store i32 1, ptr %var, align 4 -// CHECK:STDOUT: %0 = load i32, ptr %var, align 4 -// CHECK:STDOUT: ret i32 %0 +// CHECK:STDOUT: %1 = load i32, ptr %var, align 4 +// CHECK:STDOUT: ret i32 %1 // CHECK:STDOUT: } fn Run() -> i32 { diff --git a/toolchain/semantics/semantics_handle.cpp b/toolchain/semantics/semantics_handle.cpp index fb77b61d0bf7..15dc9cc890cb 100644 --- a/toolchain/semantics/semantics_handle.cpp +++ b/toolchain/semantics/semantics_handle.cpp @@ -228,7 +228,8 @@ auto SemanticsHandleInfixOperator(SemanticsContext& context, context.AddNodeAndPush( parse_node, SemanticsNode::BlockArg::Make( - parse_node, context.semantics_ir().GetNode(rhs_id).type_id())); + parse_node, context.semantics_ir().GetNode(rhs_id).type_id(), + resume_block_id)); break; } diff --git a/toolchain/semantics/semantics_handle_if_expression.cpp b/toolchain/semantics/semantics_handle_if_expression.cpp index 90dfe3ff47b6..db6b32e8b522 100644 --- a/toolchain/semantics/semantics_handle_if_expression.cpp +++ b/toolchain/semantics/semantics_handle_if_expression.cpp @@ -68,7 +68,8 @@ auto SemanticsHandleIfExpressionElse(SemanticsContext& context, // Obtain the value in the resumption block and push it. context.AddNodeAndPush( - if_node, SemanticsNode::BlockArg::Make(if_node, result_type_id)); + if_node, + SemanticsNode::BlockArg::Make(if_node, result_type_id, resume_block_id)); return true; } diff --git a/toolchain/semantics/semantics_node.h b/toolchain/semantics/semantics_node.h index 6017ce5f76f6..a74840ec9887 100644 --- a/toolchain/semantics/semantics_node.h +++ b/toolchain/semantics/semantics_node.h @@ -285,7 +285,8 @@ class SemanticsNode { SemanticsStringId /*name_id*/, SemanticsNodeId /*node_id*/>; - using BlockArg = Factory; + using BlockArg = + Factory; using BoolLiteral = Factory; @@ -450,6 +451,9 @@ struct SemanticsIdMapInfo { // Support use of Id types as DenseMap/DenseSet keys. template <> +struct llvm::DenseMapInfo + : public Carbon::SemanticsIdMapInfo {}; +template <> struct llvm::DenseMapInfo : public Carbon::SemanticsIdMapInfo {}; template <> diff --git a/toolchain/semantics/testdata/if_expression/basic.carbon b/toolchain/semantics/testdata/if_expression/basic.carbon index ca2c2fe1f11c..28a0b60a4a09 100644 --- a/toolchain/semantics/testdata/if_expression/basic.carbon +++ b/toolchain/semantics/testdata/if_expression/basic.carbon @@ -35,7 +35,7 @@ // CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+4, arg1: node+2, type: type1}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+9}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+10}, -// CHECK:STDOUT: {kind: BlockArg, type: type1}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block7, type: type1}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+13, type: type1}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ diff --git a/toolchain/semantics/testdata/if_expression/constant_condition.carbon b/toolchain/semantics/testdata/if_expression/constant_condition.carbon index e2163dfe53ba..dd3e735bebd1 100644 --- a/toolchain/semantics/testdata/if_expression/constant_condition.carbon +++ b/toolchain/semantics/testdata/if_expression/constant_condition.carbon @@ -41,7 +41,7 @@ // CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+10}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block7, arg1: node+11}, -// CHECK:STDOUT: {kind: BlockArg, type: type0}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block7, type: type0}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+14, type: type0}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function3}, // CHECK:STDOUT: {kind: BoolLiteral, arg0: false, type: type1}, @@ -51,7 +51,7 @@ // CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block11, arg1: node+20}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block11, arg1: node+21}, -// CHECK:STDOUT: {kind: BlockArg, type: type0}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block11, type: type0}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+24, type: type0}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ diff --git a/toolchain/semantics/testdata/if_expression/control_flow.carbon b/toolchain/semantics/testdata/if_expression/control_flow.carbon index deadb0688725..f80d766db11d 100644 --- a/toolchain/semantics/testdata/if_expression/control_flow.carbon +++ b/toolchain/semantics/testdata/if_expression/control_flow.carbon @@ -41,7 +41,7 @@ // CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+11}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+12}, -// CHECK:STDOUT: {kind: BlockArg, type: type0}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block9, type: type0}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+15, type: type0}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ diff --git a/toolchain/semantics/testdata/if_expression/nested.carbon b/toolchain/semantics/testdata/if_expression/nested.carbon index da14e4d65702..f37aade769c0 100644 --- a/toolchain/semantics/testdata/if_expression/nested.carbon +++ b/toolchain/semantics/testdata/if_expression/nested.carbon @@ -41,17 +41,17 @@ // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type1}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+11}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block9, arg1: node+12}, -// CHECK:STDOUT: {kind: BlockArg, type: type1}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block9, type: type1}, // CHECK:STDOUT: {kind: BranchIf, arg0: block11, arg1: node+4}, // CHECK:STDOUT: {kind: Branch, arg0: block10}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: type1}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: type1}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block12, arg1: node+18}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block12, arg1: node+19}, -// CHECK:STDOUT: {kind: BlockArg, type: type1}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block12, type: type1}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block13, arg1: node+15}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block13, arg1: node+22}, -// CHECK:STDOUT: {kind: BlockArg, type: type1}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block13, type: type1}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+25, type: type1}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ diff --git a/toolchain/semantics/testdata/operators/and.carbon b/toolchain/semantics/testdata/operators/and.carbon index c2e6d51e95f2..a7156511aae2 100644 --- a/toolchain/semantics/testdata/operators/and.carbon +++ b/toolchain/semantics/testdata/operators/and.carbon @@ -35,7 +35,7 @@ // CHECK:STDOUT: {kind: BranchWithArg, arg0: block5, arg1: node+8}, // CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block5, arg1: node+11}, -// CHECK:STDOUT: {kind: BlockArg, type: type0}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block5, type: type0}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+13, type: type0}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ diff --git a/toolchain/semantics/testdata/operators/or.carbon b/toolchain/semantics/testdata/operators/or.carbon index 35139c906032..fd5106c974df 100644 --- a/toolchain/semantics/testdata/operators/or.carbon +++ b/toolchain/semantics/testdata/operators/or.carbon @@ -36,7 +36,7 @@ // CHECK:STDOUT: {kind: BranchWithArg, arg0: block5, arg1: node+9}, // CHECK:STDOUT: {kind: Call, arg0: block0, arg1: function1, type: type0}, // CHECK:STDOUT: {kind: BranchWithArg, arg0: block5, arg1: node+12}, -// CHECK:STDOUT: {kind: BlockArg, type: type0}, +// CHECK:STDOUT: {kind: BlockArg, arg0: block5, type: type0}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+14, type: type0}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [