From 79c0b65288a8f0d365f78c5051e24483d64ce6d3 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 26 Apr 2024 16:27:07 -0700 Subject: [PATCH] Separate constant emission from function emission. (#3916) Make constant emission non-recursive, and stop building a bogus FunctionContext to emit constants. To support this, move `InstConstantKind` from the typed instruction definition into the `.def` file, and add more macros to allow us to generate case labels based on whether an instruction is a constant. --------- Co-authored-by: Jon Ross-Perkins Co-authored-by: Carbon Infra Bot --- toolchain/check/context.cpp | 1 + toolchain/lower/BUILD | 2 + toolchain/lower/constant.cpp | 271 ++++++++++++++++++ toolchain/lower/constant.h | 22 ++ toolchain/lower/file_context.cpp | 71 +++-- toolchain/lower/file_context.h | 13 +- toolchain/lower/function_context.cpp | 14 +- toolchain/lower/function_context.h | 4 +- toolchain/lower/handle.cpp | 62 ---- toolchain/lower/handle_aggregates.cpp | 61 +--- toolchain/lower/handle_type.cpp | 65 +---- .../testdata/array/assign_return_value.carbon | 4 +- toolchain/lower/testdata/array/base.carbon | 19 +- .../testdata/array/function_param.carbon | 4 +- .../testdata/basics/numeric_literals.carbon | 8 +- toolchain/lower/testdata/class/adapt.carbon | 7 +- toolchain/lower/testdata/class/base.carbon | 5 +- .../function/call/struct_param.carbon | 4 +- .../testdata/function/call/tuple_param.carbon | 4 +- .../call/tuple_param_with_return_slot.carbon | 6 +- .../index/array_element_access.carbon | 9 +- .../index/tuple_element_access.carbon | 9 +- .../index/tuple_return_value_access.carbon | 4 +- toolchain/lower/testdata/let/tuple.carbon | 10 +- .../testdata/operators/assignment.carbon | 7 +- .../testdata/pointer/address_of_field.carbon | 7 +- .../testdata/struct/member_access.carbon | 7 +- .../lower/testdata/struct/two_entries.carbon | 7 +- .../lower/testdata/tuple/one_entry.carbon | 3 + .../lower/testdata/tuple/two_entries.carbon | 4 +- toolchain/sem_ir/constant.h | 5 + toolchain/sem_ir/file.cpp | 1 + toolchain/sem_ir/inst_kind.cpp | 8 +- toolchain/sem_ir/inst_kind.def | 205 +++++++------ toolchain/sem_ir/inst_kind.h | 29 +- toolchain/sem_ir/typed_insts.h | 132 ++++----- 36 files changed, 625 insertions(+), 469 deletions(-) create mode 100644 toolchain/lower/constant.cpp create mode 100644 toolchain/lower/constant.h diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 645710c8daba..c0a1c7431f90 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -941,6 +941,7 @@ class TypeCompleter { -> SemIR::ValueRepr { CARBON_KIND_SWITCH(inst) { #define CARBON_SEM_IR_INST_KIND_TYPE(...) +#define CARBON_SEM_IR_INST_KIND_MAYBE_TYPE(...) #define CARBON_SEM_IR_INST_KIND(Name) case SemIR::Name::Kind: #include "toolchain/sem_ir/inst_kind.def" CARBON_FATAL() << "Type refers to non-type inst " << inst; diff --git a/toolchain/lower/BUILD b/toolchain/lower/BUILD index 7cdc875026a1..c057fa608011 100644 --- a/toolchain/lower/BUILD +++ b/toolchain/lower/BUILD @@ -28,6 +28,8 @@ cc_library( cc_library( name = "context", srcs = [ + "constant.cpp", + "constant.h", "file_context.cpp", "function_context.cpp", ] + diff --git a/toolchain/lower/constant.cpp b/toolchain/lower/constant.cpp new file mode 100644 index 000000000000..eaaa2945e9cc --- /dev/null +++ b/toolchain/lower/constant.cpp @@ -0,0 +1,271 @@ +// 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 "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Value.h" +#include "toolchain/lower/file_context.h" +#include "toolchain/sem_ir/inst.h" + +namespace Carbon::Lower { + +// Context and shared functionality for lowering constant values. +class ConstantContext { + public: + explicit ConstantContext(FileContext& file_context, + llvm::MutableArrayRef constants) + : file_context_(&file_context), constants_(constants) {} + + // Gets the lowered constant value for an instruction, which must have a + // constant value that has already been lowered. + auto GetConstant(SemIR::InstId inst_id) const -> llvm::Constant* { + return GetConstant(file_context_->sem_ir().constant_values().Get(inst_id)); + } + + // Gets the lowered constant value for a constant that has already been + // lowered. + auto GetConstant(SemIR::ConstantId const_id) const -> llvm::Constant* { + CARBON_CHECK(const_id.is_template() && const_id.inst_id().index >= 0) + << "Unexpected constant ID " << const_id; + CARBON_CHECK(const_id.inst_id().index <= last_lowered_constant_index_) + << "Queried constant " << const_id << " that has not been lowered yet"; + return constants_[const_id.inst_id().index]; + } + + // Returns a constant for the case of a value that should never be used. + auto GetUnusedConstant(SemIR::TypeId /*type_id*/) const -> llvm::Constant* { + // TODO: Consider using a poison value of the appropriate type. + return nullptr; + } + + // Gets a callable's function. Returns nullptr for a builtin. + auto GetFunction(SemIR::FunctionId function_id) -> llvm::Function* { + return file_context_->GetFunction(function_id); + } + + // Returns a lowered type for the given type_id. + auto GetType(SemIR::TypeId type_id) const -> llvm::Type* { + return file_context_->GetType(type_id); + } + + // Returns a lowered value to use for a value of type `type`. + auto GetTypeAsValue() const -> llvm::Constant* { + return file_context_->GetTypeAsValue(); + } + + // Sets the index of the constant we most recently lowered. This is used to + // check we don't look at constants that we've not lowered yet. + auto SetLastLoweredConstantIndex(int32_t index) { + last_lowered_constant_index_ = index; + } + + auto llvm_context() const -> llvm::LLVMContext& { + return file_context_->llvm_context(); + } + auto llvm_module() const -> llvm::Module& { + return file_context_->llvm_module(); + } + auto sem_ir() const -> const SemIR::File& { return file_context_->sem_ir(); } + + private: + FileContext* file_context_; + llvm::MutableArrayRef constants_; + int32_t last_lowered_constant_index_ = -1; +}; + +// For each instruction kind that can produce a constant, there is a function +// below to convert it to an `llvm::Constant*`: +// +// auto EmitAsConstant(ConstantContext& context, +// SemIR:: inst) -> llvm::Constant*; + +// For constants that are always of type `type`, produce the trivial runtime +// representation of type `type`. +#define CARBON_SEM_IR_INST_KIND_NOT_TYPE(...) +#define CARBON_SEM_IR_INST_KIND_MAYBE_TYPE(...) +#define CARBON_SEM_IR_INST_KIND_CONSTANT_SYMBOLIC_ONLY(...) +#define CARBON_SEM_IR_INST_KIND(Name) \ + static auto Emit##Name##AsConstant( \ + ConstantContext& context, SemIR::Name /*inst*/) -> llvm::Constant* { \ + return context.GetTypeAsValue(); \ + } +#include "toolchain/sem_ir/inst_kind.def" + +// Emits an aggregate constant of LLVM type `Type` whose elements are the +// contents of `refs_id`. +template +static auto EmitAggregateConstant(ConstantContext& context, + SemIR::InstBlockId refs_id, Type* llvm_type) + -> llvm::Constant* { + auto refs = context.sem_ir().inst_blocks().Get(refs_id); + llvm::SmallVector elements; + elements.reserve(refs.size()); + for (auto ref : refs) { + elements.push_back(context.GetConstant(ref)); + } + + return ConstantType::get(llvm_type, elements); +} + +static auto EmitStructValueAsConstant(ConstantContext& context, + SemIR::StructValue inst) + -> llvm::Constant* { + return EmitAggregateConstant( + context, inst.elements_id, + cast(context.GetType(inst.type_id))); +} + +static auto EmitTupleValueAsConstant(ConstantContext& context, + SemIR::TupleValue inst) + -> llvm::Constant* { + // TODO: Add an ArrayValue instruction and stop using TupleValues to represent + // array constants. + if (context.sem_ir().types().Is(inst.type_id)) { + return EmitAggregateConstant( + context, inst.elements_id, + cast(context.GetType(inst.type_id))); + } + + return EmitAggregateConstant( + context, inst.elements_id, + cast(context.GetType(inst.type_id))); +} + +static auto EmitAddrOfAsConstant(ConstantContext& /*context*/, + SemIR::AddrOf /*inst*/) -> llvm::Constant* { + // TODO: Constant lvalue support. For now we have no constant lvalues, so we + // should never form a constant AddrOf. + CARBON_FATAL() << "AddrOf constants not supported yet"; +} + +static auto EmitAssociatedEntityAsConstant(ConstantContext& context, + SemIR::AssociatedEntity inst) + -> llvm::Constant* { + return context.GetUnusedConstant(inst.type_id); +} + +static auto EmitBaseDeclAsConstant(ConstantContext& context, + SemIR::BaseDecl inst) -> llvm::Constant* { + return context.GetUnusedConstant(inst.type_id); +} + +static auto EmitBoolLiteralAsConstant(ConstantContext& context, + SemIR::BoolLiteral inst) + -> llvm::Constant* { + return llvm::ConstantInt::get(llvm::Type::getInt1Ty(context.llvm_context()), + inst.value.index); +} + +static auto EmitBoundMethodAsConstant(ConstantContext& context, + SemIR::BoundMethod inst) + -> llvm::Constant* { + // Propagate just the function; the object is separately provided to the + // enclosing call as an implicit argument. + return context.GetConstant(inst.function_id); +} + +static auto EmitFieldDeclAsConstant(ConstantContext& context, + SemIR::FieldDecl inst) -> llvm::Constant* { + return context.GetUnusedConstant(inst.type_id); +} + +static auto EmitFloatLiteralAsConstant(ConstantContext& context, + SemIR::FloatLiteral inst) + -> llvm::Constant* { + const llvm::APFloat& value = context.sem_ir().floats().Get(inst.float_id); + return llvm::ConstantFP::get(context.GetType(inst.type_id), value); +} + +static auto EmitFunctionDeclAsConstant(ConstantContext& context, + SemIR::FunctionDecl inst) + -> llvm::Constant* { + // TODO: Add a FunctionValue that FunctionDecl evaluates to, and remove this. + return context.GetFunction(inst.function_id); +} + +static auto EmitInterfaceWitnessAsConstant(ConstantContext& context, + SemIR::InterfaceWitness inst) + -> llvm::Constant* { + // TODO: For dynamic dispatch, we might want to lower witness tables as + // constants. + return context.GetUnusedConstant(inst.type_id); +} + +static auto EmitIntLiteralAsConstant(ConstantContext& context, + SemIR::IntLiteral inst) + -> llvm::Constant* { + return llvm::ConstantInt::get(context.GetType(inst.type_id), + context.sem_ir().ints().Get(inst.int_id)); +} + +static auto EmitNamespaceAsConstant(ConstantContext& context, + SemIR::Namespace inst) -> llvm::Constant* { + return context.GetUnusedConstant(inst.type_id); +} + +static auto EmitRealLiteralAsConstant(ConstantContext& context, + SemIR::RealLiteral inst) + -> llvm::Constant* { + const Real& real = context.sem_ir().reals().Get(inst.real_id); + // TODO: This will probably have overflow issues, and should be fixed. + double val = + real.mantissa.getZExtValue() * + std::pow((real.is_decimal ? 10 : 2), real.exponent.getSExtValue()); + llvm::APFloat llvm_val(val); + return llvm::ConstantFP::get(context.GetType(inst.type_id), llvm_val); +} + +static auto EmitStringLiteralAsConstant(ConstantContext& /*context*/, + SemIR::StringLiteral inst) + -> llvm::Constant* { + CARBON_FATAL() << "TODO: Add support: " << inst; +} + +static auto EmitStructTypeFieldAsConstant(ConstantContext& /*context*/, + SemIR::StructTypeField /*inst*/) + -> llvm::Constant* { + // A StructTypeField isn't a value, so this constant value won't ever be used. + // It also doesn't even have a type, so we can't use GetUnusedConstant. + return nullptr; +} + +auto LowerConstants(FileContext& file_context, + llvm::MutableArrayRef constants) -> void { + ConstantContext context(file_context, constants); + // Lower each constant in InstId order. This guarantees we lower the + // dependencies of a constant before we lower the constant itself. + for (auto [inst_id_val, const_id] : + llvm::enumerate(file_context.sem_ir().constant_values().array_ref())) { + if (!const_id.is_valid() || !const_id.is_template()) { + // We are only interested in lowering template constants. + continue; + } + + if (const_id.inst_id().index != static_cast(inst_id_val)) { + // This isn't the instruction that defines the constant. + continue; + } + + auto inst = file_context.sem_ir().insts().Get(const_id.inst_id()); + llvm::Constant* value = nullptr; + switch (inst.kind()) { +#define CARBON_SEM_IR_INST_KIND_CONSTANT_NEVER(...) +#define CARBON_SEM_IR_INST_KIND_CONSTANT_SYMBOLIC_ONLY(...) +#define CARBON_SEM_IR_INST_KIND(Name) \ + case SemIR::Name::Kind: \ + value = Emit##Name##AsConstant(context, inst.As()); \ + break; +#include "toolchain/sem_ir/inst_kind.def" + + default: + CARBON_FATAL() << "Unexpected constant instruction kind " << inst; + } + + constants[const_id.inst_id().index] = value; + context.SetLastLoweredConstantIndex(const_id.inst_id().index); + } +} + +} // namespace Carbon::Lower diff --git a/toolchain/lower/constant.h b/toolchain/lower/constant.h new file mode 100644 index 000000000000..efda42ac6443 --- /dev/null +++ b/toolchain/lower/constant.h @@ -0,0 +1,22 @@ +// 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_LOWER_CONSTANT_H_ +#define CARBON_TOOLCHAIN_LOWER_CONSTANT_H_ + +#include "llvm/ADT/ArrayRef.h" +#include "toolchain/lower/file_context.h" + +namespace Carbon::Lower { + +// Forms LLVM constant values for all constants used in the file described by +// `file_context`. The indexes in the `constants` array corresponding to +// template constant instructions are populated with corresponding constant +// values. +auto LowerConstants(FileContext& file_context, + llvm::MutableArrayRef constants) -> void; + +} // namespace Carbon::Lower + +#endif // CARBON_TOOLCHAIN_LOWER_CONSTANT_H_ diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 02c289fa46c8..feecdb006251 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -8,6 +8,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" #include "toolchain/base/kind_switch.h" +#include "toolchain/lower/constant.h" #include "toolchain/lower/function_context.h" #include "toolchain/sem_ir/entry_point.h" #include "toolchain/sem_ir/file.h" @@ -50,6 +51,10 @@ auto FileContext::Run() -> std::unique_ptr { // TODO: Lower global variable declarations. + // Lower constants. + constants_.resize(sem_ir_->insts().size()); + LowerConstants(*this, constants_); + // Lower function definitions. for (auto i : llvm::seq(sem_ir_->functions().size())) { BuildFunctionDefinition(SemIR::FunctionId(i)); @@ -61,49 +66,38 @@ auto FileContext::Run() -> std::unique_ptr { } auto FileContext::GetGlobal(SemIR::InstId inst_id) -> llvm::Value* { + auto inst = sem_ir().insts().Get(inst_id); + auto const_id = sem_ir().constant_values().Get(inst_id); - if (const_id.is_constant()) { - inst_id = const_id.inst_id(); - } + if (const_id.is_template()) { + // For value expressions and initializing expressions, the value produced by + // a constant instruction is a value representation of the constant. For + // initializing expressions, `FinishInit` will perform a copy if needed. + // TODO: Handle reference expression constants. + auto* const_value = constants_[const_id.inst_id().index]; - // All builtins are types, with the same empty lowered value. - if (inst_id.is_builtin()) { - return GetTypeAsValue(); - } - - // TODO: Add a FunctionValue that FunctionDecl evaluates to, and remove this. - auto target = sem_ir().insts().Get(inst_id); - if (auto function_decl = target.TryAs()) { - return GetFunction(function_decl->function_id); - } - - if (target.Is() || target.Is() || - target.Is()) { - return llvm::ConstantStruct::getAnon(llvm_context(), {}); - } - - if (target.type_id() == SemIR::TypeId::TypeType) { - return GetTypeAsValue(); - } - - auto constant_id = sem_ir().constant_values().Get(inst_id); - if (constant_id.is_constant()) { - if (auto function_decl = sem_ir().insts().TryGetAs( - constant_id.inst_id())) { - return GetFunction(function_decl->function_id); + // If we want a pointer to the constant, materialize a global to hold it. + // TODO: We could reuse the same global if the constant is used more than + // once. + auto value_rep = SemIR::GetValueRepr(sem_ir(), inst.type_id()); + if (value_rep.kind == SemIR::ValueRepr::Pointer) { + llvm::StringRef name = + inst_namer_ ? inst_namer_->GetUnscopedNameFor(inst_id) : ""; + llvm::StringRef sep = (name.empty() || name[0] == '.') ? "" : "."; + return new llvm::GlobalVariable( + llvm_module(), GetType(sem_ir().GetPointeeType(value_rep.type_id)), + /*isConstant=*/true, llvm::GlobalVariable::InternalLinkage, + const_value, "const" + sep + name); } - auto* value = globals_.lookup(constant_id.inst_id()); - if (!value) { - // TODO: Less-hacky constant lowering. - FunctionContext ctx(*this, nullptr, vlog_stream_); - ctx.LowerInst(constant_id.inst_id()); - value = ctx.GetValue(constant_id.inst_id()); - globals_.insert({constant_id.inst_id(), value}); - } - return value; + + // Otherwise, we can use the constant value directly. + return const_value; } - CARBON_FATAL() << "Missing value: " << inst_id << " " << target; + // TODO: For generics, handle references to symbolic constants. + + CARBON_FATAL() << "Missing value: " << inst_id << " " + << sem_ir().insts().Get(inst_id); } auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id) @@ -389,6 +383,7 @@ auto FileContext::BuildType(SemIR::InstId inst_id) -> llvm::Type* { } #define CARBON_SEM_IR_INST_KIND_TYPE(...) +#define CARBON_SEM_IR_INST_KIND_MAYBE_TYPE(...) #define CARBON_SEM_IR_INST_KIND(Name) case SemIR::Name::Kind: #include "toolchain/sem_ir/inst_kind.def" CARBON_FATAL() << "Cannot use inst as type: " << inst_id << " " diff --git a/toolchain/lower/file_context.h b/toolchain/lower/file_context.h index af146c0c0aec..a6d45b33fdeb 100644 --- a/toolchain/lower/file_context.h +++ b/toolchain/lower/file_context.h @@ -42,7 +42,7 @@ class FileContext { } // Returns a lowered value to use for a value of type `type`. - auto GetTypeAsValue() -> llvm::Value* { + auto GetTypeAsValue() -> llvm::Constant* { return llvm::ConstantStruct::get(GetTypeType()); } @@ -91,16 +91,19 @@ class FileContext { // Maps callables to lowered functions. SemIR treats callables as the // canonical form of a function, so lowering needs to do the same. - llvm::SmallVector functions_; + // We resize this directly to the (often large) correct size. + llvm::SmallVector functions_; // Provides lowered versions of types. - llvm::SmallVector types_; + // We resize this directly to the (often large) correct size. + llvm::SmallVector types_; // Lowered version of the builtin type `type`. llvm::StructType* type_type_ = nullptr; - // Maps global instructions to their lowered values. - llvm::DenseMap globals_; + // Maps constants to their lowered values. + // We resize this directly to the (often large) correct size. + llvm::SmallVector constants_; }; } // namespace Carbon::Lower diff --git a/toolchain/lower/function_context.cpp b/toolchain/lower/function_context.cpp index a34136c025f4..fcb3a721be20 100644 --- a/toolchain/lower/function_context.cpp +++ b/toolchain/lower/function_context.cpp @@ -47,24 +47,30 @@ auto FunctionContext::TryToReuseBlock(SemIR::InstBlockId block_id, auto FunctionContext::LowerBlock(SemIR::InstBlockId block_id) -> void { for (auto inst_id : sem_ir().inst_blocks().Get(block_id)) { - // Skip over constants. `FileContext::GetGlobal` lowers them as needed. - if (sem_ir().constant_values().Get(inst_id).is_constant()) { - continue; - } LowerInst(inst_id); } } auto FunctionContext::LowerInst(SemIR::InstId inst_id) -> void { + // Skip over constants. `FileContext::GetGlobal` lowers them as needed. + if (sem_ir().constant_values().Get(inst_id).is_constant()) { + return; + } + auto inst = sem_ir().insts().Get(inst_id); CARBON_VLOG() << "Lowering " << inst_id << ": " << inst << "\n"; builder_.getInserter().SetCurrentInstId(inst_id); switch (inst.kind()) { +#define CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS(Name) #define CARBON_SEM_IR_INST_KIND(Name) \ case SemIR::Name::Kind: \ Handle##Name(*this, inst_id, inst.As()); \ break; #include "toolchain/sem_ir/inst_kind.def" + + default: + CARBON_FATAL() << "Missing constant value for constant instruction " + << inst; } builder_.getInserter().SetCurrentInstId(SemIR::InstId::Invalid); } diff --git a/toolchain/lower/function_context.h b/toolchain/lower/function_context.h index 0f6793a85ff8..301db488a1e5 100644 --- a/toolchain/lower/function_context.h +++ b/toolchain/lower/function_context.h @@ -160,7 +160,9 @@ class FunctionContext { llvm::DenseMap locals_; }; -// Declare handlers for each SemIR::File instruction. +// Declare handlers for each SemIR::File instruction that is not always +// constant. +#define CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS(Name) #define CARBON_SEM_IR_INST_KIND(Name) \ auto Handle##Name(FunctionContext& context, SemIR::InstId inst_id, \ SemIR::Name inst) -> void; diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index 1854b21df006..400657a9e1f9 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -77,12 +77,6 @@ auto HandleAssociatedConstantDecl(FunctionContext& /*context*/, FatalErrorIfEncountered(inst); } -auto HandleAssociatedEntity(FunctionContext& /*context*/, - SemIR::InstId /*inst_id*/, - SemIR::AssociatedEntity inst) -> void { - FatalErrorIfEncountered(inst); -} - auto HandleBindAlias(FunctionContext& context, SemIR::InstId inst_id, SemIR::BindAlias inst) -> void { auto type_inst_id = context.sem_ir().types().GetInstId(inst.type_id); @@ -108,13 +102,6 @@ auto HandleBlockArg(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetBlockArg(inst.block_id, inst.type_id)); } -auto HandleBoolLiteral(FunctionContext& context, SemIR::InstId inst_id, - SemIR::BoolLiteral inst) -> void { - llvm::Value* v = - llvm::ConstantInt::get(context.builder().getInt1Ty(), inst.value.index); - context.SetLocal(inst_id, v); -} - auto HandleBoundMethod(FunctionContext& context, SemIR::InstId inst_id, SemIR::BoundMethod inst) -> void { // Propagate just the function; the object is separately provided to the @@ -172,11 +159,6 @@ auto HandleBranchWithArg(FunctionContext& context, SemIR::InstId /*inst_id*/, context.builder().ClearInsertionPoint(); } -auto HandleBuiltin(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, - SemIR::Builtin inst) -> void { - CARBON_FATAL() << "TODO: Add support: " << inst; -} - // Get the predicate to use for an `icmp` instruction generated for the // specified builtin. static auto GetBuiltinICmpPredicate(SemIR::BuiltinFunctionKind builtin_kind, @@ -484,18 +466,6 @@ auto HandleDeref(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetValue(inst.pointer_id)); } -auto HandleFloatLiteral(FunctionContext& context, SemIR::InstId inst_id, - SemIR::FloatLiteral inst) -> void { - const llvm::APFloat& value = context.sem_ir().floats().Get(inst.float_id); - context.SetLocal( - inst_id, llvm::ConstantFP::get(context.builder().getDoubleTy(), value)); -} - -auto HandleFunctionDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, - SemIR::FunctionDecl inst) -> void { - FatalErrorIfEncountered(inst); -} - auto HandleImplDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, SemIR::ImplDecl inst) -> void { FatalErrorIfEncountered(inst); @@ -547,15 +517,6 @@ auto HandleInterfaceWitnessAccess(FunctionContext& context, context.SetLocal(inst_id, context.GetValue(const_id.inst_id())); } -auto HandleIntLiteral(FunctionContext& context, SemIR::InstId inst_id, - SemIR::IntLiteral inst) -> void { - const llvm::APInt& i = context.sem_ir().ints().Get(inst.int_id); - // TODO: This won't offer correct semantics, but seems close enough for now. - llvm::Value* v = - llvm::ConstantInt::get(context.builder().getInt32Ty(), i.getZExtValue()); - context.SetLocal(inst_id, v); -} - auto HandleNameRef(FunctionContext& context, SemIR::InstId inst_id, SemIR::NameRef inst) -> void { auto type_inst_id = context.sem_ir().types().GetInstId(inst.type_id); @@ -566,28 +527,11 @@ auto HandleNameRef(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetValue(inst.value_id)); } -auto HandleNamespace(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, - SemIR::Namespace inst) -> void { - FatalErrorIfEncountered(inst); -} - auto HandleParam(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, SemIR::Param /*inst*/) -> void { CARBON_FATAL() << "Parameters should be lowered by `BuildFunctionDefinition`"; } -auto HandleRealLiteral(FunctionContext& context, SemIR::InstId inst_id, - SemIR::RealLiteral inst) -> void { - const Real& real = context.sem_ir().reals().Get(inst.real_id); - // TODO: This will probably have overflow issues, and should be fixed. - double val = - real.mantissa.getZExtValue() * - std::pow((real.is_decimal ? 10 : 2), real.exponent.getSExtValue()); - llvm::APFloat llvm_val(val); - context.SetLocal(inst_id, llvm::ConstantFP::get( - context.builder().getDoubleTy(), llvm_val)); -} - auto HandleReturn(FunctionContext& context, SemIR::InstId /*inst_id*/, SemIR::Return /*inst*/) -> void { context.builder().CreateRetVoid(); @@ -618,12 +562,6 @@ auto HandleSpliceBlock(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetValue(inst.result_id)); } -auto HandleStringLiteral(FunctionContext& /*context*/, - SemIR::InstId /*inst_id*/, SemIR::StringLiteral inst) - -> void { - CARBON_FATAL() << "TODO: Add support: " << inst; -} - auto HandleUnaryOperatorNot(FunctionContext& context, SemIR::InstId inst_id, SemIR::UnaryOperatorNot inst) -> void { context.SetLocal( diff --git a/toolchain/lower/handle_aggregates.cpp b/toolchain/lower/handle_aggregates.cpp index 6139ee2e8a52..2b16c826f0c9 100644 --- a/toolchain/lower/handle_aggregates.cpp +++ b/toolchain/lower/handle_aggregates.cpp @@ -148,16 +148,6 @@ auto HandleClassInit(FunctionContext& context, SemIR::InstId inst_id, "class.init")); } -auto HandleBaseDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, - SemIR::BaseDecl /*inst*/) -> void { - // No action to perform. -} - -auto HandleFieldDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, - SemIR::FieldDecl /*inst*/) -> void { - // No action to perform. -} - auto HandleStructAccess(FunctionContext& context, SemIR::InstId inst_id, SemIR::StructAccess inst) -> void { auto struct_type_id = context.sem_ir().insts().Get(inst.struct_id).type_id(); @@ -203,47 +193,18 @@ auto EmitAggregateValueRepr(FunctionContext& context, SemIR::TypeId type_id, auto pointee_type_id = context.sem_ir().GetPointeeType(value_rep.type_id); auto* llvm_value_rep_type = context.GetType(pointee_type_id); - auto refs = context.sem_ir().inst_blocks().Get(refs_id); - if (context.builder().GetInsertBlock()) { - // Write the value representation to a local alloca so we can produce a - // pointer to it as the value representation of the struct or tuple. - auto* alloca = - context.builder().CreateAlloca(llvm_value_rep_type, - /*ArraySize=*/nullptr, name); - for (auto [i, ref] : llvm::enumerate(refs)) { - context.builder().CreateStore(context.GetValue(ref), - context.builder().CreateStructGEP( - llvm_value_rep_type, alloca, i)); - } - return alloca; - } else { - // TODO: Move this out to a separate constant lowering file. - llvm::SmallVector elements; - elements.reserve(refs.size()); - for (auto ref : refs) { - auto ref_value_rep = SemIR::GetValueRepr( - context.sem_ir(), context.sem_ir().insts().Get(ref).type_id()); - auto* inner_value = llvm::cast(context.GetValue(ref)); - if (ref_value_rep.kind == SemIR::ValueRepr::Pointer) { - inner_value = - llvm::cast(inner_value)->getInitializer(); - } - elements.push_back(inner_value); - } - llvm::Constant* value; - if (auto* struct_type = - llvm::dyn_cast(llvm_value_rep_type)) { - value = llvm::ConstantStruct::get(struct_type, elements); - } else if (auto* array_type = - llvm::dyn_cast(llvm_value_rep_type)) { - value = llvm::ConstantArray::get(array_type, elements); - } else { - CARBON_FATAL() << "Unknown aggregate value representation"; - } - return new llvm::GlobalVariable( - context.llvm_module(), llvm_value_rep_type, /*isConstant=*/true, - llvm::GlobalVariable::InternalLinkage, value, name); + // Write the value representation to a local alloca so we can produce a + // pointer to it as the value representation of the struct or tuple. + auto* alloca = + context.builder().CreateAlloca(llvm_value_rep_type, + /*ArraySize=*/nullptr, name); + for (auto [i, ref] : + llvm::enumerate(context.sem_ir().inst_blocks().Get(refs_id))) { + context.builder().CreateStore( + context.GetValue(ref), + context.builder().CreateStructGEP(llvm_value_rep_type, alloca, i)); } + return alloca; } case SemIR::ValueRepr::Custom: diff --git a/toolchain/lower/handle_type.cpp b/toolchain/lower/handle_type.cpp index 0cdbc547e3f2..66609c219429 100644 --- a/toolchain/lower/handle_type.cpp +++ b/toolchain/lower/handle_type.cpp @@ -7,64 +7,21 @@ namespace Carbon::Lower { -auto HandleArrayType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::ArrayType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleAssociatedEntityType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::AssociatedEntityType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleClassType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::ClassType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleConstType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::ConstType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} +// For instructions that are always of type `type`, produce the trivial runtime +// representation of type `type`. +#define CARBON_SEM_IR_INST_KIND_NOT_TYPE(...) +#define CARBON_SEM_IR_INST_KIND_MAYBE_TYPE(...) +#define CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS(...) +#define CARBON_SEM_IR_INST_KIND(Name) \ + auto Handle##Name(FunctionContext& context, SemIR::InstId inst_id, \ + SemIR::Name /*inst*/) -> void { \ + context.SetLocal(inst_id, context.GetTypeAsValue()); \ + } +#include "toolchain/sem_ir/inst_kind.def" auto HandleFacetTypeAccess(FunctionContext& context, SemIR::InstId inst_id, SemIR::FacetTypeAccess /*inst*/) -> void { context.SetLocal(inst_id, context.GetTypeAsValue()); } -auto HandleFloatType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::FloatType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleInterfaceType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::InterfaceType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleIntType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::IntType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandlePointerType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::PointerType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleStructType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::StructType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleTupleType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::TupleType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - -auto HandleUnboundElementType(FunctionContext& context, SemIR::InstId inst_id, - SemIR::UnboundElementType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - } // namespace Carbon::Lower diff --git a/toolchain/lower/testdata/array/assign_return_value.carbon b/toolchain/lower/testdata/array/assign_return_value.carbon index 376bdd97587e..ac12ae4e3602 100644 --- a/toolchain/lower/testdata/array/assign_return_value.carbon +++ b/toolchain/lower/testdata/array/assign_return_value.carbon @@ -13,13 +13,13 @@ fn Run() { // CHECK:STDOUT: ; ModuleID = 'assign_return_value.carbon' // CHECK:STDOUT: source_filename = "assign_return_value.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32 } { i32 12, i32 24 } +// CHECK:STDOUT: @const.loc7_39 = internal constant { i32, i32 } { i32 12, i32 24 } // CHECK:STDOUT: // CHECK:STDOUT: define void @F(ptr sret({ i32, i32 }) %return) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc7_38.2.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 0 // CHECK:STDOUT: %.loc7_38.4.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @tuple, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @const.loc7_39, i64 8, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/testdata/array/base.carbon b/toolchain/lower/testdata/array/base.carbon index 94bdaf627a9b..f418d8024dd4 100644 --- a/toolchain/lower/testdata/array/base.carbon +++ b/toolchain/lower/testdata/array/base.carbon @@ -15,32 +15,32 @@ fn Run() { // CHECK:STDOUT: ; ModuleID = 'base.carbon' // CHECK:STDOUT: source_filename = "base.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant [1 x i32] [i32 1] -// CHECK:STDOUT: @tuple.1 = internal constant [2 x double] [double 0x4026333333333334, double 2.200000e+00] -// CHECK:STDOUT: @tuple.2 = internal constant [5 x {}] poison -// CHECK:STDOUT: @tuple.3 = internal constant { i32, i32, i32 } { i32 1, i32 2, i32 3 } +// CHECK:STDOUT: @const.loc8_25 = internal constant [1 x i32] [i32 1] +// CHECK:STDOUT: @const.loc9_33 = internal constant [2 x double] [double 0x4026333333333334, double 2.200000e+00] +// CHECK:STDOUT: @const.loc10_41 = internal constant [5 x {}] zeroinitializer +// CHECK:STDOUT: @const.loc11_37 = internal constant { i32, i32, i32 } { i32 1, i32 2, i32 3 } // CHECK:STDOUT: // CHECK:STDOUT: define void @main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %a.var = alloca [1 x i32], align 4 // CHECK:STDOUT: %.loc8_24.3.array.index = getelementptr inbounds [1 x i32], ptr %a.var, i32 0, i32 0 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a.var, ptr align 4 @tuple, i64 4, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a.var, ptr align 4 @const.loc8_25, i64 4, i1 false) // CHECK:STDOUT: %b.var = alloca [2 x double], align 8 // CHECK:STDOUT: %.loc9_32.3.array.index = getelementptr inbounds [2 x double], ptr %b.var, i32 0, i32 0 // CHECK:STDOUT: %.loc9_32.6.array.index = getelementptr inbounds [2 x double], ptr %b.var, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %b.var, ptr align 8 @tuple.1, i64 16, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %b.var, ptr align 8 @const.loc9_33, i64 16, i1 false) // CHECK:STDOUT: %c.var = alloca [5 x {}], align 8 // CHECK:STDOUT: %.loc10_40.3.array.index = getelementptr inbounds [5 x {}], ptr %c.var, i32 0, i32 0 // CHECK:STDOUT: %.loc10_40.6.array.index = getelementptr inbounds [5 x {}], ptr %c.var, i32 0, i32 1 // CHECK:STDOUT: %.loc10_40.9.array.index = getelementptr inbounds [5 x {}], ptr %c.var, i32 0, i32 2 // CHECK:STDOUT: %.loc10_40.12.array.index = getelementptr inbounds [5 x {}], ptr %c.var, i32 0, i32 3 // CHECK:STDOUT: %.loc10_40.15.array.index = getelementptr inbounds [5 x {}], ptr %c.var, i32 0, i32 4 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %c.var, ptr align 1 @tuple.2, i64 0, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %c.var, ptr align 1 @const.loc10_41, i64 0, i1 false) // CHECK:STDOUT: %d.var = alloca { i32, i32, i32 }, align 8 // CHECK:STDOUT: %.loc11_36.2.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %d.var, i32 0, i32 0 // CHECK:STDOUT: %.loc11_36.4.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %d.var, i32 0, i32 1 // CHECK:STDOUT: %.loc11_36.6.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %d.var, i32 0, i32 2 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %d.var, ptr align 4 @tuple.3, i64 12, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %d.var, ptr align 4 @const.loc11_37, i64 12, i1 false) // CHECK:STDOUT: %e.var = alloca [3 x i32], align 4 // CHECK:STDOUT: %.loc12_21.1.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %d.var, i32 0, i32 0 // CHECK:STDOUT: %.loc12_21.2 = load i32, ptr %.loc12_21.1.tuple.elem, align 4 @@ -61,9 +61,6 @@ fn Run() { // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 3 } -// CHECK:STDOUT: uselistorder i32 2, { 0, 1, 3, 4, 2 } -// CHECK:STDOUT: uselistorder i32 3, { 1, 0 } // CHECK:STDOUT: uselistorder ptr @llvm.memcpy.p0.p0.i64, { 3, 2, 1, 0 } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/array/function_param.carbon b/toolchain/lower/testdata/array/function_param.carbon index d341ca83b6e0..553da4804bab 100644 --- a/toolchain/lower/testdata/array/function_param.carbon +++ b/toolchain/lower/testdata/array/function_param.carbon @@ -15,7 +15,7 @@ fn G() -> i32 { // CHECK:STDOUT: ; ModuleID = 'function_param.carbon' // CHECK:STDOUT: source_filename = "function_param.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant [3 x i32] [i32 1, i32 2, i32 3] +// CHECK:STDOUT: @const.loc12_11.1 = internal constant [3 x i32] [i32 1, i32 2, i32 3] // CHECK:STDOUT: // CHECK:STDOUT: define i32 @F(ptr %arr, i32 %i) { // CHECK:STDOUT: entry: @@ -30,7 +30,7 @@ fn G() -> i32 { // CHECK:STDOUT: %.loc12_20.4.array.index = getelementptr inbounds [3 x i32], ptr %.loc12_20.2.temp, i32 0, i32 0 // CHECK:STDOUT: %.loc12_20.7.array.index = getelementptr inbounds [3 x i32], ptr %.loc12_20.2.temp, i32 0, i32 1 // CHECK:STDOUT: %.loc12_20.10.array.index = getelementptr inbounds [3 x i32], ptr %.loc12_20.2.temp, i32 0, i32 2 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %.loc12_20.2.temp, ptr align 4 @tuple, i64 12, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %.loc12_20.2.temp, ptr align 4 @const.loc12_11.1, i64 12, i1 false) // CHECK:STDOUT: %F.call = call i32 @F(ptr %.loc12_20.2.temp, i32 1) // CHECK:STDOUT: ret i32 %F.call // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/basics/numeric_literals.carbon b/toolchain/lower/testdata/basics/numeric_literals.carbon index 62fa54771fe8..e2369b025a55 100644 --- a/toolchain/lower/testdata/basics/numeric_literals.carbon +++ b/toolchain/lower/testdata/basics/numeric_literals.carbon @@ -26,8 +26,8 @@ fn F() { // CHECK:STDOUT: ; ModuleID = 'numeric_literals.carbon' // CHECK:STDOUT: source_filename = "numeric_literals.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant [4 x i32] [i32 8, i32 9, i32 8, i32 8] -// CHECK:STDOUT: @tuple.1 = internal constant [6 x double] [double 9.000000e-01, double 8.000000e+00, double 8.000000e+01, double 1.000000e+07, double 1.000000e+08, double 1.000000e-08] +// CHECK:STDOUT: @const.loc15_4 = internal constant [4 x i32] [i32 8, i32 9, i32 8, i32 8] +// CHECK:STDOUT: @const.loc23_4 = internal constant [6 x double] [double 9.000000e-01, double 8.000000e+00, double 8.000000e+01, double 1.000000e+07, double 1.000000e+08, double 1.000000e-08] // CHECK:STDOUT: // CHECK:STDOUT: define void @F() { // CHECK:STDOUT: entry: @@ -36,7 +36,7 @@ fn F() { // CHECK:STDOUT: %.loc15_3.6.array.index = getelementptr inbounds [4 x i32], ptr %ints.var, i32 0, i32 1 // CHECK:STDOUT: %.loc15_3.9.array.index = getelementptr inbounds [4 x i32], ptr %ints.var, i32 0, i32 2 // CHECK:STDOUT: %.loc15_3.12.array.index = getelementptr inbounds [4 x i32], ptr %ints.var, i32 0, i32 3 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %ints.var, ptr align 4 @tuple, i64 16, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %ints.var, ptr align 4 @const.loc15_4, i64 16, i1 false) // CHECK:STDOUT: %floats.var = alloca [6 x double], align 8 // CHECK:STDOUT: %.loc23_3.3.array.index = getelementptr inbounds [6 x double], ptr %floats.var, i32 0, i32 0 // CHECK:STDOUT: %.loc23_3.6.array.index = getelementptr inbounds [6 x double], ptr %floats.var, i32 0, i32 1 @@ -44,7 +44,7 @@ fn F() { // CHECK:STDOUT: %.loc23_3.12.array.index = getelementptr inbounds [6 x double], ptr %floats.var, i32 0, i32 3 // CHECK:STDOUT: %.loc23_3.15.array.index = getelementptr inbounds [6 x double], ptr %floats.var, i32 0, i32 4 // CHECK:STDOUT: %.loc23_3.18.array.index = getelementptr inbounds [6 x double], ptr %floats.var, i32 0, i32 5 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %floats.var, ptr align 8 @tuple.1, i64 48, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %floats.var, ptr align 8 @const.loc23_4, i64 48, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/testdata/class/adapt.carbon b/toolchain/lower/testdata/class/adapt.carbon index 5ada92ceb281..cc6500baf6e1 100644 --- a/toolchain/lower/testdata/class/adapt.carbon +++ b/toolchain/lower/testdata/class/adapt.carbon @@ -50,13 +50,13 @@ fn DoStuff(a: Int) -> Int { // CHECK:STDOUT: ; ModuleID = 'adapt_class.carbon' // CHECK:STDOUT: source_filename = "adapt_class.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @struct = internal constant { i32, i32 } { i32 1, i32 2 } +// CHECK:STDOUT: @const.loc9_28 = internal constant { i32, i32 } { i32 1, i32 2 } // CHECK:STDOUT: // CHECK:STDOUT: define void @Make(ptr sret({ i32, i32 }) %return) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc9_27.2.a = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 0 // CHECK:STDOUT: %.loc9_27.4.b = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @struct, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @const.loc9_28, i64 8, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -84,9 +84,6 @@ fn DoStuff(a: Int) -> Int { // CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: -// CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 0, 1, 3, 2 } -// CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } // CHECK:STDOUT: ; ModuleID = 'adapt_int.carbon' // CHECK:STDOUT: source_filename = "adapt_int.carbon" diff --git a/toolchain/lower/testdata/class/base.carbon b/toolchain/lower/testdata/class/base.carbon index 2186058cd015..3ecd3f1e41d2 100644 --- a/toolchain/lower/testdata/class/base.carbon +++ b/toolchain/lower/testdata/class/base.carbon @@ -29,15 +29,14 @@ fn Convert(p: Derived*) -> Base* { // CHECK:STDOUT: ; ModuleID = 'base.carbon' // CHECK:STDOUT: source_filename = "base.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @struct = internal constant { i32 } { i32 4 } -// CHECK:STDOUT: @struct.1 = internal constant { { i32 }, i32 } { { i32 } { i32 4 }, i32 7 } +// CHECK:STDOUT: @const.loc18_36 = internal constant { { i32 }, i32 } { { i32 } { i32 4 }, i32 7 } // CHECK:STDOUT: // CHECK:STDOUT: define void @Make(ptr sret({ { i32 }, i32 }) %return) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc18_35.2.base = getelementptr inbounds { { i32 }, i32 }, ptr %return, i32 0, i32 0 // CHECK:STDOUT: %.loc18_26.2.b = getelementptr inbounds { i32 }, ptr %.loc18_35.2.base, i32 0, i32 0 // CHECK:STDOUT: %.loc18_35.4.d = getelementptr inbounds { { i32 }, i32 }, ptr %return, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @struct.1, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @const.loc18_36, i64 8, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/testdata/function/call/struct_param.carbon b/toolchain/lower/testdata/function/call/struct_param.carbon index 6ec53bc8edc6..fc4589b6472f 100644 --- a/toolchain/lower/testdata/function/call/struct_param.carbon +++ b/toolchain/lower/testdata/function/call/struct_param.carbon @@ -13,7 +13,7 @@ fn Main() { // CHECK:STDOUT: ; ModuleID = 'struct_param.carbon' // CHECK:STDOUT: source_filename = "struct_param.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @struct = internal constant { i32, i32 } { i32 2, i32 3 } +// CHECK:STDOUT: @const.loc10_4.3 = internal constant { i32, i32 } { i32 2, i32 3 } // CHECK:STDOUT: // CHECK:STDOUT: define void @F({ i32 } %b, ptr %c) { // CHECK:STDOUT: entry: @@ -22,6 +22,6 @@ fn Main() { // CHECK:STDOUT: // CHECK:STDOUT: define void @Main() { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @F({ i32 } { i32 1 }, ptr @struct) +// CHECK:STDOUT: call void @F({ i32 } { i32 1 }, ptr @const.loc10_4.3) // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/function/call/tuple_param.carbon b/toolchain/lower/testdata/function/call/tuple_param.carbon index 9e00545a3f38..ce0561fe63f9 100644 --- a/toolchain/lower/testdata/function/call/tuple_param.carbon +++ b/toolchain/lower/testdata/function/call/tuple_param.carbon @@ -13,7 +13,7 @@ fn Main() { // CHECK:STDOUT: ; ModuleID = 'tuple_param.carbon' // CHECK:STDOUT: source_filename = "tuple_param.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32 } { i32 2, i32 3 } +// CHECK:STDOUT: @const.loc10_4.3 = internal constant { i32, i32 } { i32 2, i32 3 } // CHECK:STDOUT: // CHECK:STDOUT: define void @F({ i32 } %b, ptr %c) { // CHECK:STDOUT: entry: @@ -22,6 +22,6 @@ fn Main() { // CHECK:STDOUT: // CHECK:STDOUT: define void @Main() { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @F({ i32 } { i32 1 }, ptr @tuple) +// CHECK:STDOUT: call void @F({ i32 } { i32 1 }, ptr @const.loc10_4.3) // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/function/call/tuple_param_with_return_slot.carbon b/toolchain/lower/testdata/function/call/tuple_param_with_return_slot.carbon index 8dcfa28e5983..7394a44ade1f 100644 --- a/toolchain/lower/testdata/function/call/tuple_param_with_return_slot.carbon +++ b/toolchain/lower/testdata/function/call/tuple_param_with_return_slot.carbon @@ -15,7 +15,7 @@ fn Main() { // CHECK:STDOUT: ; ModuleID = 'tuple_param_with_return_slot.carbon' // CHECK:STDOUT: source_filename = "tuple_param_with_return_slot.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32 } { i32 2, i32 3 } +// CHECK:STDOUT: @const.loc12_4.4 = internal constant { i32, i32 } { i32 2, i32 3 } // CHECK:STDOUT: // CHECK:STDOUT: define void @F(ptr sret({ i32, i32, i32 }) %return, { i32 } %b, ptr %c) { // CHECK:STDOUT: entry: @@ -36,9 +36,9 @@ fn Main() { // CHECK:STDOUT: define void @Main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc12_4.1.temp = alloca { i32, i32, i32 }, align 8 -// CHECK:STDOUT: call void @F(ptr %.loc12_4.1.temp, { i32 } { i32 1 }, ptr @tuple) +// CHECK:STDOUT: call void @F(ptr %.loc12_4.1.temp, { i32 } { i32 1 }, ptr @const.loc12_4.4) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 2, { 1, 0 } +// CHECK:STDOUT: uselistorder i32 1, { 3, 0, 1, 2 } diff --git a/toolchain/lower/testdata/index/array_element_access.carbon b/toolchain/lower/testdata/index/array_element_access.carbon index c05358b3f855..cf44dc8587eb 100644 --- a/toolchain/lower/testdata/index/array_element_access.carbon +++ b/toolchain/lower/testdata/index/array_element_access.carbon @@ -17,14 +17,14 @@ fn Run() { // CHECK:STDOUT: ; ModuleID = 'array_element_access.carbon' // CHECK:STDOUT: source_filename = "array_element_access.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32 } { i32 1, i32 2 } -// CHECK:STDOUT: @tuple.1 = internal constant [2 x i32] [i32 1, i32 2] +// CHECK:STDOUT: @const.loc6_37 = internal constant { i32, i32 } { i32 1, i32 2 } +// CHECK:STDOUT: @const.loc8_35 = internal constant [2 x i32] [i32 1, i32 2] // CHECK:STDOUT: // CHECK:STDOUT: define void @A(ptr sret({ i32, i32 }) %return) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc6_36.2.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 0 // CHECK:STDOUT: %.loc6_36.4.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @tuple, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @const.loc6_37, i64 8, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -32,7 +32,7 @@ fn Run() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc8_34.3.array.index = getelementptr inbounds [2 x i32], ptr %return, i32 0, i32 0 // CHECK:STDOUT: %.loc8_34.6.array.index = getelementptr inbounds [2 x i32], ptr %return, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @tuple.1, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @const.loc8_35, i64 8, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -73,7 +73,6 @@ fn Run() { // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 11 } // CHECK:STDOUT: uselistorder ptr @llvm.memcpy.p0.p0.i64, { 1, 0 } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/index/tuple_element_access.carbon b/toolchain/lower/testdata/index/tuple_element_access.carbon index d303730bff85..8615c7a43fcb 100644 --- a/toolchain/lower/testdata/index/tuple_element_access.carbon +++ b/toolchain/lower/testdata/index/tuple_element_access.carbon @@ -14,7 +14,7 @@ fn Run() -> i32 { // CHECK:STDOUT: ; ModuleID = 'tuple_element_access.carbon' // CHECK:STDOUT: source_filename = "tuple_element_access.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32, i32 } { i32 0, i32 1, i32 2 } +// CHECK:STDOUT: @const.loc8_37 = internal constant { i32, i32, i32 } { i32 0, i32 1, i32 2 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @main() { // CHECK:STDOUT: entry: @@ -22,7 +22,7 @@ fn Run() -> i32 { // CHECK:STDOUT: %.loc8_36.2.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 0 // CHECK:STDOUT: %.loc8_36.4.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 1 // CHECK:STDOUT: %.loc8_36.6.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 2 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a.var, ptr align 4 @tuple, i64 12, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a.var, ptr align 4 @const.loc8_37, i64 12, i1 false) // CHECK:STDOUT: %b.var = alloca i32, align 4 // CHECK:STDOUT: %.loc9_19.1.tuple.index = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 0 // CHECK:STDOUT: %.loc9_19.2 = load i32, ptr %.loc9_19.1.tuple.index, align 4 @@ -37,9 +37,4 @@ fn Run() -> i32 { // CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: -// CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 0, { 0, 1, 2, 3, 5, 6, 7, 8, 4 } -// CHECK:STDOUT: uselistorder i32 1, { 0, 1, 3, 4, 2 } -// CHECK:STDOUT: uselistorder i32 2, { 0, 2, 1 } -// CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/index/tuple_return_value_access.carbon b/toolchain/lower/testdata/index/tuple_return_value_access.carbon index a957ad7da30f..5d931add2d4d 100644 --- a/toolchain/lower/testdata/index/tuple_return_value_access.carbon +++ b/toolchain/lower/testdata/index/tuple_return_value_access.carbon @@ -13,13 +13,13 @@ fn Run() { // CHECK:STDOUT: ; ModuleID = 'tuple_return_value_access.carbon' // CHECK:STDOUT: source_filename = "tuple_return_value_access.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32 } { i32 12, i32 24 } +// CHECK:STDOUT: @const.loc7_39 = internal constant { i32, i32 } { i32 12, i32 24 } // CHECK:STDOUT: // CHECK:STDOUT: define void @F(ptr sret({ i32, i32 }) %return) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc7_38.2.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 0 // CHECK:STDOUT: %.loc7_38.4.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %return, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @tuple, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %return, ptr align 4 @const.loc7_39, i64 8, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/testdata/let/tuple.carbon b/toolchain/lower/testdata/let/tuple.carbon index e39ac3f2b3d2..b0ff4259f053 100644 --- a/toolchain/lower/testdata/let/tuple.carbon +++ b/toolchain/lower/testdata/let/tuple.carbon @@ -14,8 +14,8 @@ fn F() -> i32 { // CHECK:STDOUT: ; ModuleID = 'tuple.carbon' // CHECK:STDOUT: source_filename = "tuple.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32, i32 } { i32 1, i32 2, i32 3 } -// CHECK:STDOUT: @tuple.1 = internal constant { i32, i32 } { i32 4, i32 5 } +// CHECK:STDOUT: @const.loc8_37 = internal constant { i32, i32, i32 } { i32 1, i32 2, i32 3 } +// CHECK:STDOUT: @const.loc9_29 = internal constant { i32, i32 } { i32 4, i32 5 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @F() { // CHECK:STDOUT: entry: @@ -23,11 +23,11 @@ fn F() -> i32 { // CHECK:STDOUT: %.loc8_36.2.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 0 // CHECK:STDOUT: %.loc8_36.4.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 1 // CHECK:STDOUT: %.loc8_36.6.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 2 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a.var, ptr align 4 @tuple, i64 12, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a.var, ptr align 4 @const.loc8_37, i64 12, i1 false) // CHECK:STDOUT: %b.var = alloca { i32, i32 }, align 8 // CHECK:STDOUT: %.loc9_28.2.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %b.var, i32 0, i32 0 // CHECK:STDOUT: %.loc9_28.4.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %b.var, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b.var, ptr align 4 @tuple.1, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b.var, ptr align 4 @const.loc9_29, i64 8, i1 false) // CHECK:STDOUT: %.loc10_43.1.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 0 // CHECK:STDOUT: %.loc10_43.2 = load i32, ptr %.loc10_43.1.tuple.elem, align 4 // CHECK:STDOUT: %.loc10_43.3.tuple.elem = getelementptr inbounds { i32, i32, i32 }, ptr %a.var, i32 0, i32 1 @@ -66,8 +66,6 @@ fn F() -> i32 { // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 12 } -// CHECK:STDOUT: uselistorder i32 2, { 0, 1, 3, 2 } // CHECK:STDOUT: uselistorder ptr @llvm.memcpy.p0.p0.i64, { 1, 0 } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/operators/assignment.carbon b/toolchain/lower/testdata/operators/assignment.carbon index 00ef8a52b6a6..f842d1558552 100644 --- a/toolchain/lower/testdata/operators/assignment.carbon +++ b/toolchain/lower/testdata/operators/assignment.carbon @@ -14,7 +14,7 @@ fn Main() { // CHECK:STDOUT: ; ModuleID = 'assignment.carbon' // CHECK:STDOUT: source_filename = "assignment.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32 } { i32 1, i32 2 } +// CHECK:STDOUT: @const.loc11_5 = internal constant { i32, i32 } { i32 1, i32 2 } // CHECK:STDOUT: // CHECK:STDOUT: define void @Main() { // CHECK:STDOUT: entry: @@ -24,14 +24,11 @@ fn Main() { // CHECK:STDOUT: %b.var = alloca { i32, i32 }, align 8 // CHECK:STDOUT: %.loc11_12.2.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %b.var, i32 0, i32 0 // CHECK:STDOUT: %.loc11_12.4.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %b.var, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b.var, ptr align 4 @tuple, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %b.var, ptr align 4 @const.loc11_5, i64 8, i1 false) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: -// CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 1, 2, 3, 0 } -// CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/pointer/address_of_field.carbon b/toolchain/lower/testdata/pointer/address_of_field.carbon index 56a3d6a0a5f7..2eda1688e1a6 100644 --- a/toolchain/lower/testdata/pointer/address_of_field.carbon +++ b/toolchain/lower/testdata/pointer/address_of_field.carbon @@ -14,7 +14,7 @@ fn F() { // CHECK:STDOUT: ; ModuleID = 'address_of_field.carbon' // CHECK:STDOUT: source_filename = "address_of_field.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @struct = internal constant { i32, i32 } { i32 1, i32 2 } +// CHECK:STDOUT: @const.loc10_47 = internal constant { i32, i32 } { i32 1, i32 2 } // CHECK:STDOUT: // CHECK:STDOUT: declare void @G(ptr) // CHECK:STDOUT: @@ -23,7 +23,7 @@ fn F() { // CHECK:STDOUT: %s.var = alloca { i32, i32 }, align 8 // CHECK:STDOUT: %.loc10_46.2.a = getelementptr inbounds { i32, i32 }, ptr %s.var, i32 0, i32 0 // CHECK:STDOUT: %.loc10_46.4.b = getelementptr inbounds { i32, i32 }, ptr %s.var, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %s.var, ptr align 4 @struct, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %s.var, ptr align 4 @const.loc10_47, i64 8, i1 false) // CHECK:STDOUT: %.loc11_7.b = getelementptr inbounds { i32, i32 }, ptr %s.var, i32 0, i32 1 // CHECK:STDOUT: call void @G(ptr %.loc11_7.b) // CHECK:STDOUT: ret void @@ -32,7 +32,4 @@ fn F() { // CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: -// CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 0, 2, 3, 1 } -// CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/struct/member_access.carbon b/toolchain/lower/testdata/struct/member_access.carbon index ce10f5f734d8..e1e3a8c7a614 100644 --- a/toolchain/lower/testdata/struct/member_access.carbon +++ b/toolchain/lower/testdata/struct/member_access.carbon @@ -14,14 +14,14 @@ fn Run() -> i32 { // CHECK:STDOUT: ; ModuleID = 'member_access.carbon' // CHECK:STDOUT: source_filename = "member_access.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @struct = internal constant { double, i32 } { double 0.000000e+00, i32 1 } +// CHECK:STDOUT: @const.loc8_49 = internal constant { double, i32 } { double 0.000000e+00, i32 1 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.var = alloca { double, i32 }, align 8 // CHECK:STDOUT: %.loc8_48.2.a = getelementptr inbounds { double, i32 }, ptr %x.var, i32 0, i32 0 // CHECK:STDOUT: %.loc8_48.4.b = getelementptr inbounds { double, i32 }, ptr %x.var, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x.var, ptr align 8 @struct, i64 16, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x.var, ptr align 8 @const.loc8_49, i64 16, i1 false) // CHECK:STDOUT: %y.var = alloca i32, align 4 // CHECK:STDOUT: %.loc9_17.1.b = getelementptr inbounds { double, i32 }, ptr %x.var, i32 0, i32 1 // CHECK:STDOUT: %.loc9_17.2 = load i32, ptr %.loc9_17.1.b, align 4 @@ -35,7 +35,4 @@ fn Run() -> i32 { // CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: -// CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 0, 1, 2, 4, 5, 3 } -// CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/struct/two_entries.carbon b/toolchain/lower/testdata/struct/two_entries.carbon index b2c3b934a4cb..61a0cbe5db58 100644 --- a/toolchain/lower/testdata/struct/two_entries.carbon +++ b/toolchain/lower/testdata/struct/two_entries.carbon @@ -13,14 +13,14 @@ fn Run() -> i32 { // CHECK:STDOUT: ; ModuleID = 'two_entries.carbon' // CHECK:STDOUT: source_filename = "two_entries.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @struct = internal constant { i32, i32 } { i32 1, i32 2 } +// CHECK:STDOUT: @const.loc8_47 = internal constant { i32, i32 } { i32 1, i32 2 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.var = alloca { i32, i32 }, align 8 // CHECK:STDOUT: %.loc8_46.2.a = getelementptr inbounds { i32, i32 }, ptr %x.var, i32 0, i32 0 // CHECK:STDOUT: %.loc8_46.4.b = getelementptr inbounds { i32, i32 }, ptr %x.var, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x.var, ptr align 4 @struct, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x.var, ptr align 4 @const.loc8_47, i64 8, i1 false) // CHECK:STDOUT: %y.var = alloca { i32, i32 }, align 8 // CHECK:STDOUT: %.loc9_31.1.a = getelementptr inbounds { i32, i32 }, ptr %x.var, i32 0, i32 0 // CHECK:STDOUT: %.loc9_31.2 = load i32, ptr %.loc9_31.1.a, align 4 @@ -36,7 +36,4 @@ fn Run() -> i32 { // CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) // CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 // CHECK:STDOUT: -// CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder i32 1, { 0, 1, 2, 4, 5, 3 } -// CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } diff --git a/toolchain/lower/testdata/tuple/one_entry.carbon b/toolchain/lower/testdata/tuple/one_entry.carbon index fafcdd67f7a7..c91ca789edfe 100644 --- a/toolchain/lower/testdata/tuple/one_entry.carbon +++ b/toolchain/lower/testdata/tuple/one_entry.carbon @@ -24,3 +24,6 @@ fn Run() -> i32 { // CHECK:STDOUT: store { i32 } %.loc9_20.3.tuple.init, ptr %y.var, align 4 // CHECK:STDOUT: ret i32 0 // CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder i32 1, { 0, 2, 1 } diff --git a/toolchain/lower/testdata/tuple/two_entries.carbon b/toolchain/lower/testdata/tuple/two_entries.carbon index 0e60ee96f491..0576d235dfa8 100644 --- a/toolchain/lower/testdata/tuple/two_entries.carbon +++ b/toolchain/lower/testdata/tuple/two_entries.carbon @@ -13,14 +13,14 @@ fn Run() -> i32 { // CHECK:STDOUT: ; ModuleID = 'two_entries.carbon' // CHECK:STDOUT: source_filename = "two_entries.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: @tuple = internal constant { i32, i32 } { i32 12, i32 7 } +// CHECK:STDOUT: @const.loc8_30 = internal constant { i32, i32 } { i32 12, i32 7 } // CHECK:STDOUT: // CHECK:STDOUT: define i32 @main() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.var = alloca { i32, i32 }, align 8 // CHECK:STDOUT: %.loc8_29.2.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %x.var, i32 0, i32 0 // CHECK:STDOUT: %.loc8_29.4.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %x.var, i32 0, i32 1 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x.var, ptr align 4 @tuple, i64 8, i1 false) +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x.var, ptr align 4 @const.loc8_30, i64 8, i1 false) // CHECK:STDOUT: %y.var = alloca { i32, i32 }, align 8 // CHECK:STDOUT: %.loc9_23.1.tuple.elem = getelementptr inbounds { i32, i32 }, ptr %x.var, i32 0, i32 0 // CHECK:STDOUT: %.loc9_23.2 = load i32, ptr %.loc9_23.1.tuple.elem, align 4 diff --git a/toolchain/sem_ir/constant.h b/toolchain/sem_ir/constant.h index c99f10d5cd08..de5348af9e37 100644 --- a/toolchain/sem_ir/constant.h +++ b/toolchain/sem_ir/constant.h @@ -37,6 +37,11 @@ class ConstantValueStore { values_[inst_id.index] = const_id; } + // Returns the constant values mapping as an ArrayRef whose keys are + // instruction indexes. Some of the elements in this mapping may be Invalid or + // NotConstant. + auto array_ref() const -> llvm::ArrayRef { return values_; } + private: const ConstantId default_; diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 04543861b71e..42f0afb945ac 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -193,6 +193,7 @@ static auto GetTypePrecedence(InstKind kind) -> int { return -2; #define CARBON_SEM_IR_INST_KIND_TYPE(...) +#define CARBON_SEM_IR_INST_KIND_MAYBE_TYPE(...) #define CARBON_SEM_IR_INST_KIND(Name) case SemIR::Name::Kind: #include "toolchain/sem_ir/inst_kind.def" CARBON_FATAL() << "GetTypePrecedence for non-type inst kind " << kind; diff --git a/toolchain/sem_ir/inst_kind.cpp b/toolchain/sem_ir/inst_kind.cpp index 5738f5730f1b..8da678048866 100644 --- a/toolchain/sem_ir/inst_kind.cpp +++ b/toolchain/sem_ir/inst_kind.cpp @@ -33,7 +33,13 @@ auto InstKind::value_kind() const -> InstValueKind { auto InstKind::constant_kind() const -> InstConstantKind { static constexpr InstConstantKind Table[] = { -#define CARBON_SEM_IR_INST_KIND(Name) SemIR::Name::Kind.constant_kind(), +#define CARBON_SEM_IR_INST_KIND_CONSTANT_NEVER(...) InstConstantKind::Never, +#define CARBON_SEM_IR_INST_KIND_CONSTANT_SYMBOLIC_ONLY(...) \ + InstConstantKind::SymbolicOnly, +#define CARBON_SEM_IR_INST_KIND_CONSTANT_CONDITIONAL(...) \ + InstConstantKind::Conditional, +#define CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS(...) InstConstantKind::Always, +#define CARBON_SEM_IR_INST_KIND(Name) #include "toolchain/sem_ir/inst_kind.def" }; return Table[AsInt()]; diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 9deadcdbb7e3..f4ee59bd8c0d 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -11,14 +11,31 @@ // - CARBON_SEM_IR_INST_KIND(Name) // Invoked for each kind of semantic instruction. // -// The invocation of the above macro will be wrapped in one of these, which by -// default expand to their argument: +// The invocation of the above macro will be wrapped in one macro from each of +// the following sets, which by default expand to their argument: +// +// Whether the instruction can define a type: // - CARBON_SEM_IR_INST_KIND_TYPE(...) -// Invoked for each instruction that might define a type constant. +// Invoked for each instruction that is always of type `type`, and might +// define a type constant. +// - CARBON_SEM_IR_INST_KIND_MAYBE_TYPE(...) +// Invoked for each instruction that is sometimes of type `type`, and might +// define a type constant. // - CARBON_SEM_IR_INST_KIND_NOT_TYPE(...) // Invoked for each instruction that can never define a type constant. Note // that such instructions can still have type `type`, but are not the // canonical definition of any type. +// +// Whether the instruction can define a constant, see `InstConstantKind`: +// - CARBON_SEM_IR_INST_KIND_CONSTANT_NEVER(...) +// Invoked when `constant_kind()` is `InstConstantKind::Never`. +// - CARBON_SEM_IR_INST_KIND_CONSTANT_SYMBOLIC_ONLY(...) +// Invoked when `constant_kind()` is `InstConstantKind::SymbolicOnly`. +// - CARBON_SEM_IR_INST_KIND_CONSTANT_CONDITIONAL(...) +// Invoked when `constant_kind()` is `InstConstantKind::Conditional`. +// - CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS(...) +// Invoked when `constant_kind()` is `InstConstantKind::Always`. +// // Defining these is optional. #ifndef CARBON_SEM_IR_INST_KIND @@ -28,92 +45,118 @@ #ifndef CARBON_SEM_IR_INST_KIND_NOT_TYPE #define CARBON_SEM_IR_INST_KIND_NOT_TYPE(...) __VA_ARGS__ #endif +#ifndef CARBON_SEM_IR_INST_KIND_MAYBE_TYPE +#define CARBON_SEM_IR_INST_KIND_MAYBE_TYPE(...) __VA_ARGS__ +#endif #ifndef CARBON_SEM_IR_INST_KIND_TYPE #define CARBON_SEM_IR_INST_KIND_TYPE(...) __VA_ARGS__ #endif -#define CARBON_SEM_IR_INST_KIND_IMPL(Name, IsType) \ - CARBON_SEM_IR_INST_KIND_##IsType(CARBON_SEM_IR_INST_KIND(Name)) +#ifndef CARBON_SEM_IR_INST_KIND_CONSTANT_NEVER +#define CARBON_SEM_IR_INST_KIND_CONSTANT_NEVER(...) __VA_ARGS__ +#endif +#ifndef CARBON_SEM_IR_INST_KIND_CONSTANT_SYMBOLIC_ONLY +#define CARBON_SEM_IR_INST_KIND_CONSTANT_SYMBOLIC_ONLY(...) __VA_ARGS__ +#endif +#ifndef CARBON_SEM_IR_INST_KIND_CONSTANT_CONDITIONAL +#define CARBON_SEM_IR_INST_KIND_CONSTANT_CONDITIONAL(...) __VA_ARGS__ +#endif +#ifndef CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS +#define CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS(...) __VA_ARGS__ +#endif + +#define CARBON_SEM_IR_INST_KIND_IMPL(Name, IsType, IsConstant) \ + CARBON_SEM_IR_INST_KIND_##IsType( \ + CARBON_SEM_IR_INST_KIND_##IsConstant(CARBON_SEM_IR_INST_KIND(Name))) // For each instruction kind declared here there is a matching definition in // `typed_insts.h`. -CARBON_SEM_IR_INST_KIND_IMPL(AdaptDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(AddrOf, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(AddrPattern, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ArrayIndex, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ArrayInit, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ArrayType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(AsCompatible, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Assign, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(AssociatedConstantDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(AssociatedEntity, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(AssociatedEntityType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BaseDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BindAlias, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BindName, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BindSymbolicName, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BindValue, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BlockArg, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BoolLiteral, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BoundMethod, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Branch, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BranchIf, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(BranchWithArg, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Builtin, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Call, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ClassDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ClassElementAccess, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ClassInit, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ClassType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ConstType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Converted, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Deref, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(FacetTypeAccess, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(FloatLiteral, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(FloatType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(FieldDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(FunctionDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ImplDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ImportRefUnloaded, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ImportRefLoaded, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ImportRefUsed, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(InitializeFrom, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(InterfaceDecl, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(InterfaceType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(InterfaceWitness, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(InterfaceWitnessAccess, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(IntLiteral, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(IntType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(NameRef, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Namespace, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Param, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(PointerType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(RealLiteral, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ReturnExpr, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Return, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(SpliceBlock, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(StringLiteral, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(StructAccess, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(StructInit, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(StructLiteral, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(StructTypeField, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(StructType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(StructValue, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(TemporaryStorage, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(Temporary, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(TupleAccess, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(TupleIndex, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(TupleInit, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(TupleLiteral, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(TupleType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(TupleValue, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(UnaryOperatorNot, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(UnboundElementType, TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ValueAsRef, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(ValueOfInitializer, NOT_TYPE) -CARBON_SEM_IR_INST_KIND_IMPL(VarStorage, NOT_TYPE) +CARBON_SEM_IR_INST_KIND_IMPL(AdaptDecl, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(AddrOf, NOT_TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(AddrPattern, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ArrayIndex, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ArrayInit, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ArrayType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(AsCompatible, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(Assign, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(AssociatedConstantDecl, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(AssociatedEntity, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(AssociatedEntityType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(BaseDecl, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(BindAlias, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(BindName, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(BindSymbolicName, MAYBE_TYPE, + CONSTANT_SYMBOLIC_ONLY) +CARBON_SEM_IR_INST_KIND_IMPL(BindValue, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(BlockArg, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(BoolLiteral, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(BoundMethod, NOT_TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(Branch, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(BranchIf, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(BranchWithArg, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(Builtin, TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(Call, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ClassDecl, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ClassElementAccess, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ClassInit, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ClassType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(ConstType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(Converted, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(Deref, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(FacetTypeAccess, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(FieldDecl, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(FloatLiteral, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(FloatType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(FunctionDecl, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(ImplDecl, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ImportRefUnloaded, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ImportRefLoaded, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ImportRefUsed, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(InitializeFrom, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(InterfaceDecl, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(InterfaceType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(InterfaceWitness, NOT_TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(InterfaceWitnessAccess, MAYBE_TYPE, + CONSTANT_SYMBOLIC_ONLY) +CARBON_SEM_IR_INST_KIND_IMPL(IntLiteral, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(IntType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(NameRef, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(Namespace, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(Param, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(PointerType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(RealLiteral, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(ReturnExpr, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(Return, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(SpliceBlock, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(StringLiteral, NOT_TYPE, CONSTANT_ALWAYS) +CARBON_SEM_IR_INST_KIND_IMPL(StructAccess, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(StructInit, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(StructLiteral, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(StructType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(StructTypeField, NOT_TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(StructValue, NOT_TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(TemporaryStorage, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(Temporary, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(TupleAccess, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(TupleIndex, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(TupleInit, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(TupleLiteral, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(TupleType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(TupleValue, NOT_TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(UnaryOperatorNot, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(UnboundElementType, TYPE, CONSTANT_CONDITIONAL) +CARBON_SEM_IR_INST_KIND_IMPL(ValueAsRef, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(ValueOfInitializer, NOT_TYPE, CONSTANT_NEVER) +CARBON_SEM_IR_INST_KIND_IMPL(VarStorage, NOT_TYPE, CONSTANT_NEVER) -#undef CARBON_SEM_IR_INST_KIND_NOT_TYPE #undef CARBON_SEM_IR_INST_KIND_TYPE +#undef CARBON_SEM_IR_INST_KIND_MAYBE_TYPE +#undef CARBON_SEM_IR_INST_KIND_NOT_TYPE + +#undef CARBON_SEM_IR_INST_KIND_CONSTANT_NEVER +#undef CARBON_SEM_IR_INST_KIND_CONSTANT_SYMBOLIC_ONLY +#undef CARBON_SEM_IR_INST_KIND_CONSTANT_CONDITIONAL +#undef CARBON_SEM_IR_INST_KIND_CONSTANT_ALWAYS + #undef CARBON_SEM_IR_INST_KIND_IMPL #undef CARBON_SEM_IR_INST_KIND diff --git a/toolchain/sem_ir/inst_kind.h b/toolchain/sem_ir/inst_kind.h index 5632f01cc74b..9cc073ceca7f 100644 --- a/toolchain/sem_ir/inst_kind.h +++ b/toolchain/sem_ir/inst_kind.h @@ -79,11 +79,7 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) { template constexpr auto Define( llvm::StringLiteral ir_name, - InstConstantKind constant_kind = InstConstantKind::Never) const - -> Definition; - template - constexpr auto Define(llvm::StringLiteral ir_name, - TerminatorKind terminator_kind) const + TerminatorKind terminator_kind = TerminatorKind::NotTerminator) const -> Definition; using EnumBase::AsInt; @@ -134,11 +130,6 @@ class InstKind::Definition : public InstKind { // Returns the name to use for this instruction kind in Semantics IR. constexpr auto ir_name() const -> llvm::StringLiteral { return ir_name_; } - // Returns whether this kind of instruction is able to define a constant. - constexpr auto constant_kind() const -> InstConstantKind { - return constant_kind_; - } - // Returns whether this instruction kind is a code block terminator. See // InstKind::terminator_kind(). constexpr auto terminator_kind() const -> TerminatorKind { @@ -149,32 +140,18 @@ class InstKind::Definition : public InstKind { friend class InstKind; constexpr Definition(InstKind kind, llvm::StringLiteral ir_name, - InstConstantKind constant_kind, TerminatorKind terminator_kind) - : InstKind(kind), - ir_name_(ir_name), - constant_kind_(constant_kind), - terminator_kind_(terminator_kind) {} + : InstKind(kind), ir_name_(ir_name), terminator_kind_(terminator_kind) {} llvm::StringLiteral ir_name_; - InstConstantKind constant_kind_; TerminatorKind terminator_kind_; }; -template -constexpr auto InstKind::Define(llvm::StringLiteral ir_name, - InstConstantKind constant_kind) const - -> Definition { - return Definition(*this, ir_name, constant_kind, - TerminatorKind::NotTerminator); -} - template constexpr auto InstKind::Define(llvm::StringLiteral ir_name, TerminatorKind terminator_kind) const -> Definition { - return Definition(*this, ir_name, InstConstantKind::Never, - terminator_kind); + return Definition(*this, ir_name, terminator_kind); } } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index b1b4a8182aae..d0947062e496 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -55,8 +55,8 @@ struct AdaptDecl { struct AddrOf { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::AddrOf.Define( - "addr_of", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::AddrOf.Define("addr_of"); TypeId type_id; InstId lvalue_id; @@ -73,8 +73,8 @@ struct AddrPattern { struct ArrayIndex { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::ArrayIndex.Define( - "array_index", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::ArrayIndex.Define("array_index"); TypeId type_id; InstId array_id; @@ -142,8 +142,8 @@ struct ArrayInit { }; struct ArrayType { - static constexpr auto Kind = InstKind::ArrayType.Define( - "array_type", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::ArrayType.Define("array_type"); TypeId type_id; InstId bound_id; @@ -186,8 +186,8 @@ struct AssociatedConstantDecl { // This represents the entity before impl lookup is performed, and identifies // the slot within a witness where the constant value will be found. struct AssociatedEntity { - static constexpr auto Kind = InstKind::AssociatedEntity.Define( - "assoc_entity", InstConstantKind::Always); + static constexpr auto Kind = + InstKind::AssociatedEntity.Define("assoc_entity"); // The type of the associated entity. This is an AssociatedEntityType. TypeId type_id; @@ -200,7 +200,7 @@ struct AssociatedEntity { struct AssociatedEntityType { static constexpr auto Kind = InstKind::AssociatedEntityType.Define( - "assoc_entity_type", InstConstantKind::Conditional); + "assoc_entity_type"); TypeId type_id; InterfaceId interface_id; @@ -211,8 +211,8 @@ struct AssociatedEntityType { // element of the derived class, and the type of the `BaseDecl` instruction is // an `UnboundElementType`. struct BaseDecl { - static constexpr auto Kind = InstKind::BaseDecl.Define( - "base_decl", InstConstantKind::Always); + static constexpr auto Kind = + InstKind::BaseDecl.Define("base_decl"); TypeId type_id; TypeId base_type_id; @@ -253,8 +253,8 @@ struct BindName { }; struct BindSymbolicName { - static constexpr auto Kind = InstKind::BindSymbolicName.Define( - "bind_symbolic_name", InstConstantKind::SymbolicOnly); + static constexpr auto Kind = + InstKind::BindSymbolicName.Define("bind_symbolic_name"); TypeId type_id; BindNameId bind_name_id; @@ -280,8 +280,8 @@ struct BlockArg { }; struct BoolLiteral { - static constexpr auto Kind = InstKind::BoolLiteral.Define( - "bool_literal", InstConstantKind::Always); + static constexpr auto Kind = + InstKind::BoolLiteral.Define("bool_literal"); TypeId type_id; BoolValue value; @@ -290,8 +290,8 @@ struct BoolLiteral { // A bound method, that combines a function with the value to use for its // `self` parameter, such as `object.MethodName`. struct BoundMethod { - static constexpr auto Kind = InstKind::BoundMethod.Define( - "bound_method", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::BoundMethod.Define("bound_method"); TypeId type_id; // The object argument in the bound method, which will be used to initialize @@ -344,8 +344,8 @@ struct BranchWithArg { struct Builtin { // Builtins don't have a parse node associated with them. - static constexpr auto Kind = InstKind::Builtin.Define( - "builtin", InstConstantKind::Always); + static constexpr auto Kind = + InstKind::Builtin.Define("builtin"); TypeId type_id; BuiltinKind builtin_kind; @@ -355,8 +355,7 @@ struct Call { // For a syntactic call, the parse node will be a CallExprStartId. However, // calls can arise from other syntaxes, such as operators and implicit // conversions. - static constexpr auto Kind = InstKind::Call.Define( - "call", InstConstantKind::SymbolicOnly); + static constexpr auto Kind = InstKind::Call.Define("call"); TypeId type_id; InstId callee_id; @@ -369,8 +368,7 @@ struct Call { struct ClassDecl { static constexpr auto Kind = - InstKind::ClassDecl.Define( - "class_decl", InstConstantKind::Always); + InstKind::ClassDecl.Define("class_decl"); TypeId type_id; // TODO: For a generic class declaration, the name of the class declaration @@ -404,8 +402,7 @@ struct ClassInit { struct ClassType { static constexpr auto Kind = - InstKind::ClassType.Define( - "class_type", InstConstantKind::Conditional); + InstKind::ClassType.Define("class_type"); TypeId type_id; ClassId class_id; @@ -414,8 +411,7 @@ struct ClassType { struct ConstType { static constexpr auto Kind = - InstKind::ConstType.Define( - "const_type", InstConstantKind::Conditional); + InstKind::ConstType.Define("const_type"); TypeId type_id; TypeId inner_id; @@ -448,18 +444,28 @@ struct FacetTypeAccess { InstId facet_id; }; +// A field in a class, of the form `var field: field_type;`. The type of the +// `FieldDecl` instruction is an `UnboundElementType`. +struct FieldDecl { + static constexpr auto Kind = + InstKind::FieldDecl.Define("field_decl"); + + TypeId type_id; + NameId name_id; + ElementIndex index; +}; + struct FloatLiteral { static constexpr auto Kind = - InstKind::FloatLiteral.Define( - "float_literal", InstConstantKind::Always); + InstKind::FloatLiteral.Define("float_literal"); TypeId type_id; FloatId float_id; }; struct FloatType { - static constexpr auto Kind = InstKind::FloatType.Define( - "float_type", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::FloatType.Define("float_type"); TypeId type_id; // TODO: Consider adding a more compact way of representing either a small @@ -467,22 +473,9 @@ struct FloatType { InstId bit_width_id; }; -// A field in a class, of the form `var field: field_type;`. The type of the -// `FieldDecl` instruction is an `UnboundElementType`. -struct FieldDecl { - static constexpr auto Kind = - InstKind::FieldDecl.Define( - "field_decl", InstConstantKind::Always); - - TypeId type_id; - NameId name_id; - ElementIndex index; -}; - struct FunctionDecl { static constexpr auto Kind = - InstKind::FunctionDecl.Define( - "fn_decl", InstConstantKind::Always); + InstKind::FunctionDecl.Define("fn_decl"); TypeId type_id; FunctionId function_id; @@ -571,8 +564,8 @@ struct InterfaceDecl { }; struct InterfaceType { - static constexpr auto Kind = InstKind::InterfaceType.Define( - "interface_type", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::InterfaceType.Define("interface_type"); TypeId type_id; InterfaceId interface_id; @@ -584,7 +577,7 @@ struct InterfaceType { struct InterfaceWitness { static constexpr auto Kind = InstKind::InterfaceWitness.Define( - "interface_witness", InstConstantKind::Conditional); + "interface_witness"); TypeId type_id; InstBlockId elements_id; @@ -603,16 +596,16 @@ struct InterfaceWitnessAccess { struct IntLiteral { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::IntLiteral.Define( - "int_literal", InstConstantKind::Always); + static constexpr auto Kind = + InstKind::IntLiteral.Define("int_literal"); TypeId type_id; IntId int_id; }; struct IntType { - static constexpr auto Kind = InstKind::IntType.Define( - "int_type", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::IntType.Define("int_type"); TypeId type_id; IntKind int_kind; @@ -633,8 +626,7 @@ struct NameRef { struct Namespace { static constexpr auto Kind = - InstKind::Namespace.Define( - "namespace", InstConstantKind::Always); + InstKind::Namespace.Define("namespace"); TypeId type_id; NameScopeId name_scope_id; @@ -651,8 +643,8 @@ struct Param { struct PointerType { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::PointerType.Define( - "ptr_type", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::PointerType.Define("ptr_type"); TypeId type_id; TypeId pointee_id; @@ -660,8 +652,7 @@ struct PointerType { struct RealLiteral { static constexpr auto Kind = - InstKind::RealLiteral.Define( - "real_literal", InstConstantKind::Always); + InstKind::RealLiteral.Define("real_literal"); TypeId type_id; RealId real_id; @@ -699,8 +690,7 @@ struct SpliceBlock { struct StringLiteral { static constexpr auto Kind = - InstKind::StringLiteral.Define( - "string_literal", InstConstantKind::Always); + InstKind::StringLiteral.Define("string_literal"); TypeId type_id; StringLiteralValueId string_literal_id; @@ -737,8 +727,8 @@ struct StructLiteral { struct StructType { // TODO: Make this more specific. It can be one of: ClassDefinitionId, // StructLiteralId, StructTypeLiteralId - static constexpr auto Kind = InstKind::StructType.Define( - "struct_type", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::StructType.Define("struct_type"); TypeId type_id; InstBlockId fields_id; @@ -746,8 +736,8 @@ struct StructType { struct StructTypeField { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::StructTypeField.Define( - "struct_type_field", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::StructTypeField.Define("struct_type_field"); // This instruction is an implementation detail of `StructType`, and doesn't // produce a value, so has no type, even though it declares a field with a @@ -758,8 +748,8 @@ struct StructTypeField { struct StructValue { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::StructValue.Define( - "struct_value", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::StructValue.Define("struct_value"); TypeId type_id; InstBlockId elements_id; @@ -822,8 +812,8 @@ struct TupleLiteral { struct TupleType { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::TupleType.Define( - "tuple_type", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::TupleType.Define("tuple_type"); TypeId type_id; TypeBlockId elements_id; @@ -831,8 +821,8 @@ struct TupleType { struct TupleValue { // TODO: Make Parse::NodeId more specific. - static constexpr auto Kind = InstKind::TupleValue.Define( - "tuple_value", InstConstantKind::Conditional); + static constexpr auto Kind = + InstKind::TupleValue.Define("tuple_value"); TypeId type_id; InstBlockId elements_id; @@ -853,7 +843,7 @@ struct UnaryOperatorNot { struct UnboundElementType { static constexpr auto Kind = InstKind::UnboundElementType.Define< Parse::NodeIdOneOf>( - "unbound_element_type", InstConstantKind::Conditional); + "unbound_element_type"); TypeId type_id; // The class that a value of this type is an element of.