inst_namer.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221
  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. #include "toolchain/sem_ir/inst_namer.h"
  5. #include <string>
  6. #include <utility>
  7. #include <variant>
  8. #include "common/ostream.h"
  9. #include "common/raw_string_ostream.h"
  10. #include "llvm/ADT/STLExtras.h"
  11. #include "llvm/ADT/SmallVector.h"
  12. #include "llvm/ADT/StableHashing.h"
  13. #include "toolchain/base/kind_switch.h"
  14. #include "toolchain/base/shared_value_stores.h"
  15. #include "toolchain/base/value_ids.h"
  16. #include "toolchain/lex/tokenized_buffer.h"
  17. #include "toolchain/parse/tree.h"
  18. #include "toolchain/sem_ir/cpp_overload_set.h"
  19. #include "toolchain/sem_ir/entity_with_params_base.h"
  20. #include "toolchain/sem_ir/function.h"
  21. #include "toolchain/sem_ir/ids.h"
  22. #include "toolchain/sem_ir/inst_kind.h"
  23. #include "toolchain/sem_ir/pattern.h"
  24. #include "toolchain/sem_ir/singleton_insts.h"
  25. #include "toolchain/sem_ir/type_info.h"
  26. #include "toolchain/sem_ir/typed_insts.h"
  27. namespace Carbon::SemIR {
  28. class InstNamer::NamingContext {
  29. public:
  30. explicit NamingContext(InstNamer* inst_namer, InstNamer::ScopeId scope_id,
  31. InstId inst_id);
  32. // Names the single instruction. Use bound names where available. Otherwise,
  33. // assign a backup name.
  34. //
  35. // Insts with a type_id are required to add names; other insts may
  36. // optionally set a name. All insts may push other insts to be named.
  37. auto NameInst() -> void;
  38. private:
  39. // Adds the instruction's name.
  40. auto AddInstName(std::string name) -> void;
  41. // Adds the instruction's name by `NameId`.
  42. auto AddInstNameId(NameId name_id, llvm::StringRef suffix = "") -> void {
  43. AddInstName((sem_ir().names().GetIRBaseName(name_id) + suffix).str());
  44. }
  45. // Names an `IntType` or `FloatType`.
  46. auto AddIntOrFloatTypeName(char type_literal_prefix, InstId bit_width_id,
  47. llvm::StringRef suffix = "") -> void;
  48. // Names an `ImplWitnessTable` instruction.
  49. auto AddWitnessTableName(InstId witness_table_inst_id, std::string name)
  50. -> void;
  51. // Pushes all instructions in a block, by ID.
  52. auto PushBlockId(ScopeId scope_id, InstBlockId block_id) -> void {
  53. inst_namer_->PushBlockId(scope_id, block_id);
  54. }
  55. // Names the instruction as an entity. May push processing of the entity.
  56. template <typename EntityIdT>
  57. auto AddEntityNameAndMaybePush(EntityIdT id, llvm::StringRef suffix = "")
  58. -> void {
  59. AddInstName((inst_namer_->MaybePushEntity(id) + suffix).str());
  60. }
  61. auto sem_ir() -> const File& { return *inst_namer_->sem_ir_; }
  62. InstNamer* inst_namer_;
  63. ScopeId scope_id_;
  64. InstId inst_id_;
  65. Inst inst_;
  66. };
  67. InstNamer::InstNamer(const File* sem_ir, int total_ir_count)
  68. : sem_ir_(sem_ir), fingerprinter_(total_ir_count) {
  69. insts_.resize(sem_ir->insts().size(), {ScopeId::None, Namespace::Name()});
  70. labels_.resize(sem_ir->inst_blocks().size());
  71. scopes_.resize(GetScopeIdOffset(ScopeIdTypeEnum::None));
  72. generic_scopes_.resize(sem_ir->generics().size(), ScopeId::None);
  73. // We process the stack between each large block in order to reduce the
  74. // temporary size of the stack.
  75. auto process_stack = [&] {
  76. while (!inst_stack_.empty() || !inst_block_stack_.empty()) {
  77. if (inst_stack_.empty()) {
  78. auto [scope_id, block_id] = inst_block_stack_.pop_back_val();
  79. PushBlockInsts(scope_id, sem_ir_->inst_blocks().Get(block_id));
  80. }
  81. while (!inst_stack_.empty()) {
  82. auto [scope_id, inst_id] = inst_stack_.pop_back_val();
  83. NamingContext context(this, scope_id, inst_id);
  84. context.NameInst();
  85. }
  86. }
  87. };
  88. // Name each of the top-level scopes, in order. We use these as the roots of
  89. // walking the IR.
  90. PushBlockInsts(ScopeId::Constants, sem_ir->constants().array_ref());
  91. process_stack();
  92. PushBlockId(ScopeId::Imports, InstBlockId::Imports);
  93. process_stack();
  94. PushBlockId(ScopeId::File, sem_ir->top_inst_block_id());
  95. process_stack();
  96. // Global init won't have any other references, so we add it directly.
  97. if (sem_ir_->global_ctor_id().has_value()) {
  98. MaybePushEntity(sem_ir_->global_ctor_id());
  99. process_stack();
  100. }
  101. }
  102. auto InstNamer::GetScopeIdOffset(ScopeIdTypeEnum id_enum) const -> int {
  103. int offset = 0;
  104. // For each Id type, add the number of entities *above* its case; for example,
  105. // the offset for functions excludes the functions themselves. The fallthrough
  106. // handles summing to get uniqueness; order isn't special.
  107. switch (id_enum) {
  108. case ScopeIdTypeEnum::None:
  109. // `None` will be getting a full count of scopes.
  110. offset += sem_ir_->associated_constants().size();
  111. [[fallthrough]];
  112. case ScopeIdTypeEnum::For<AssociatedConstantId>:
  113. offset += sem_ir_->classes().size();
  114. [[fallthrough]];
  115. case ScopeIdTypeEnum::For<ClassId>:
  116. offset += sem_ir_->cpp_overload_sets().size();
  117. [[fallthrough]];
  118. case ScopeIdTypeEnum::For<CppOverloadSetId>:
  119. offset += sem_ir_->functions().size();
  120. [[fallthrough]];
  121. case ScopeIdTypeEnum::For<FunctionId>:
  122. offset += sem_ir_->impls().size();
  123. [[fallthrough]];
  124. case ScopeIdTypeEnum::For<ImplId>:
  125. offset += sem_ir_->interfaces().size();
  126. [[fallthrough]];
  127. case ScopeIdTypeEnum::For<InterfaceId>:
  128. offset += sem_ir_->specific_interfaces().size();
  129. [[fallthrough]];
  130. case ScopeIdTypeEnum::For<SpecificInterfaceId>:
  131. offset += sem_ir_->vtables().size();
  132. [[fallthrough]];
  133. case ScopeIdTypeEnum::For<VtableId>:
  134. // All type-specific scopes are offset by `FirstEntityScope`.
  135. offset += static_cast<int>(ScopeId::FirstEntityScope);
  136. return offset;
  137. default:
  138. CARBON_FATAL("Unexpected ScopeIdTypeEnum: {0}", id_enum);
  139. }
  140. }
  141. auto InstNamer::GetScopeName(ScopeId scope) const -> std::string {
  142. switch (scope) {
  143. case ScopeId::None:
  144. return "<no scope>";
  145. // These are treated as SemIR keywords.
  146. case ScopeId::File:
  147. return "file";
  148. case ScopeId::Imports:
  149. return "imports";
  150. case ScopeId::Constants:
  151. return "constants";
  152. // For everything else, use an @ prefix.
  153. default:
  154. return ("@" + GetScopeInfo(scope).name.GetFullName()).str();
  155. }
  156. }
  157. auto InstNamer::GetUnscopedNameFor(InstId inst_id) const -> llvm::StringRef {
  158. if (!inst_id.has_value()) {
  159. return "";
  160. }
  161. if (IsSingletonInstId(inst_id)) {
  162. return sem_ir_->insts().Get(inst_id).kind().ir_name();
  163. }
  164. auto index = sem_ir_->insts().GetRawIndex(inst_id);
  165. const auto& inst_name = insts_[index].second;
  166. return inst_name ? inst_name.GetFullName() : "";
  167. }
  168. auto InstNamer::GetNameFor(ScopeId scope_id, InstId inst_id) const
  169. -> std::string {
  170. if (!inst_id.has_value()) {
  171. return "invalid";
  172. }
  173. // Check for a builtin.
  174. if (IsSingletonInstId(inst_id)) {
  175. return sem_ir_->insts().Get(inst_id).kind().ir_name().str();
  176. }
  177. if (inst_id == SemIR::Namespace::PackageInstId) {
  178. return "package";
  179. }
  180. auto index = sem_ir_->insts().GetRawIndex(inst_id);
  181. const auto& [inst_scope, inst_name] = insts_[index];
  182. if (!inst_name) {
  183. // This should not happen in valid IR.
  184. RawStringOstream out;
  185. out << "<unexpected>." << inst_id;
  186. auto loc_id = sem_ir_->insts().GetCanonicalLocId(inst_id);
  187. // TODO: Consider handling other kinds.
  188. if (loc_id.kind() == LocId::Kind::NodeId) {
  189. const auto& tree = sem_ir_->parse_tree();
  190. auto token = tree.node_token(loc_id.node_id());
  191. out << ".loc" << tree.tokens().GetLineNumber(token) << "_"
  192. << tree.tokens().GetColumnNumber(token);
  193. }
  194. return out.TakeStr();
  195. }
  196. if (inst_scope == scope_id) {
  197. return ("%" + inst_name.GetFullName()).str();
  198. }
  199. return (GetScopeName(inst_scope) + ".%" + inst_name.GetFullName()).str();
  200. }
  201. auto InstNamer::GetUnscopedLabelFor(InstBlockId block_id) const
  202. -> llvm::StringRef {
  203. if (!block_id.has_value()) {
  204. return "";
  205. }
  206. const auto& label_name = labels_[block_id.index].second;
  207. return label_name ? label_name.GetFullName() : "";
  208. }
  209. // Returns the IR name to use for a label, when referenced from a given scope.
  210. auto InstNamer::GetLabelFor(ScopeId scope_id, InstBlockId block_id) const
  211. -> std::string {
  212. if (!block_id.has_value()) {
  213. return "!invalid";
  214. }
  215. const auto& [label_scope, label_name] = labels_[block_id.index];
  216. if (!label_name) {
  217. // This should not happen in valid IR.
  218. RawStringOstream out;
  219. out << "<unexpected instblockref " << block_id << ">";
  220. return out.TakeStr();
  221. }
  222. if (label_scope == scope_id) {
  223. return ("!" + label_name.GetFullName()).str();
  224. }
  225. return (GetScopeName(label_scope) + ".!" + label_name.GetFullName()).str();
  226. }
  227. auto InstNamer::Namespace::Name::GetFullName() const -> llvm::StringRef {
  228. if (!value_) {
  229. return "<null name>";
  230. }
  231. llvm::StringMapEntry<NameResult>* value = value_;
  232. while (value->second.ambiguous && value->second.fallback) {
  233. value = value->second.fallback.value_;
  234. }
  235. return value->first();
  236. }
  237. auto InstNamer::Namespace::Name::GetBaseName() const -> llvm::StringRef {
  238. if (!value_) {
  239. return "<null name>";
  240. }
  241. return value_->first().take_front(base_name_size_);
  242. }
  243. auto InstNamer::Namespace::AllocateName(
  244. const InstNamer& inst_namer,
  245. std::variant<LocId, uint64_t> loc_id_or_fingerprint, std::string name)
  246. -> Name {
  247. // The best (shortest) name for this instruction so far, and the current
  248. // name for it.
  249. Name best;
  250. Name current;
  251. const size_t base_name_size = name.size();
  252. // Add `name` as a name for this entity.
  253. auto add_name = [&](bool mark_ambiguous = true) {
  254. auto [it, added] = allocated_.insert({name, NameResult()});
  255. Name new_name = Name(it, base_name_size);
  256. if (!added) {
  257. if (mark_ambiguous) {
  258. // This name was allocated for a different instruction. Mark it as
  259. // ambiguous and keep looking for a name for this instruction.
  260. new_name.SetAmbiguous();
  261. }
  262. } else {
  263. if (!best) {
  264. best = new_name;
  265. } else {
  266. CARBON_CHECK(current);
  267. current.SetFallback(new_name);
  268. }
  269. current = new_name;
  270. }
  271. return added;
  272. };
  273. // Use the given name if it's available.
  274. if (!name.empty()) {
  275. add_name();
  276. }
  277. // Append location information to try to disambiguate.
  278. if (auto* loc_id = std::get_if<LocId>(&loc_id_or_fingerprint)) {
  279. *loc_id = inst_namer.sem_ir_->insts().GetCanonicalLocId(*loc_id);
  280. // TODO: Consider handling other kinds.
  281. if (loc_id->kind() == LocId::Kind::NodeId) {
  282. const auto& tree = inst_namer.sem_ir_->parse_tree();
  283. auto token = tree.node_token(loc_id->node_id());
  284. llvm::raw_string_ostream(name)
  285. << ".loc" << tree.tokens().GetLineNumber(token);
  286. add_name();
  287. llvm::raw_string_ostream(name)
  288. << "_" << tree.tokens().GetColumnNumber(token);
  289. add_name();
  290. }
  291. } else {
  292. uint64_t fingerprint = std::get<uint64_t>(loc_id_or_fingerprint);
  293. llvm::raw_string_ostream out(name);
  294. out << ".";
  295. // Include names with 3-6 characters from the fingerprint. Then fall back to
  296. // sequential numbering.
  297. for (int n : llvm::seq(1, 7)) {
  298. out.write_hex((fingerprint >> (64 - 4 * n)) & 0xF);
  299. if (n >= 3) {
  300. add_name();
  301. }
  302. }
  303. }
  304. // Append numbers until we find an available name.
  305. name += ".";
  306. auto name_size_without_counter = name.size();
  307. for (int counter = 1;; ++counter) {
  308. name.resize(name_size_without_counter);
  309. llvm::raw_string_ostream(name) << counter;
  310. if (add_name(/*mark_ambiguous=*/false)) {
  311. return best;
  312. }
  313. }
  314. }
  315. auto InstNamer::AddBlockLabel(
  316. ScopeId scope_id, InstBlockId block_id, std::string name,
  317. std::variant<LocId, uint64_t> loc_id_or_fingerprint) -> void {
  318. if (!block_id.has_value() || labels_[block_id.index].second) {
  319. return;
  320. }
  321. if (auto* loc_id = std::get_if<LocId>(&loc_id_or_fingerprint);
  322. loc_id && !loc_id->has_value()) {
  323. if (const auto& block = sem_ir_->inst_blocks().Get(block_id);
  324. !block.empty()) {
  325. loc_id_or_fingerprint = LocId(block.front());
  326. }
  327. }
  328. labels_[block_id.index] = {
  329. scope_id, GetScopeInfo(scope_id).labels.AllocateName(
  330. *this, loc_id_or_fingerprint, std::move(name))};
  331. }
  332. // Provides names for `AddBlockLabel`.
  333. struct BranchNames {
  334. // Returns names for a branching parse node, or nullopt if not a branch.
  335. static auto For(Parse::NodeKind node_kind) -> std::optional<BranchNames> {
  336. switch (node_kind) {
  337. case Parse::NodeKind::ForHeaderStart:
  338. return {{.prefix = "for", .branch = "next"}};
  339. case Parse::NodeKind::ForHeader:
  340. return {{.prefix = "for", .branch_if = "body", .branch = "done"}};
  341. case Parse::NodeKind::IfExprIf:
  342. return {{.prefix = "if.expr",
  343. .branch_if = "then",
  344. .branch = "else",
  345. .branch_with_arg = "result"}};
  346. case Parse::NodeKind::IfCondition:
  347. return {{.prefix = "if", .branch_if = "then", .branch = "else"}};
  348. case Parse::NodeKind::IfStatement:
  349. return {{.prefix = "if", .branch = "done"}};
  350. case Parse::NodeKind::ShortCircuitOperandAnd:
  351. return {
  352. {.prefix = "and", .branch_if = "rhs", .branch_with_arg = "result"}};
  353. case Parse::NodeKind::ShortCircuitOperandOr:
  354. return {
  355. {.prefix = "or", .branch_if = "rhs", .branch_with_arg = "result"}};
  356. case Parse::NodeKind::WhileConditionStart:
  357. return {{.prefix = "while", .branch = "cond"}};
  358. case Parse::NodeKind::WhileCondition:
  359. return {{.prefix = "while", .branch_if = "body", .branch = "done"}};
  360. default:
  361. return std::nullopt;
  362. }
  363. }
  364. // Returns the provided suffix for the instruction kind, or an empty string.
  365. auto GetSuffix(InstKind inst_kind) -> llvm::StringLiteral {
  366. switch (inst_kind) {
  367. case BranchIf::Kind:
  368. return branch_if;
  369. case Branch::Kind:
  370. return branch;
  371. case BranchWithArg::Kind:
  372. return branch_with_arg;
  373. default:
  374. return "";
  375. }
  376. }
  377. // The kind of branch, based on the node kind.
  378. llvm::StringLiteral prefix;
  379. // For labeling branch instruction kinds. Only expected kinds need a value;
  380. // the empty string is for unexpected kinds.
  381. llvm::StringLiteral branch_if = "";
  382. llvm::StringLiteral branch = "";
  383. llvm::StringLiteral branch_with_arg = "";
  384. };
  385. // Finds and adds a suitable block label for the given SemIR instruction that
  386. // represents some kind of branch.
  387. auto InstNamer::AddBlockLabel(ScopeId scope_id, LocId loc_id, AnyBranch branch)
  388. -> void {
  389. std::string label;
  390. loc_id = sem_ir_->insts().GetCanonicalLocId(loc_id);
  391. if (loc_id.node_id().has_value()) {
  392. if (auto names = BranchNames::For(
  393. sem_ir_->parse_tree().node_kind(loc_id.node_id()))) {
  394. if (auto suffix = names->GetSuffix(branch.kind); !suffix.empty()) {
  395. label = llvm::formatv("{0}.{1}", names->prefix, suffix);
  396. } else {
  397. label =
  398. llvm::formatv("{0}.<unexpected {1}>", names->prefix, branch.kind);
  399. }
  400. }
  401. }
  402. AddBlockLabel(scope_id, branch.target_id, label, loc_id);
  403. }
  404. auto InstNamer::PushBlockId(ScopeId scope_id, InstBlockId block_id) -> void {
  405. if (block_id.has_value()) {
  406. inst_block_stack_.push_back({scope_id, block_id});
  407. }
  408. }
  409. auto InstNamer::PushBlockInsts(ScopeId scope_id,
  410. llvm::ArrayRef<InstId> inst_ids) -> void {
  411. for (auto inst_id : llvm::reverse(inst_ids)) {
  412. if (inst_id.has_value() && !IsSingletonInstId(inst_id)) {
  413. inst_stack_.push_back(std::make_pair(scope_id, inst_id));
  414. }
  415. }
  416. }
  417. auto InstNamer::PushGeneric(ScopeId scope_id, GenericId generic_id) -> void {
  418. if (!generic_id.has_value()) {
  419. return;
  420. }
  421. generic_scopes_[sem_ir_->generics().GetRawIndex(generic_id)] = scope_id;
  422. const auto& generic = sem_ir_->generics().Get(generic_id);
  423. // Push blocks in reverse order.
  424. PushBlockId(scope_id, generic.definition_block_id);
  425. PushBlockId(scope_id, generic.decl_block_id);
  426. }
  427. auto InstNamer::PushEntity(AssociatedConstantId associated_constant_id,
  428. ScopeId scope_id, Scope& scope) -> void {
  429. const auto& assoc_const =
  430. sem_ir_->associated_constants().Get(associated_constant_id);
  431. scope.name = globals_.AllocateName(
  432. *this, LocId(assoc_const.decl_id),
  433. sem_ir_->names().GetIRBaseName(assoc_const.name_id).str());
  434. // Push blocks in reverse order.
  435. PushGeneric(scope_id, assoc_const.generic_id);
  436. }
  437. auto InstNamer::PushEntity(ClassId class_id, ScopeId scope_id, Scope& scope)
  438. -> void {
  439. const auto& class_info = sem_ir_->classes().Get(class_id);
  440. LocId class_loc(class_info.latest_decl_id());
  441. scope.name = globals_.AllocateName(
  442. *this, class_loc,
  443. sem_ir_->names().GetIRBaseName(class_info.name_id).str());
  444. AddBlockLabel(scope_id, class_info.body_block_id, "class", class_loc);
  445. PushGeneric(scope_id, class_info.generic_id);
  446. // Push blocks in reverse order.
  447. PushBlockId(scope_id, class_info.body_block_id);
  448. PushBlockId(scope_id, class_info.pattern_block_id);
  449. }
  450. auto InstNamer::GetNameForParentNameScope(NameScopeId name_scope_id)
  451. -> llvm::StringRef {
  452. if (!name_scope_id.has_value()) {
  453. return "";
  454. }
  455. auto scope_inst =
  456. sem_ir_->insts().Get(sem_ir_->name_scopes().Get(name_scope_id).inst_id());
  457. CARBON_KIND_SWITCH(scope_inst) {
  458. case CARBON_KIND(ClassDecl class_decl): {
  459. return MaybePushEntity(class_decl.class_id);
  460. }
  461. case CARBON_KIND(ImplDecl impl): {
  462. return MaybePushEntity(impl.impl_id);
  463. }
  464. case CARBON_KIND(InterfaceDecl interface): {
  465. return MaybePushEntity(interface.interface_id);
  466. }
  467. case SemIR::Namespace::Kind: {
  468. // Only prefix type scopes.
  469. return "";
  470. }
  471. default: {
  472. return "<unsupported scope>";
  473. }
  474. }
  475. }
  476. auto InstNamer::PushEntity(FunctionId function_id, ScopeId scope_id,
  477. Scope& scope) -> void {
  478. const auto& fn = sem_ir_->functions().Get(function_id);
  479. LocId fn_loc(fn.latest_decl_id());
  480. auto scope_prefix = GetNameForParentNameScope(fn.parent_scope_id);
  481. scope.name = globals_.AllocateName(
  482. *this, fn_loc,
  483. llvm::formatv("{0}{1}{2}", scope_prefix, scope_prefix.empty() ? "" : ".",
  484. sem_ir_->names().GetIRBaseName(fn.name_id)));
  485. if (!fn.body_block_ids.empty()) {
  486. AddBlockLabel(scope_id, fn.body_block_ids.front(), "entry", fn_loc);
  487. }
  488. // Push blocks in reverse order.
  489. PushGeneric(scope_id, fn.generic_id);
  490. for (auto block_id : llvm::reverse(fn.body_block_ids)) {
  491. PushBlockId(scope_id, block_id);
  492. }
  493. PushBlockId(scope_id, fn.pattern_block_id);
  494. PushBlockId(scope_id, fn.call_params_id);
  495. }
  496. auto InstNamer::PushEntity(CppOverloadSetId cpp_overload_set_id,
  497. ScopeId /*scope_id*/, Scope& scope) -> void {
  498. const CppOverloadSet& overload_set =
  499. sem_ir_->cpp_overload_sets().Get(cpp_overload_set_id);
  500. uint64_t fingerprint =
  501. fingerprinter_.GetOrCompute(sem_ir_, cpp_overload_set_id);
  502. auto scope_prefix = GetNameForParentNameScope(overload_set.parent_scope_id);
  503. scope.name = globals_.AllocateName(
  504. *this, fingerprint,
  505. llvm::formatv("{0}{1}{2}.cpp_overload_set", scope_prefix,
  506. scope_prefix.empty() ? "" : ".",
  507. sem_ir_->names().GetIRBaseName(overload_set.name_id)));
  508. }
  509. auto InstNamer::PushEntity(ImplId impl_id, ScopeId scope_id, Scope& scope)
  510. -> void {
  511. const auto& impl = sem_ir_->impls().Get(impl_id);
  512. auto impl_fingerprint = fingerprinter_.GetOrCompute(sem_ir_, impl_id);
  513. llvm::StringRef self_name;
  514. auto self_const_id =
  515. sem_ir_->constant_values().GetConstantInstId(impl.self_id);
  516. auto index = sem_ir_->insts().GetRawIndex(self_const_id);
  517. if (IsSingletonInstId(self_const_id)) {
  518. self_name = sem_ir_->insts().Get(self_const_id).kind().ir_name();
  519. } else if (const auto& inst_name = insts_[index].second) {
  520. self_name = inst_name.GetBaseName();
  521. } else {
  522. self_name = "<unexpected self>";
  523. }
  524. llvm::StringRef interface_name;
  525. if (impl.interface.interface_id.has_value()) {
  526. interface_name = MaybePushEntity(impl.interface.interface_id);
  527. } else {
  528. interface_name = "<error>";
  529. }
  530. scope.name = globals_.AllocateName(
  531. *this, impl_fingerprint,
  532. llvm::formatv("{0}.as.{1}.impl", self_name, interface_name));
  533. AddBlockLabel(scope_id, impl.body_block_id, "impl", impl_fingerprint);
  534. // Push blocks in reverse order.
  535. PushGeneric(scope_id, impl.generic_id);
  536. PushBlockId(scope_id, impl.body_block_id);
  537. PushBlockId(scope_id, impl.pattern_block_id);
  538. }
  539. auto InstNamer::PushEntity(InterfaceId interface_id, ScopeId scope_id,
  540. Scope& scope) -> void {
  541. const auto& interface = sem_ir_->interfaces().Get(interface_id);
  542. LocId interface_loc(interface.latest_decl_id());
  543. scope.name = globals_.AllocateName(
  544. *this, interface_loc,
  545. sem_ir_->names().GetIRBaseName(interface.name_id).str());
  546. AddBlockLabel(scope_id, interface.body_block_id, "interface", interface_loc);
  547. // Push blocks in reverse order.
  548. PushGeneric(scope_id, interface.generic_id);
  549. PushBlockId(scope_id, interface.body_block_id);
  550. PushBlockId(scope_id, interface.pattern_block_id);
  551. }
  552. auto InstNamer::PushEntity(VtableId vtable_id, ScopeId /*scope_id*/,
  553. Scope& scope) -> void {
  554. const auto& vtable = sem_ir_->vtables().Get(vtable_id);
  555. const auto& class_info = sem_ir_->classes().Get(vtable.class_id);
  556. LocId vtable_loc(class_info.latest_decl_id());
  557. scope.name = globals_.AllocateName(
  558. *this, vtable_loc,
  559. sem_ir_->names().GetIRBaseName(class_info.name_id).str() + ".vtable");
  560. // TODO: Add support for generic vtables here and elsewhere.
  561. // PushGeneric(scope_id, vtable_info.generic_id);
  562. }
  563. InstNamer::NamingContext::NamingContext(InstNamer* inst_namer,
  564. InstNamer::ScopeId scope_id,
  565. InstId inst_id)
  566. : inst_namer_(inst_namer),
  567. scope_id_(scope_id),
  568. inst_id_(inst_id),
  569. inst_(sem_ir().insts().Get(inst_id)) {}
  570. auto InstNamer::NamingContext::AddInstName(std::string name) -> void {
  571. auto index = sem_ir().insts().GetRawIndex(inst_id_);
  572. ScopeId old_scope_id = inst_namer_->insts_[index].first;
  573. if (old_scope_id == ScopeId::None) {
  574. std::variant<LocId, uint64_t> loc_id_or_fingerprint = LocId::None;
  575. if (scope_id_ == ScopeId::Constants || scope_id_ == ScopeId::Imports) {
  576. loc_id_or_fingerprint =
  577. inst_namer_->fingerprinter_.GetOrCompute(&sem_ir(), inst_id_);
  578. } else {
  579. loc_id_or_fingerprint = LocId(inst_id_);
  580. }
  581. auto scoped_name = inst_namer_->GetScopeInfo(scope_id_).insts.AllocateName(
  582. *inst_namer_, loc_id_or_fingerprint, std::move(name));
  583. inst_namer_->insts_[index] = {scope_id_, scoped_name};
  584. } else {
  585. CARBON_CHECK(old_scope_id == scope_id_,
  586. "Attempting to name inst in multiple scopes");
  587. }
  588. }
  589. auto InstNamer::NamingContext::AddIntOrFloatTypeName(char type_literal_prefix,
  590. InstId bit_width_id,
  591. llvm::StringRef suffix)
  592. -> void {
  593. RawStringOstream out;
  594. out << type_literal_prefix;
  595. if (auto bit_width = sem_ir().insts().TryGetAs<IntValue>(bit_width_id)) {
  596. out << sem_ir().ints().Get(bit_width->int_id);
  597. } else {
  598. out << "N";
  599. }
  600. out << suffix;
  601. AddInstName(out.TakeStr());
  602. }
  603. auto InstNamer::NamingContext::AddWitnessTableName(InstId witness_table_inst_id,
  604. std::string name) -> void {
  605. auto witness_table =
  606. sem_ir().insts().GetAs<ImplWitnessTable>(witness_table_inst_id);
  607. if (!witness_table.impl_id.has_value()) {
  608. // TODO: The witness comes from a facet value. Can we get the
  609. // interface names from it? Store the facet value instruction in the
  610. // table?
  611. AddInstName(name);
  612. return;
  613. }
  614. const auto& impl = sem_ir().impls().Get(witness_table.impl_id);
  615. auto name_id = sem_ir().interfaces().Get(impl.interface.interface_id).name_id;
  616. std::string suffix = llvm::formatv(".{}", name);
  617. AddInstNameId(name_id, suffix);
  618. }
  619. auto InstNamer::NamingContext::NameInst() -> void {
  620. CARBON_KIND_SWITCH(inst_) {
  621. case AddrOf::Kind: {
  622. AddInstName("addr");
  623. return;
  624. }
  625. case ArrayType::Kind: {
  626. // TODO: Can we figure out the name of the type this is an array of?
  627. AddInstName("array_type");
  628. return;
  629. }
  630. case CARBON_KIND(AssociatedConstantDecl inst): {
  631. AddEntityNameAndMaybePush(inst.assoc_const_id);
  632. PushBlockId(inst_namer_->GetScopeFor(inst.assoc_const_id),
  633. inst.decl_block_id);
  634. return;
  635. }
  636. case CARBON_KIND(AssociatedEntity inst): {
  637. RawStringOstream out;
  638. out << "assoc" << inst.index.index;
  639. AddInstName(out.TakeStr());
  640. return;
  641. }
  642. case CARBON_KIND(AssociatedEntityType inst): {
  643. AddEntityNameAndMaybePush(inst.interface_id, ".assoc_type");
  644. return;
  645. }
  646. case BindAlias::Kind:
  647. case BindName::Kind:
  648. case BindSymbolicName::Kind:
  649. case ExportDecl::Kind: {
  650. auto inst = inst_.As<AnyBindNameOrExportDecl>();
  651. AddInstNameId(sem_ir().entity_names().Get(inst.entity_name_id).name_id);
  652. return;
  653. }
  654. case BindingPattern::Kind:
  655. case SymbolicBindingPattern::Kind: {
  656. auto inst = inst_.As<AnyBindingPattern>();
  657. auto name_id = NameId::Underscore;
  658. if (inst.entity_name_id.has_value()) {
  659. name_id = sem_ir().entity_names().Get(inst.entity_name_id).name_id;
  660. }
  661. AddInstNameId(name_id, ".patt");
  662. return;
  663. }
  664. case CARBON_KIND(BoolLiteral inst): {
  665. if (inst.value.ToBool()) {
  666. AddInstName("true");
  667. } else {
  668. AddInstName("false");
  669. }
  670. return;
  671. }
  672. case CARBON_KIND(BoundMethod inst): {
  673. auto type_id = sem_ir().insts().Get(inst.function_decl_id).type_id();
  674. if (auto fn_ty = sem_ir().types().TryGetAs<FunctionType>(type_id)) {
  675. AddEntityNameAndMaybePush(fn_ty->function_id, ".bound");
  676. } else {
  677. AddInstName("bound_method");
  678. }
  679. return;
  680. }
  681. case Branch::Kind:
  682. case BranchIf::Kind:
  683. case BranchWithArg::Kind: {
  684. auto branch = inst_.As<AnyBranch>();
  685. inst_namer_->AddBlockLabel(scope_id_, LocId(inst_id_), branch);
  686. return;
  687. }
  688. case CARBON_KIND(Call inst): {
  689. auto callee = GetCallee(sem_ir(), inst.callee_id);
  690. if (auto* fn = std::get_if<CalleeFunction>(&callee)) {
  691. AddEntityNameAndMaybePush(fn->function_id, ".call");
  692. return;
  693. }
  694. AddInstName("");
  695. return;
  696. }
  697. case CARBON_KIND(ClassDecl inst): {
  698. AddEntityNameAndMaybePush(inst.class_id, ".decl");
  699. auto class_scope_id = inst_namer_->GetScopeFor(inst.class_id);
  700. PushBlockId(class_scope_id, inst.decl_block_id);
  701. return;
  702. }
  703. case CARBON_KIND(ClassType inst): {
  704. if (auto literal_info = TypeLiteralInfo::ForType(sem_ir(), inst);
  705. literal_info.is_valid()) {
  706. AddInstName(literal_info.GetLiteralAsString(sem_ir()));
  707. } else {
  708. AddEntityNameAndMaybePush(inst.class_id);
  709. }
  710. return;
  711. }
  712. case CompleteTypeWitness::Kind: {
  713. // TODO: Can we figure out the name of the type this is a witness for?
  714. AddInstName("complete_type");
  715. return;
  716. }
  717. case CARBON_KIND(VtableDecl inst): {
  718. const auto& vtable = sem_ir().vtables().Get(inst.vtable_id);
  719. inst_namer_->MaybePushEntity(inst.vtable_id);
  720. if (inst_namer_->GetScopeFor(vtable.class_id) == scope_id_) {
  721. inst_namer_->MaybePushEntity(vtable.class_id);
  722. AddInstName("vtable_decl");
  723. } else {
  724. AddEntityNameAndMaybePush(vtable.class_id, ".vtable_decl");
  725. }
  726. return;
  727. }
  728. case CARBON_KIND(VtablePtr inst): {
  729. const auto& vtable = sem_ir().vtables().Get(inst.vtable_id);
  730. inst_namer_->MaybePushEntity(inst.vtable_id);
  731. AddEntityNameAndMaybePush(vtable.class_id, ".vtable_ptr");
  732. return;
  733. }
  734. case ConstType::Kind: {
  735. // TODO: Can we figure out the name of the type argument?
  736. AddInstName("const");
  737. return;
  738. }
  739. case CARBON_KIND(FacetAccessType inst): {
  740. if (auto name =
  741. sem_ir().insts().TryGetAs<NameRef>(inst.facet_value_inst_id)) {
  742. AddInstNameId(name->name_id, ".as_type");
  743. } else {
  744. AddInstName("as_type");
  745. }
  746. return;
  747. }
  748. case CARBON_KIND(SymbolicBindingType inst): {
  749. auto bind =
  750. sem_ir().insts().GetAs<BindSymbolicName>(inst.facet_value_inst_id);
  751. auto name_id = sem_ir().entity_names().Get(bind.entity_name_id).name_id;
  752. if (name_id.has_value()) {
  753. AddInstNameId(name_id, ".binding.as_type");
  754. } else {
  755. AddInstName("binding.as_type");
  756. }
  757. return;
  758. }
  759. case CARBON_KIND(FacetType inst): {
  760. const auto& facet_type_info =
  761. sem_ir().facet_types().Get(inst.facet_type_id);
  762. bool has_where = facet_type_info.other_requirements ||
  763. !facet_type_info.builtin_constraint_mask.empty() ||
  764. !facet_type_info.self_impls_constraints.empty() ||
  765. !facet_type_info.rewrite_constraints.empty();
  766. if (facet_type_info.extend_constraints.size() == 1) {
  767. AddEntityNameAndMaybePush(
  768. facet_type_info.extend_constraints.front().interface_id,
  769. has_where ? "_where.type" : ".type");
  770. } else if (facet_type_info.extend_constraints.empty()) {
  771. AddInstName(has_where ? "type_where" : "type");
  772. } else {
  773. AddInstName("facet_type");
  774. }
  775. return;
  776. }
  777. case CARBON_KIND(FacetValue inst): {
  778. if (auto facet_type =
  779. sem_ir().types().TryGetAs<FacetType>(inst.type_id)) {
  780. const auto& facet_type_info =
  781. sem_ir().facet_types().Get(facet_type->facet_type_id);
  782. if (auto interface = facet_type_info.TryAsSingleInterface()) {
  783. AddEntityNameAndMaybePush(interface->interface_id, ".facet");
  784. return;
  785. }
  786. }
  787. AddInstName("facet_value");
  788. return;
  789. }
  790. case CARBON_KIND(FloatType inst): {
  791. AddIntOrFloatTypeName('f', inst.bit_width_id);
  792. return;
  793. }
  794. case FloatLiteralValue::Kind:
  795. case FloatValue::Kind: {
  796. AddInstName("float");
  797. return;
  798. }
  799. case CARBON_KIND(FunctionDecl inst): {
  800. AddEntityNameAndMaybePush(inst.function_id, ".decl");
  801. auto function_scope_id = inst_namer_->GetScopeFor(inst.function_id);
  802. PushBlockId(function_scope_id, inst.decl_block_id);
  803. return;
  804. }
  805. case CARBON_KIND(FunctionType inst): {
  806. AddEntityNameAndMaybePush(inst.function_id, ".type");
  807. return;
  808. }
  809. case CARBON_KIND(CppOverloadSetValue inst): {
  810. AddEntityNameAndMaybePush(inst.overload_set_id, ".value");
  811. return;
  812. }
  813. case CARBON_KIND(CppOverloadSetType inst): {
  814. AddEntityNameAndMaybePush(inst.overload_set_id, ".type");
  815. return;
  816. }
  817. case CARBON_KIND(GenericClassType inst): {
  818. AddEntityNameAndMaybePush(inst.class_id, ".type");
  819. return;
  820. }
  821. case CARBON_KIND(GenericInterfaceType inst): {
  822. AddEntityNameAndMaybePush(inst.interface_id, ".type");
  823. return;
  824. }
  825. case CARBON_KIND(ImplDecl inst): {
  826. // `impl` declarations aren't named because they aren't added to any
  827. // namespace, and so aren't referenced directly.
  828. inst_namer_->MaybePushEntity(inst.impl_id);
  829. PushBlockId(inst_namer_->GetScopeFor(inst.impl_id), inst.decl_block_id);
  830. return;
  831. }
  832. case CARBON_KIND(LookupImplWitness inst): {
  833. const auto& interface =
  834. sem_ir().specific_interfaces().Get(inst.query_specific_interface_id);
  835. AddEntityNameAndMaybePush(interface.interface_id, ".lookup_impl_witness");
  836. return;
  837. }
  838. case CARBON_KIND(ImplWitness inst): {
  839. AddWitnessTableName(inst.witness_table_id, "impl_witness");
  840. return;
  841. }
  842. case CARBON_KIND(ImplWitnessAccess inst): {
  843. // TODO: Include information about the impl?
  844. RawStringOstream out;
  845. out << "impl.elem" << inst.index.index;
  846. AddInstName(out.TakeStr());
  847. return;
  848. }
  849. case CARBON_KIND(ImplWitnessAccessSubstituted inst): {
  850. // TODO: Include information about the impl?
  851. RawStringOstream out;
  852. auto access = sem_ir().insts().GetAs<ImplWitnessAccess>(
  853. inst.impl_witness_access_id);
  854. out << "impl.elem" << access.index.index << ".subst";
  855. AddInstName(out.TakeStr());
  856. return;
  857. }
  858. case ImplWitnessAssociatedConstant::Kind: {
  859. AddInstName("impl_witness_assoc_constant");
  860. return;
  861. }
  862. case ImplWitnessTable::Kind: {
  863. AddWitnessTableName(inst_id_, "impl_witness_table");
  864. return;
  865. }
  866. case ImportCppDecl::Kind: {
  867. AddInstName("Cpp.import_cpp");
  868. return;
  869. }
  870. case CARBON_KIND(ImportDecl inst): {
  871. if (inst.package_id.has_value()) {
  872. AddInstNameId(inst.package_id, ".import");
  873. } else {
  874. AddInstName("default.import");
  875. }
  876. return;
  877. }
  878. case ImportRefUnloaded::Kind:
  879. case ImportRefLoaded::Kind: {
  880. // Build the base import name: <package>.<entity-name>
  881. RawStringOstream out;
  882. auto inst = inst_.As<AnyImportRef>();
  883. auto import_ir_inst =
  884. sem_ir().import_ir_insts().Get(inst.import_ir_inst_id);
  885. const auto& import_ir =
  886. *sem_ir().import_irs().Get(import_ir_inst.ir_id()).sem_ir;
  887. auto package_id = import_ir.package_id();
  888. if (auto ident_id = package_id.AsIdentifierId(); ident_id.has_value()) {
  889. out << import_ir.identifiers().Get(ident_id);
  890. } else {
  891. out << package_id.AsSpecialName();
  892. }
  893. out << ".";
  894. // Add entity name if available.
  895. if (inst.entity_name_id.has_value()) {
  896. auto name_id = sem_ir().entity_names().Get(inst.entity_name_id).name_id;
  897. out << sem_ir().names().GetIRBaseName(name_id);
  898. } else {
  899. out << "import_ref";
  900. }
  901. AddInstName(out.TakeStr());
  902. // When building import refs, we frequently add instructions without
  903. // a block. Constants that refer to them need to be separately
  904. // named.
  905. auto const_id = sem_ir().constant_values().Get(inst_id_);
  906. if (const_id.has_value() && const_id.is_concrete()) {
  907. auto const_inst_id = sem_ir().constant_values().GetInstId(const_id);
  908. auto index = sem_ir().insts().GetRawIndex(const_inst_id);
  909. if (!inst_namer_->insts_[index].second) {
  910. inst_namer_->PushBlockInsts(ScopeId::Imports, const_inst_id);
  911. }
  912. }
  913. return;
  914. }
  915. case CARBON_KIND(InstValue inst): {
  916. inst_namer_->PushBlockInsts(scope_id_, inst.inst_id);
  917. AddInstName(
  918. ("inst." + sem_ir().insts().Get(inst.inst_id).kind().ir_name())
  919. .str());
  920. return;
  921. }
  922. case CARBON_KIND(InterfaceDecl inst): {
  923. AddEntityNameAndMaybePush(inst.interface_id, ".decl");
  924. auto interface_scope_id = inst_namer_->GetScopeFor(inst.interface_id);
  925. PushBlockId(interface_scope_id, inst.decl_block_id);
  926. return;
  927. }
  928. case CARBON_KIND(IntType inst): {
  929. AddIntOrFloatTypeName(inst.int_kind == IntKind::Signed ? 'i' : 'u',
  930. inst.bit_width_id, ".builtin");
  931. return;
  932. }
  933. case CARBON_KIND(IntValue inst): {
  934. RawStringOstream out;
  935. out << "int_" << sem_ir().ints().Get(inst.int_id);
  936. AddInstName(out.TakeStr());
  937. return;
  938. }
  939. case CARBON_KIND(NameBindingDecl inst): {
  940. PushBlockId(scope_id_, inst.pattern_block_id);
  941. return;
  942. }
  943. case CARBON_KIND(NameRef inst): {
  944. AddInstNameId(inst.name_id, ".ref");
  945. return;
  946. }
  947. // The namespace is specified here due to the name conflict.
  948. case CARBON_KIND(SemIR::Namespace inst): {
  949. AddInstNameId(sem_ir().name_scopes().Get(inst.name_scope_id).name_id());
  950. return;
  951. }
  952. case OutParam::Kind:
  953. case RefParam::Kind:
  954. case ValueParam::Kind: {
  955. AddInstNameId(inst_.As<AnyParam>().pretty_name_id, ".param");
  956. return;
  957. }
  958. case OutParamPattern::Kind:
  959. case RefParamPattern::Kind:
  960. case ValueParamPattern::Kind: {
  961. AddInstNameId(GetPrettyNameFromPatternId(sem_ir(), inst_id_),
  962. ".param_patt");
  963. return;
  964. }
  965. case PatternType::Kind: {
  966. AddInstName("pattern_type");
  967. return;
  968. }
  969. case PointerType::Kind: {
  970. AddInstName("ptr");
  971. return;
  972. }
  973. case RequireCompleteType::Kind: {
  974. AddInstName("require_complete");
  975. return;
  976. }
  977. case ReturnSlotPattern::Kind: {
  978. AddInstNameId(NameId::ReturnSlot, ".patt");
  979. return;
  980. }
  981. case CARBON_KIND(SpecificFunction inst): {
  982. auto type_id = sem_ir().insts().Get(inst.callee_id).type_id();
  983. if (auto fn_ty = sem_ir().types().TryGetAs<FunctionType>(type_id)) {
  984. AddEntityNameAndMaybePush(fn_ty->function_id, ".specific_fn");
  985. } else {
  986. AddInstName("specific_fn");
  987. }
  988. return;
  989. }
  990. case CARBON_KIND(SpecificImplFunction inst): {
  991. auto type_id = sem_ir().insts().Get(inst.callee_id).type_id();
  992. if (auto fn_ty = sem_ir().types().TryGetAs<FunctionType>(type_id)) {
  993. AddEntityNameAndMaybePush(fn_ty->function_id, ".specific_impl_fn");
  994. } else {
  995. AddInstName("specific_impl_fn");
  996. }
  997. return;
  998. }
  999. case ReturnSlot::Kind: {
  1000. AddInstNameId(NameId::ReturnSlot);
  1001. return;
  1002. }
  1003. case CARBON_KIND(SpliceBlock inst): {
  1004. PushBlockId(scope_id_, inst.block_id);
  1005. AddInstName("");
  1006. return;
  1007. }
  1008. case StringLiteral::Kind: {
  1009. AddInstName("str");
  1010. return;
  1011. }
  1012. case CARBON_KIND(StructValue inst): {
  1013. if (auto fn_ty = sem_ir().types().TryGetAs<FunctionType>(inst.type_id)) {
  1014. AddEntityNameAndMaybePush(fn_ty->function_id);
  1015. } else if (auto class_ty =
  1016. sem_ir().types().TryGetAs<ClassType>(inst.type_id)) {
  1017. AddEntityNameAndMaybePush(class_ty->class_id, ".val");
  1018. } else if (auto generic_class_ty =
  1019. sem_ir().types().TryGetAs<GenericClassType>(
  1020. inst.type_id)) {
  1021. AddEntityNameAndMaybePush(generic_class_ty->class_id, ".generic");
  1022. } else if (auto generic_interface_ty =
  1023. sem_ir().types().TryGetAs<GenericInterfaceType>(
  1024. inst.type_id)) {
  1025. AddInstNameId(sem_ir()
  1026. .interfaces()
  1027. .Get(generic_interface_ty->interface_id)
  1028. .name_id,
  1029. ".generic");
  1030. } else {
  1031. if (sem_ir().inst_blocks().Get(inst.elements_id).empty()) {
  1032. AddInstName("empty_struct");
  1033. } else {
  1034. AddInstName("struct");
  1035. }
  1036. }
  1037. return;
  1038. }
  1039. case CARBON_KIND(StructType inst): {
  1040. const auto& fields = sem_ir().struct_type_fields().Get(inst.fields_id);
  1041. if (fields.empty()) {
  1042. AddInstName("empty_struct_type");
  1043. return;
  1044. }
  1045. std::string name = "struct_type";
  1046. for (auto field : fields) {
  1047. name += ".";
  1048. name += sem_ir().names().GetIRBaseName(field.name_id).str();
  1049. }
  1050. AddInstName(std::move(name));
  1051. return;
  1052. }
  1053. case CARBON_KIND(TupleAccess inst): {
  1054. RawStringOstream out;
  1055. out << "tuple.elem" << inst.index.index;
  1056. AddInstName(out.TakeStr());
  1057. return;
  1058. }
  1059. case CARBON_KIND(TupleType inst): {
  1060. if (inst.type_elements_id == InstBlockId::Empty) {
  1061. AddInstName("empty_tuple.type");
  1062. } else {
  1063. AddInstName("tuple.type");
  1064. }
  1065. return;
  1066. }
  1067. case CARBON_KIND(TupleValue inst): {
  1068. if (sem_ir().types().Is<ArrayType>(inst.type_id)) {
  1069. AddInstName("array");
  1070. } else if (inst.elements_id == InstBlockId::Empty) {
  1071. AddInstName("empty_tuple");
  1072. } else {
  1073. AddInstName("tuple");
  1074. }
  1075. return;
  1076. }
  1077. case CARBON_KIND(UnboundElementType inst): {
  1078. if (auto class_ty =
  1079. sem_ir().insts().TryGetAs<ClassType>(inst.class_type_inst_id)) {
  1080. AddEntityNameAndMaybePush(class_ty->class_id, ".elem");
  1081. } else {
  1082. AddInstName("elem_type");
  1083. }
  1084. return;
  1085. }
  1086. case VarPattern::Kind: {
  1087. AddInstNameId(GetPrettyNameFromPatternId(sem_ir(), inst_id_),
  1088. ".var_patt");
  1089. return;
  1090. }
  1091. case CARBON_KIND(VarStorage inst): {
  1092. if (inst.pattern_id.has_value()) {
  1093. AddInstNameId(GetPrettyNameFromPatternId(sem_ir(), inst.pattern_id),
  1094. ".var");
  1095. } else {
  1096. AddInstName("var");
  1097. }
  1098. return;
  1099. }
  1100. default: {
  1101. // Sequentially number all remaining values.
  1102. if (inst_.kind().has_type()) {
  1103. AddInstName("");
  1104. }
  1105. return;
  1106. }
  1107. }
  1108. }
  1109. auto InstNamer::has_name(InstId inst_id) const -> bool {
  1110. return static_cast<bool>(
  1111. insts_[sem_ir_->insts().GetRawIndex(inst_id)].second);
  1112. }
  1113. } // namespace Carbon::SemIR