From 57090142e8e807ef9ab12ed94a616ce363b78a8f Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Fri, 28 Oct 2022 14:16:51 -0700 Subject: [PATCH] Start adding builtins to SemanticsIR (#2356) This starts adding builtins with TypeType and IntegerLiteralType. Note, structurally that's all they are, and not directly accessible in any way. Adds a type field to SemanticsNode. Now, IntegerLiteralType can be identified as having type=TypeType, and IntegerLiteral as type=IntegerLiteralType. The current iteration doesn't do anything for type propagation, because I wanted to avoid making this too big. This also switches the Identifier IR to instead BindName, with some side-effects. I'd been trying to think how to provide a name for TypeType, and switching around how things worked seemed like a better approach. And while I think it's the right direction (e.g., alias should just be a BindName), I also realized I don't need to name TypeType: there's probably a keyword to refer to the builtin, so it shouldn't use regular name lookup. --- toolchain/driver/driver.cpp | 5 +- toolchain/semantics/BUILD | 12 ++ .../semantics/semantics_builtin_kind.cpp | 19 +++ .../semantics/semantics_builtin_kind.def | 23 ++++ toolchain/semantics/semantics_builtin_kind.h | 78 ++++++++++++ toolchain/semantics/semantics_ir.cpp | 52 +++++++- toolchain/semantics/semantics_ir.h | 70 ++++++++++- toolchain/semantics/semantics_node.cpp | 5 + toolchain/semantics/semantics_node.h | 119 ++++++++++++------ toolchain/semantics/semantics_node_kind.def | 3 +- .../semantics_parse_tree_handler.cpp | 23 ++-- .../semantics/semantics_parse_tree_handler.h | 4 +- .../testdata/{ => basics}/empty.carbon | 5 + .../semantics/testdata/function/basic.carbon | 11 +- .../semantics/testdata/function/order.carbon | 23 ++-- .../testdata/return/binary_op.carbon | 15 ++- .../semantics/testdata/return/literal.carbon | 13 +- .../semantics/testdata/return/trivial.carbon | 11 +- 18 files changed, 410 insertions(+), 81 deletions(-) create mode 100644 toolchain/semantics/semantics_builtin_kind.cpp create mode 100644 toolchain/semantics/semantics_builtin_kind.def create mode 100644 toolchain/semantics/semantics_builtin_kind.h rename toolchain/semantics/testdata/{ => basics}/empty.carbon (66%) diff --git a/toolchain/driver/driver.cpp b/toolchain/driver/driver.cpp index dcdfbe07c9c1..485f7ed31fa5 100644 --- a/toolchain/driver/driver.cpp +++ b/toolchain/driver/driver.cpp @@ -162,8 +162,9 @@ auto Driver::RunDumpSubcommand(DiagnosticConsumer& consumer, return !tokenized_source.has_errors() && !parse_tree.has_errors(); } - SemanticsIR semantics_ir; - semantics_ir.Build(tokenized_source, parse_tree); + const SemanticsIR builtin_ir = SemanticsIR::MakeBuiltinIR(); + const SemanticsIR semantics_ir = + SemanticsIR::MakeFromParseTree(builtin_ir, tokenized_source, parse_tree); if (dump_mode == DumpMode::SemanticsIR) { consumer.Flush(); semantics_ir.Print(output_stream_); diff --git a/toolchain/semantics/BUILD b/toolchain/semantics/BUILD index d0943b1b2846..46490fa955f2 100644 --- a/toolchain/semantics/BUILD +++ b/toolchain/semantics/BUILD @@ -4,6 +4,17 @@ package(default_visibility = ["//visibility:public"]) +cc_library( + name = "semantics_builtin_kind", + srcs = ["semantics_builtin_kind.cpp"], + hdrs = ["semantics_builtin_kind.h"], + textual_hdrs = ["semantics_builtin_kind.def"], + deps = [ + "//common:ostream", + "@llvm-project//llvm:Support", + ], +) + cc_library( name = "semantics_node_kind", srcs = ["semantics_node_kind.cpp"], @@ -28,6 +39,7 @@ cc_library( "semantics_node.h", ], deps = [ + ":semantics_builtin_kind", ":semantics_node_kind", "//common:check", "//common:ostream", diff --git a/toolchain/semantics/semantics_builtin_kind.cpp b/toolchain/semantics/semantics_builtin_kind.cpp new file mode 100644 index 000000000000..83dfb40e7062 --- /dev/null +++ b/toolchain/semantics/semantics_builtin_kind.cpp @@ -0,0 +1,19 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/semantics/semantics_builtin_kind.h" + +#include "llvm/ADT/StringRef.h" + +namespace Carbon { + +auto SemanticsBuiltinKind::name() const -> llvm::StringRef { + static constexpr llvm::StringLiteral Names[] = { +#define CARBON_SEMANTICS_BUILTIN_KIND(Name) #Name, +#include "toolchain/semantics/semantics_builtin_kind.def" + }; + return Names[static_cast(kind_)]; +} + +} // namespace Carbon diff --git a/toolchain/semantics/semantics_builtin_kind.def b/toolchain/semantics/semantics_builtin_kind.def new file mode 100644 index 000000000000..7db2db32c579 --- /dev/null +++ b/toolchain/semantics/semantics_builtin_kind.def @@ -0,0 +1,23 @@ +// 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 +// +// Note that this is an X-macro header. +// +// It does not use `#include` guards, and instead is designed to be `#include`ed +// after the x-macro is defined in order for its inclusion to expand to the +// desired output. The x-macro for this header is `CARBON_PARSE_NODE_KIND`. The +// definition provided will be removed at the end of this file to clean up. + +#ifndef CARBON_SEMANTICS_BUILTIN_KIND +#error "Must define the x-macro to use this file." +#endif + +CARBON_SEMANTICS_BUILTIN_KIND(TypeType) +CARBON_SEMANTICS_BUILTIN_KIND(IntegerLiteralType) + +// Keep invalid last, so that we can use values as array indices without needing +// an invalid entry. +CARBON_SEMANTICS_BUILTIN_KIND(Invalid) + +#undef CARBON_SEMANTICS_BUILTIN_KIND diff --git a/toolchain/semantics/semantics_builtin_kind.h b/toolchain/semantics/semantics_builtin_kind.h new file mode 100644 index 000000000000..f6bb81d9ddea --- /dev/null +++ b/toolchain/semantics/semantics_builtin_kind.h @@ -0,0 +1,78 @@ +// 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_SEMANTICS_SEMANTICS_BUILTIN_KIND_H_ +#define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_BUILTIN_KIND_H_ + +#include + +#include "common/ostream.h" + +namespace Carbon { + +class SemanticsBuiltinKind { + private: + // Note that this must be declared earlier in the class so that its type can + // be used, for example in the conversion operator. + enum class KindEnum : uint8_t { +#define CARBON_SEMANTICS_BUILTIN_KIND(Name) Name, +#include "toolchain/semantics/semantics_builtin_kind.def" + }; + + public: + // The count of enum values excluding Invalid. + static constexpr uint8_t ValidCount = static_cast(KindEnum::Invalid); + + // `clang-format` has a bug with spacing around `->` returns in macros. See + // https://bugs.llvm.org/show_bug.cgi?id=48320 for details. +#define CARBON_SEMANTICS_BUILTIN_KIND(Name) \ + static constexpr auto Name()->SemanticsBuiltinKind { \ + return SemanticsBuiltinKind(KindEnum::Name); \ + } +#include "toolchain/semantics/semantics_builtin_kind.def" + + // The default constructor is deleted because objects of this type should + // always be constructed using the above factory functions for each unique + // kind. + SemanticsBuiltinKind() = delete; + + friend auto operator==(SemanticsBuiltinKind lhs, SemanticsBuiltinKind rhs) + -> bool { + return lhs.kind_ == rhs.kind_; + } + friend auto operator!=(SemanticsBuiltinKind lhs, SemanticsBuiltinKind rhs) + -> bool { + return lhs.kind_ != rhs.kind_; + } + + // Gets a friendly name for the token for logging or debugging. + [[nodiscard]] auto name() const -> llvm::StringRef; + + // Support conversion to and from an int32_t for SemanticNode storage. + auto AsInt() -> int32_t { return static_cast(kind_); } + static auto FromInt(int32_t val) -> SemanticsBuiltinKind { + return SemanticsBuiltinKind(static_cast(val)); + } + + // Enable conversion to our private enum, including in a `constexpr` + // context, to enable usage in `switch` and `case`. The enum remains + // private and nothing else should be using this function. + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr operator KindEnum() const { return kind_; } + + void Print(llvm::raw_ostream& out) const { out << name(); } + + private: + constexpr explicit SemanticsBuiltinKind(KindEnum k) : kind_(k) {} + + KindEnum kind_; +}; + +// We expect the builtin kind to fit compactly into 8 bits. +static_assert(sizeof(SemanticsBuiltinKind) == 1, + "Kind objects include padding!"); + +} // namespace Carbon + +#endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_BUILTIN_KIND_H_ diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index 972749f1f000..0634c192ca10 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -7,19 +7,65 @@ #include "common/check.h" #include "llvm/Support/FormatVariadic.h" #include "toolchain/lexer/tokenized_buffer.h" +#include "toolchain/semantics/semantics_builtin_kind.h" #include "toolchain/semantics/semantics_node.h" #include "toolchain/semantics/semantics_parse_tree_handler.h" namespace Carbon { -auto SemanticsIR::Build(const TokenizedBuffer& tokens, - const ParseTree& parse_tree) -> void { - SemanticsParseTreeHandler(tokens, parse_tree, *this).Build(); +auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR { + SemanticsIR semantics; + static constexpr auto BuiltinIR = SemanticsCrossReferenceIRId(0); + auto block_id = semantics.AddNodeBlock(); + semantics.cross_references_.resize_for_overwrite( + SemanticsBuiltinKind::ValidCount); + + // TODO: The type-type should be replaced with a constraint. It will probably + // remain a builtin, just reimplemented as equivalent to `constraint type {}`. + auto builtin_type_type = semantics.AddNode( + block_id, SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::TypeType(), + SemanticsNodeId(0))); + semantics.cross_references_[SemanticsBuiltinKind::TypeType().AsInt()] = + SemanticsCrossReference(BuiltinIR, block_id, builtin_type_type); + CARBON_CHECK(builtin_type_type.id == 0) + << "TypeType's type must be self-referential."; + + auto builtin_int32 = semantics.AddNode( + block_id, + SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::IntegerLiteralType(), + builtin_type_type)); + semantics + .cross_references_[SemanticsBuiltinKind::IntegerLiteralType().AsInt()] = + SemanticsCrossReference(BuiltinIR, block_id, builtin_int32); + + CARBON_CHECK(semantics.node_blocks_.size() == 1) + << "BuildBuiltins should only produce 1 block, actual: " + << semantics.node_blocks_.size(); + return semantics; +} + +auto SemanticsIR::MakeFromParseTree(const SemanticsIR& builtin_ir, + const TokenizedBuffer& tokens, + const ParseTree& parse_tree) + -> SemanticsIR { + SemanticsIR semantics(builtin_ir); + SemanticsParseTreeHandler(tokens, parse_tree, semantics).Build(); + return semantics; } auto SemanticsIR::Print(llvm::raw_ostream& out) const -> void { constexpr int Indent = 2; + out << "cross_reference_irs.size == " << cross_reference_irs_.size() << ",\n"; + + out << "cross_references = {\n"; + for (int32_t i = 0; i < static_cast(cross_references_.size()); ++i) { + out.indent(Indent); + out << SemanticsNodeId::MakeCrossReference(i) << " = \"" + << cross_references_[i] << "\";\n"; + } + out << "},\n"; + out << "identifiers = {\n"; for (int32_t i = 0; i < static_cast(identifiers_.size()); ++i) { out.indent(Indent); diff --git a/toolchain/semantics/semantics_ir.h b/toolchain/semantics/semantics_ir.h index 92d60dcecc87..98878f856462 100644 --- a/toolchain/semantics/semantics_ir.h +++ b/toolchain/semantics/semantics_ir.h @@ -16,12 +16,43 @@ class SemanticsIRForTest; namespace Carbon { +// The ID of a cross-referenced IR (within cross_reference_irs_). +struct SemanticsCrossReferenceIRId { + SemanticsCrossReferenceIRId() : id(-1) {} + constexpr explicit SemanticsCrossReferenceIRId(int32_t id) : id(id) {} + + auto Print(llvm::raw_ostream& out) const -> void { out << "ir" << id; } + + int32_t id; +}; + +// A cross-reference between node blocks or IRs; essentially, anything that's +// not in the same SemanticsNodeBlock as the referencing node. +struct SemanticsCrossReference { + SemanticsCrossReference() = default; + SemanticsCrossReference(SemanticsCrossReferenceIRId ir, + SemanticsNodeBlockId node_block, SemanticsNodeId node) + : ir(ir), node_block(node_block), node(node) {} + + auto Print(llvm::raw_ostream& out) const -> void { + out << "xref(" << ir << ", " << node_block << ", " << node << ")"; + } + + SemanticsCrossReferenceIRId ir; + SemanticsNodeBlockId node_block; + SemanticsNodeId node; +}; + // Provides semantic analysis on a ParseTree. class SemanticsIR { public: + // Produces the builtins. + static auto MakeBuiltinIR() -> SemanticsIR; + // Adds the IR for the provided ParseTree. - auto Build(const TokenizedBuffer& tokens, const ParseTree& parse_tree) - -> void; + static auto MakeFromParseTree(const SemanticsIR& builtin_ir, + const TokenizedBuffer& tokens, + const ParseTree& parse_tree) -> SemanticsIR; // Prints the full IR. auto Print(llvm::raw_ostream& out) const -> void; @@ -29,12 +60,23 @@ class SemanticsIR { private: friend class SemanticsParseTreeHandler; + // For the builtin IR only. + SemanticsIR() : SemanticsIR(*this) {} + // For most IRs. + SemanticsIR(const SemanticsIR& builtins) + : cross_reference_irs_({&builtins, this}), + cross_references_(builtins.cross_references_) {} + + // Adds an identifier, returning an ID to reference it. + // TODO: Deduplicate strings. + // TODO: Probably make generic for all strings, including literals. auto AddIdentifier(llvm::StringRef identifier) -> SemanticsIdentifierId { SemanticsIdentifierId id(identifiers_.size()); identifiers_.push_back(identifier); return id; } + // Adds an integer literal, returning an ID to reference it. auto AddIntegerLiteral(llvm::APInt integer_literal) -> SemanticsIntegerLiteralId { SemanticsIntegerLiteralId id(integer_literals_.size()); @@ -42,22 +84,42 @@ class SemanticsIR { return id; } - // Starts a new node block. + // Adds an empty new node block, returning an ID to reference it and add + // items. auto AddNodeBlock() -> SemanticsNodeBlockId { SemanticsNodeBlockId id(node_blocks_.size()); node_blocks_.resize(node_blocks_.size() + 1); return id; } - auto AddNode(SemanticsNodeBlockId block_id, SemanticsNode node) { + // Adds a node to a specified block, returning an ID to reference the node. + auto AddNode(SemanticsNodeBlockId block_id, SemanticsNode node) + -> SemanticsNodeId { auto& block = node_blocks_[block_id.id]; SemanticsNodeId node_id(block.size()); block.push_back(node); return node_id; } + // Related IRs. There will always be at least 2 entries, the builtin IR (used + // for references of builtins) followed by the current IR (used for references + // crossing node blocks). + llvm::SmallVector cross_reference_irs_; + + // Cross-references within the current IR across node blocks, and to other + // IRs. The first entries will always be builtins, at indices matching + // SemanticsBuiltinKind ordering. + // TODO: Deduplicate cross-references after they can be added outside + // builtins. + llvm::SmallVector cross_references_; + + // Storage for identifiers. llvm::SmallVector identifiers_; + + // Storage for integer literals. llvm::SmallVector integer_literals_; + + // Storage for blocks within the IR. llvm::SmallVector> node_blocks_; }; diff --git a/toolchain/semantics/semantics_node.cpp b/toolchain/semantics/semantics_node.cpp index 2fe26ec57199..1f6337266a5a 100644 --- a/toolchain/semantics/semantics_node.cpp +++ b/toolchain/semantics/semantics_node.cpp @@ -4,6 +4,8 @@ #include "toolchain/semantics/semantics_node.h" +#include "toolchain/semantics/semantics_builtin_kind.h" + namespace Carbon { static auto PrintArgs(llvm::raw_ostream& /*out*/, @@ -29,6 +31,9 @@ void SemanticsNode::Print(llvm::raw_ostream& out) const { #include "toolchain/semantics/semantics_node_kind.def" } out << ")"; + if (type_.id != -1) { + out << ": " << type_; + } } } // namespace Carbon diff --git a/toolchain/semantics/semantics_node.h b/toolchain/semantics/semantics_node.h index 1785ffbb3870..a53b21095326 100644 --- a/toolchain/semantics/semantics_node.h +++ b/toolchain/semantics/semantics_node.h @@ -9,18 +9,45 @@ #include "common/check.h" #include "common/ostream.h" +#include "toolchain/semantics/semantics_builtin_kind.h" #include "toolchain/semantics/semantics_node_kind.h" namespace Carbon { // Type-safe storage of Node IDs. struct SemanticsNodeId { + static constexpr int32_t CrossReferenceBit = 0x8000'0000; + + // Constructs a cross-reference node ID. + static auto MakeCrossReference(int32_t id) -> SemanticsNodeId { + return SemanticsNodeId(id | CrossReferenceBit); + } + // Constructs a cross-reference node ID for a builtin. This relies on + // SemanticsIR guarantees for builtin cross-reference placement. + static auto MakeBuiltinReference(SemanticsBuiltinKind kind) + -> SemanticsNodeId { + return MakeCrossReference(kind.AsInt()); + } + SemanticsNodeId() : id(-1) {} explicit SemanticsNodeId(int32_t id) : id(id) {} SemanticsNodeId(SemanticsNodeId const&) = default; auto operator=(const SemanticsNodeId& other) -> SemanticsNodeId& = default; - void Print(llvm::raw_ostream& out) const { out << "node" << id; } + auto is_cross_reference() const -> bool { return id & CrossReferenceBit; } + // Returns the ID for a cross-reference, just handling removal of the marker + // bit. + auto GetAsCrossReference() const -> int32_t { + return id & ~CrossReferenceBit; + } + + auto Print(llvm::raw_ostream& out) const -> void { + if (is_cross_reference()) { + out << "node_xref" << GetAsCrossReference(); + } else { + out << "node" << id; + } + } int32_t id; }; @@ -30,7 +57,7 @@ struct SemanticsIdentifierId { SemanticsIdentifierId() : id(-1) {} explicit SemanticsIdentifierId(int32_t id) : id(id) {} - void Print(llvm::raw_ostream& out) const { out << "ident" << id; } + auto Print(llvm::raw_ostream& out) const -> void { out << "ident" << id; } int32_t id; }; @@ -40,7 +67,7 @@ struct SemanticsIntegerLiteralId { SemanticsIntegerLiteralId() : id(-1) {} explicit SemanticsIntegerLiteralId(int32_t id) : id(id) {} - void Print(llvm::raw_ostream& out) const { out << "int" << id; } + auto Print(llvm::raw_ostream& out) const -> void { out << "int" << id; } int32_t id; }; @@ -50,7 +77,7 @@ struct SemanticsNodeBlockId { SemanticsNodeBlockId() : id(-1) {} explicit SemanticsNodeBlockId(int32_t id) : id(id) {} - void Print(llvm::raw_ostream& out) const { out << "block" << id; } + auto Print(llvm::raw_ostream& out) const -> void { out << "block" << id; } int32_t id; }; @@ -64,8 +91,8 @@ class SemanticsNode { static auto MakeBinaryOperatorAdd(SemanticsNodeId lhs, SemanticsNodeId rhs) -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::BinaryOperatorAdd(), lhs.id, - rhs.id); + return SemanticsNode(SemanticsNodeKind::BinaryOperatorAdd(), + SemanticsNodeId(), lhs.id, rhs.id); } auto GetAsBinaryOperatorAdd() const -> std::pair { @@ -73,27 +100,51 @@ class SemanticsNode { return {SemanticsNodeId(arg0_), SemanticsNodeId(arg1_)}; } + static auto MakeBindName(SemanticsIdentifierId name, SemanticsNodeId node) + -> SemanticsNode { + return SemanticsNode(SemanticsNodeKind::BindName(), SemanticsNodeId(), + name.id, node.id); + } + auto GetAsBindName() const + -> std::pair { + CARBON_CHECK(kind_ == SemanticsNodeKind::BindName()); + return {SemanticsIdentifierId(arg0_), SemanticsNodeId(arg1_)}; + } + + static auto MakeBuiltin(SemanticsBuiltinKind builtin_kind, + SemanticsNodeId type) -> SemanticsNode { + return SemanticsNode(SemanticsNodeKind::Builtin(), type, + builtin_kind.AsInt()); + } + auto GetAsBuiltin() const -> SemanticsBuiltinKind { + CARBON_CHECK(kind_ == SemanticsNodeKind::Builtin()); + return SemanticsBuiltinKind::FromInt(arg0_); + } + static auto MakeCodeBlock(SemanticsNodeBlockId node_block) -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::CodeBlock(), node_block.id); + return SemanticsNode(SemanticsNodeKind::CodeBlock(), SemanticsNodeId(), + node_block.id); } auto GetAsCodeBlock() const -> SemanticsNodeBlockId { CARBON_CHECK(kind_ == SemanticsNodeKind::CodeBlock()); return SemanticsNodeBlockId(arg0_); } - static auto MakeFunctionDeclaration(SemanticsNodeId name) -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::FunctionDeclaration(), name.id); + // TODO: The signature should be added as a parameter. + static auto MakeFunctionDeclaration() -> SemanticsNode { + return SemanticsNode(SemanticsNodeKind::FunctionDeclaration(), + SemanticsNodeId()); } - auto GetAsFunctionDeclaration() const -> SemanticsNodeId { + auto GetAsFunctionDeclaration() const -> NoArgs { CARBON_CHECK(kind_ == SemanticsNodeKind::FunctionDeclaration()); - return SemanticsNodeId(arg0_); + return {}; } static auto MakeFunctionDefinition(SemanticsNodeId decl, SemanticsNodeBlockId node_block) -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::FunctionDefinition(), decl.id, - node_block.id); + return SemanticsNode(SemanticsNodeKind::FunctionDefinition(), + SemanticsNodeId(), decl.id, node_block.id); } auto GetAsFunctionDefinition() const -> std::pair { @@ -101,18 +152,12 @@ class SemanticsNode { return {SemanticsNodeId(arg0_), SemanticsNodeBlockId(arg1_)}; } - static auto MakeIdentifier(SemanticsIdentifierId identifier) - -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::Identifier(), identifier.id); - } - auto GetAsIdentifier() const -> SemanticsIdentifierId { - CARBON_CHECK(kind_ == SemanticsNodeKind::Identifier()); - return SemanticsIdentifierId(arg0_); - } - static auto MakeIntegerLiteral(SemanticsIntegerLiteralId integer) -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::IntegerLiteral(), integer.id); + return SemanticsNode(SemanticsNodeKind::IntegerLiteral(), + SemanticsNodeId::MakeBuiltinReference( + SemanticsBuiltinKind::IntegerLiteralType()), + integer.id); } auto GetAsIntegerLiteral() const -> SemanticsIntegerLiteralId { CARBON_CHECK(kind_ == SemanticsNodeKind::IntegerLiteral()); @@ -120,7 +165,7 @@ class SemanticsNode { } static auto MakeReturn() -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::Return()); + return SemanticsNode(SemanticsNodeKind::Return(), SemanticsNodeId()); } auto GetAsReturn() const -> NoArgs { CARBON_CHECK(kind_ == SemanticsNodeKind::Return()); @@ -128,34 +173,38 @@ class SemanticsNode { } static auto MakeReturnExpression(SemanticsNodeId expr) -> SemanticsNode { - return SemanticsNode(SemanticsNodeKind::ReturnExpression(), expr.id); + return SemanticsNode(SemanticsNodeKind::ReturnExpression(), + SemanticsNodeId(), expr.id); } auto GetAsReturnExpression() const -> SemanticsNodeId { CARBON_CHECK(kind_ == SemanticsNodeKind::ReturnExpression()); return SemanticsNodeId(arg0_); } - SemanticsNode() : SemanticsNode(SemanticsNodeKind::Invalid()) {} + SemanticsNode() + : SemanticsNode(SemanticsNodeKind::Invalid(), SemanticsNodeId()) {} auto kind() -> SemanticsNodeKind { return kind_; } + auto type() -> SemanticsNodeId { return type_; } - void Print(llvm::raw_ostream& out) const; + auto Print(llvm::raw_ostream& out) const -> void; private: - explicit SemanticsNode(SemanticsNodeKind kind, int32_t arg0 = -1, - int32_t arg1 = -1) - : kind_(kind), arg0_(arg0), arg1_(arg1) {} + explicit SemanticsNode(SemanticsNodeKind kind, SemanticsNodeId type, + int32_t arg0 = -1, int32_t arg1 = -1) + : kind_(kind), type_(type), arg0_(arg0), arg1_(arg1) {} SemanticsNodeKind kind_; + SemanticsNodeId type_; int32_t arg0_; int32_t arg1_; }; -// TODO: This is currently 12 bytes because we sometimes have 2 arguments for a -// pair of SemanticsNodes. If SemanticsNode was tracked in 3.5 bytes, we could -// potentially change SemanticsNode to 8 bytes. This may be worth investigating -// further. -static_assert(sizeof(SemanticsNode) == 12, "Unexpected SemanticsNode size"); +// TODO: This is currently 16 bytes because we sometimes have 2 arguments for a +// pair of SemanticsNodes. However, SemanticsNodeKind is 1 byte; if args +// were 3.5 bytes, we could potentially shrink SemanticsNode by 4 bytes. This +// may be worth investigating further. +static_assert(sizeof(SemanticsNode) == 16, "Unexpected SemanticsNode size"); } // namespace Carbon diff --git a/toolchain/semantics/semantics_node_kind.def b/toolchain/semantics/semantics_node_kind.def index e06c4d13e8c2..896b9762799c 100644 --- a/toolchain/semantics/semantics_node_kind.def +++ b/toolchain/semantics/semantics_node_kind.def @@ -16,10 +16,11 @@ CARBON_SEMANTICS_NODE_KIND(Invalid) CARBON_SEMANTICS_NODE_KIND(BinaryOperatorAdd) +CARBON_SEMANTICS_NODE_KIND(BindName) +CARBON_SEMANTICS_NODE_KIND(Builtin) CARBON_SEMANTICS_NODE_KIND(CodeBlock) CARBON_SEMANTICS_NODE_KIND(FunctionDeclaration) CARBON_SEMANTICS_NODE_KIND(FunctionDefinition) -CARBON_SEMANTICS_NODE_KIND(Identifier) CARBON_SEMANTICS_NODE_KIND(IntegerLiteral) CARBON_SEMANTICS_NODE_KIND(Return) CARBON_SEMANTICS_NODE_KIND(ReturnExpression) diff --git a/toolchain/semantics/semantics_parse_tree_handler.cpp b/toolchain/semantics/semantics_parse_tree_handler.cpp index c34673f61972..18bcf80cde96 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.cpp +++ b/toolchain/semantics/semantics_parse_tree_handler.cpp @@ -19,10 +19,6 @@ auto SemanticsParseTreeHandler::Build() -> void { for (auto it = range.begin();; ++it) { auto parse_node = *it; switch (auto parse_kind = parse_tree_->node_kind(parse_node)) { - case ParseNodeKind::DeclaredName(): { - HandleDeclaredName(parse_node); - break; - } case ParseNodeKind::FunctionDefinition(): { HandleFunctionDefinition(parse_node); break; @@ -55,6 +51,7 @@ auto SemanticsParseTreeHandler::Build() -> void { HandleReturnStatement(parse_node); break; } + case ParseNodeKind::DeclaredName(): case ParseNodeKind::FunctionIntroducer(): case ParseNodeKind::ParameterListEnd(): case ParseNodeKind::StatementEnd(): { @@ -112,11 +109,13 @@ auto SemanticsParseTreeHandler::PopWithResult(ParseNodeKind pop_parse_kind) return node_id; } -auto SemanticsParseTreeHandler::HandleDeclaredName(ParseTree::Node parse_node) - -> void { - auto text = parse_tree_->GetNodeText(parse_node); - auto identifier_id = semantics_->AddIdentifier(text); - Push(parse_node, SemanticsNode::MakeIdentifier(identifier_id)); +auto SemanticsParseTreeHandler::AddIdentifier(ParseTree::Node decl_node) + -> SemanticsIdentifierId { + CARBON_CHECK(parse_tree_->node_kind(decl_node) == + ParseNodeKind::DeclaredName()) + << parse_tree_->node_kind(decl_node); + auto text = parse_tree_->GetNodeText(decl_node); + return semantics_->AddIdentifier(text); } auto SemanticsParseTreeHandler::HandleFunctionDefinition( @@ -134,10 +133,12 @@ auto SemanticsParseTreeHandler::HandleFunctionDefinition( auto SemanticsParseTreeHandler::HandleFunctionDefinitionStart( ParseTree::Node parse_node) -> void { Pop(ParseNodeKind::ParameterList()); - auto name_node_id = PopWithResult(ParseNodeKind::DeclaredName()); + auto name = AddIdentifier(node_stack_.back().parse_node); + node_stack_.pop_back(); Pop(ParseNodeKind::FunctionIntroducer()); - auto decl_id = AddNode(SemanticsNode::MakeFunctionDeclaration(name_node_id)); + auto decl_id = AddNode(SemanticsNode::MakeFunctionDeclaration()); + AddNode(SemanticsNode::MakeBindName(name, decl_id)); auto block_id = semantics_->AddNodeBlock(); AddNode(SemanticsNode::MakeFunctionDefinition(decl_id, block_id)); node_block_stack_.push_back(block_id); diff --git a/toolchain/semantics/semantics_parse_tree_handler.h b/toolchain/semantics/semantics_parse_tree_handler.h index 3b9e7b2effa7..495f51717a7a 100644 --- a/toolchain/semantics/semantics_parse_tree_handler.h +++ b/toolchain/semantics/semantics_parse_tree_handler.h @@ -5,7 +5,6 @@ #ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_ #define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_PARSE_TREE_HANDLER_H_ -#include "common/check.h" #include "toolchain/parser/parse_tree.h" #include "toolchain/semantics/semantics_ir.h" #include "toolchain/semantics/semantics_node.h" @@ -30,6 +29,9 @@ class SemanticsParseTreeHandler { llvm::Optional result_id; }; + // Adds an identifier for a DeclaredName node, returning its reference. + auto AddIdentifier(ParseTree::Node decl_node) -> SemanticsIdentifierId; + // Adds a node to the current block, returning the produced ID. auto AddNode(SemanticsNode node) -> SemanticsNodeId; diff --git a/toolchain/semantics/testdata/empty.carbon b/toolchain/semantics/testdata/basics/empty.carbon similarity index 66% rename from toolchain/semantics/testdata/empty.carbon rename to toolchain/semantics/testdata/basics/empty.carbon index 91759c81afce..aed964adfc55 100644 --- a/toolchain/semantics/testdata/empty.carbon +++ b/toolchain/semantics/testdata/basics/empty.carbon @@ -4,6 +4,11 @@ // // AUTOUPDATE // RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; +// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: }, // CHECK:STDOUT: integer_literals = { diff --git a/toolchain/semantics/testdata/function/basic.carbon b/toolchain/semantics/testdata/function/basic.carbon index eb6f41cc4203..6d7cd85795a6 100644 --- a/toolchain/semantics/testdata/function/basic.carbon +++ b/toolchain/semantics/testdata/function/basic.carbon @@ -4,6 +4,11 @@ // // AUTOUPDATE // RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; +// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Foo"; // CHECK:STDOUT: }, @@ -11,9 +16,9 @@ // CHECK:STDOUT: }, // CHECK:STDOUT: node_blocks = { // CHECK:STDOUT: block0 = { -// CHECK:STDOUT: node0 = Identifier(ident0); -// CHECK:STDOUT: node1 = FunctionDeclaration(node0); -// CHECK:STDOUT: node2 = FunctionDefinition(node1, block1); +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); // CHECK:STDOUT: }, // CHECK:STDOUT: block1 = { // CHECK:STDOUT: }, diff --git a/toolchain/semantics/testdata/function/order.carbon b/toolchain/semantics/testdata/function/order.carbon index 52b2b357c83a..5dea70875fba 100644 --- a/toolchain/semantics/testdata/function/order.carbon +++ b/toolchain/semantics/testdata/function/order.carbon @@ -4,6 +4,11 @@ // // AUTOUPDATE // RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; +// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Foo"; // CHECK:STDOUT: ident1 = "Bar"; @@ -13,15 +18,15 @@ // CHECK:STDOUT: }, // CHECK:STDOUT: node_blocks = { // CHECK:STDOUT: block0 = { -// CHECK:STDOUT: node0 = Identifier(ident0); -// CHECK:STDOUT: node1 = FunctionDeclaration(node0); -// CHECK:STDOUT: node2 = FunctionDefinition(node1, block1); -// CHECK:STDOUT: node3 = Identifier(ident1); -// CHECK:STDOUT: node4 = FunctionDeclaration(node3); -// CHECK:STDOUT: node5 = FunctionDefinition(node4, block2); -// CHECK:STDOUT: node6 = Identifier(ident2); -// CHECK:STDOUT: node7 = FunctionDeclaration(node6); -// CHECK:STDOUT: node8 = FunctionDefinition(node7, block3); +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); +// CHECK:STDOUT: node3 = FunctionDeclaration(); +// CHECK:STDOUT: node4 = BindName(ident1, node3); +// CHECK:STDOUT: node5 = FunctionDefinition(node3, block2); +// CHECK:STDOUT: node6 = FunctionDeclaration(); +// CHECK:STDOUT: node7 = BindName(ident2, node6); +// CHECK:STDOUT: node8 = FunctionDefinition(node6, block3); // CHECK:STDOUT: }, // CHECK:STDOUT: block1 = { // CHECK:STDOUT: }, diff --git a/toolchain/semantics/testdata/return/binary_op.carbon b/toolchain/semantics/testdata/return/binary_op.carbon index b11a405b3545..ea93800e9ea4 100644 --- a/toolchain/semantics/testdata/return/binary_op.carbon +++ b/toolchain/semantics/testdata/return/binary_op.carbon @@ -4,6 +4,11 @@ // // AUTOUPDATE // RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; +// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Main"; // CHECK:STDOUT: }, @@ -13,13 +18,13 @@ // CHECK:STDOUT: }, // CHECK:STDOUT: node_blocks = { // CHECK:STDOUT: block0 = { -// CHECK:STDOUT: node0 = Identifier(ident0); -// CHECK:STDOUT: node1 = FunctionDeclaration(node0); -// CHECK:STDOUT: node2 = FunctionDefinition(node1, block1); +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); // CHECK:STDOUT: }, // CHECK:STDOUT: block1 = { -// CHECK:STDOUT: node0 = IntegerLiteral(int0); -// CHECK:STDOUT: node1 = IntegerLiteral(int1); +// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref1; +// CHECK:STDOUT: node1 = IntegerLiteral(int1): node_xref1; // CHECK:STDOUT: node2 = BinaryOperatorAdd(node0, node1); // CHECK:STDOUT: node3 = ReturnExpression(node2); // CHECK:STDOUT: }, diff --git a/toolchain/semantics/testdata/return/literal.carbon b/toolchain/semantics/testdata/return/literal.carbon index 0930f83e6897..c2dac54a9978 100644 --- a/toolchain/semantics/testdata/return/literal.carbon +++ b/toolchain/semantics/testdata/return/literal.carbon @@ -4,6 +4,11 @@ // // AUTOUPDATE // RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; +// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Main"; // CHECK:STDOUT: }, @@ -12,12 +17,12 @@ // CHECK:STDOUT: }, // CHECK:STDOUT: node_blocks = { // CHECK:STDOUT: block0 = { -// CHECK:STDOUT: node0 = Identifier(ident0); -// CHECK:STDOUT: node1 = FunctionDeclaration(node0); -// CHECK:STDOUT: node2 = FunctionDefinition(node1, block1); +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); // CHECK:STDOUT: }, // CHECK:STDOUT: block1 = { -// CHECK:STDOUT: node0 = IntegerLiteral(int0); +// CHECK:STDOUT: node0 = IntegerLiteral(int0): node_xref1; // CHECK:STDOUT: node1 = ReturnExpression(node0); // CHECK:STDOUT: }, // CHECK:STDOUT: } diff --git a/toolchain/semantics/testdata/return/trivial.carbon b/toolchain/semantics/testdata/return/trivial.carbon index 340dda775cb4..0928a9360cf2 100644 --- a/toolchain/semantics/testdata/return/trivial.carbon +++ b/toolchain/semantics/testdata/return/trivial.carbon @@ -4,6 +4,11 @@ // // AUTOUPDATE // RUN: %{carbon-run-semantics} +// CHECK:STDOUT: cross_reference_irs.size == 2, +// CHECK:STDOUT: cross_references = { +// CHECK:STDOUT: node_xref0 = "xref(ir0, block0, node0)"; +// CHECK:STDOUT: node_xref1 = "xref(ir0, block0, node1)"; +// CHECK:STDOUT: }, // CHECK:STDOUT: identifiers = { // CHECK:STDOUT: ident0 = "Main"; // CHECK:STDOUT: }, @@ -11,9 +16,9 @@ // CHECK:STDOUT: }, // CHECK:STDOUT: node_blocks = { // CHECK:STDOUT: block0 = { -// CHECK:STDOUT: node0 = Identifier(ident0); -// CHECK:STDOUT: node1 = FunctionDeclaration(node0); -// CHECK:STDOUT: node2 = FunctionDefinition(node1, block1); +// CHECK:STDOUT: node0 = FunctionDeclaration(); +// CHECK:STDOUT: node1 = BindName(ident0, node0); +// CHECK:STDOUT: node2 = FunctionDefinition(node0, block1); // CHECK:STDOUT: }, // CHECK:STDOUT: block1 = { // CHECK:STDOUT: node0 = Return();