semantics_ir.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_H_
  5. #define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_H_
  6. #include "llvm/ADT/ArrayRef.h"
  7. #include "llvm/ADT/SmallVector.h"
  8. #include "toolchain/lexer/numeric_literal.h"
  9. #include "toolchain/parser/parse_tree.h"
  10. #include "toolchain/semantics/semantics_node.h"
  11. namespace Carbon::Testing {
  12. class SemanticsIRForTest;
  13. } // namespace Carbon::Testing
  14. namespace Carbon {
  15. // The ID of a cross-referenced IR (within cross_reference_irs_).
  16. struct SemanticsCrossReferenceIRId : public IndexBase {
  17. using IndexBase::IndexBase;
  18. auto Print(llvm::raw_ostream& out) const -> void { out << "ir" << index; }
  19. };
  20. // A cross-reference between node blocks or IRs; essentially, anything that's
  21. // not in the same SemanticsNodeBlock as the referencing node.
  22. struct SemanticsCrossReference {
  23. SemanticsCrossReference() = default;
  24. SemanticsCrossReference(SemanticsCrossReferenceIRId ir,
  25. SemanticsNodeBlockId node_block, SemanticsNodeId node)
  26. : ir(ir), node_block(node_block), node(node) {}
  27. auto Print(llvm::raw_ostream& out) const -> void {
  28. out << "xref(" << ir << ", " << node_block << ", " << node << ")";
  29. }
  30. SemanticsCrossReferenceIRId ir;
  31. SemanticsNodeBlockId node_block;
  32. SemanticsNodeId node;
  33. };
  34. // Provides semantic analysis on a ParseTree.
  35. class SemanticsIR {
  36. public:
  37. // Produces the builtins.
  38. static auto MakeBuiltinIR() -> SemanticsIR;
  39. // Adds the IR for the provided ParseTree.
  40. static auto MakeFromParseTree(const SemanticsIR& builtin_ir,
  41. const TokenizedBuffer& tokens,
  42. const ParseTree& parse_tree,
  43. DiagnosticConsumer& consumer,
  44. llvm::raw_ostream* vlog_stream) -> SemanticsIR;
  45. // Prints the full IR.
  46. auto Print(llvm::raw_ostream& out) const -> void;
  47. private:
  48. friend class SemanticsParseTreeHandler;
  49. // As noted under cross_reference_irs_, the current IR must always be at
  50. // index 1. This is a constant for that.
  51. static constexpr auto ThisIR = SemanticsCrossReferenceIRId(1);
  52. // For the builtin IR only.
  53. SemanticsIR() : SemanticsIR(*this) {}
  54. // For most IRs.
  55. SemanticsIR(const SemanticsIR& builtins)
  56. : cross_reference_irs_({&builtins, this}),
  57. cross_references_(builtins.cross_references_) {}
  58. auto GetType(SemanticsNodeBlockId block_id, SemanticsNodeId node_id)
  59. -> SemanticsNodeId {
  60. if (node_id.is_cross_reference()) {
  61. auto ref = cross_references_[node_id.GetAsCrossReference()];
  62. auto type = cross_reference_irs_[ref.ir.index]
  63. ->node_blocks_[ref.node_block.index][ref.node.index]
  64. .type();
  65. if (type.is_cross_reference() ||
  66. (ref.ir == ThisIR && ref.node_block == block_id)) {
  67. return type;
  68. } else {
  69. // TODO: If the type is a local reference within a block other than the
  70. // present one, we don't really want to add a cross reference at this
  71. // point. Does this mean types should be required to be cross
  72. // references? And maybe always with a presence in the current IR's
  73. // cross-references, so that equality is straightforward even though
  74. // resolving the actual type is a two-step process?
  75. CARBON_FATAL() << "Need to think more about this case";
  76. }
  77. } else {
  78. return node_blocks_[block_id.index][node_id.index].type();
  79. }
  80. }
  81. // Adds an identifier, returning an ID to reference it.
  82. // TODO: Deduplicate strings.
  83. // TODO: Probably make generic for all strings, including literals.
  84. auto AddIdentifier(llvm::StringRef identifier) -> SemanticsIdentifierId {
  85. SemanticsIdentifierId id(identifiers_.size());
  86. identifiers_.push_back(identifier);
  87. return id;
  88. }
  89. // Adds an integer literal, returning an ID to reference it.
  90. auto AddIntegerLiteral(llvm::APInt integer_literal)
  91. -> SemanticsIntegerLiteralId {
  92. SemanticsIntegerLiteralId id(integer_literals_.size());
  93. integer_literals_.push_back(integer_literal);
  94. return id;
  95. }
  96. // Adds an empty new node block, returning an ID to reference it and add
  97. // items.
  98. auto AddNodeBlock() -> SemanticsNodeBlockId {
  99. SemanticsNodeBlockId id(node_blocks_.size());
  100. node_blocks_.resize(node_blocks_.size() + 1);
  101. return id;
  102. }
  103. // Adds a node to a specified block, returning an ID to reference the node.
  104. auto AddNode(SemanticsNodeBlockId block_id, SemanticsNode node)
  105. -> SemanticsNodeId {
  106. auto& block = node_blocks_[block_id.index];
  107. SemanticsNodeId node_id(block.size());
  108. block.push_back(node);
  109. return node_id;
  110. }
  111. // Related IRs. There will always be at least 2 entries, the builtin IR (used
  112. // for references of builtins) followed by the current IR (used for references
  113. // crossing node blocks).
  114. llvm::SmallVector<const SemanticsIR*> cross_reference_irs_;
  115. // Cross-references within the current IR across node blocks, and to other
  116. // IRs. The first entries will always be builtins, at indices matching
  117. // SemanticsBuiltinKind ordering.
  118. // TODO: Deduplicate cross-references after they can be added outside
  119. // builtins.
  120. llvm::SmallVector<SemanticsCrossReference> cross_references_;
  121. // Storage for identifiers.
  122. llvm::SmallVector<llvm::StringRef> identifiers_;
  123. // Storage for integer literals.
  124. llvm::SmallVector<llvm::APInt> integer_literals_;
  125. // Storage for blocks within the IR.
  126. llvm::SmallVector<llvm::SmallVector<SemanticsNode>> node_blocks_;
  127. };
  128. } // namespace Carbon
  129. #endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_IR_H_