context.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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/lower/context.h"
  5. #include "common/check.h"
  6. #include "common/growing_range.h"
  7. #include "common/raw_string_ostream.h"
  8. #include "common/vlog.h"
  9. #include "llvm/Transforms/Utils/ModuleUtils.h"
  10. #include "toolchain/lower/file_context.h"
  11. #include "toolchain/sem_ir/inst_namer.h"
  12. namespace Carbon::Lower {
  13. Context::Context(
  14. llvm::LLVMContext* llvm_context,
  15. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs, bool want_debug_info,
  16. const Parse::GetTreeAndSubtreesStore* tree_and_subtrees_getters,
  17. clang::CodeGenerator* clang_code_generator, llvm::StringRef module_name,
  18. int total_ir_count, Lower::OptimizationLevel opt_level,
  19. llvm::raw_ostream* vlog_stream)
  20. : llvm_context_(llvm_context),
  21. clang_code_generator_(clang_code_generator),
  22. llvm_module_owner_(
  23. clang_code_generator_
  24. ? nullptr
  25. : std::make_unique<llvm::Module>(module_name, *llvm_context)),
  26. llvm_module_(llvm_module_owner_ ? llvm_module_owner_.get()
  27. : clang_code_generator_->GetModule()),
  28. file_system_(std::move(fs)),
  29. opt_level_(opt_level),
  30. di_builder_(*llvm_module_),
  31. di_compile_unit_(want_debug_info
  32. ? BuildDICompileUnit(llvm_module_->getName(),
  33. *llvm_module_, di_builder_)
  34. : nullptr),
  35. tree_and_subtrees_getters_(tree_and_subtrees_getters),
  36. vlog_stream_(vlog_stream),
  37. total_ir_count_(total_ir_count),
  38. file_contexts_(
  39. FileContextStore::MakeForOverwriteWithExplicitSize(total_ir_count_)) {
  40. }
  41. auto Context::GetFileContext(const SemIR::File* file,
  42. const SemIR::InstNamer* inst_namer)
  43. -> FileContext& {
  44. auto& file_context = file_contexts_.Get(file->check_ir_id());
  45. if (!file_context) {
  46. file_context =
  47. std::make_unique<FileContext>(*this, *file, inst_namer, vlog_stream_);
  48. file_context->PrepareToLower();
  49. }
  50. return *file_context;
  51. }
  52. auto Context::LowerPendingDefinitions() -> void {
  53. // Lower function definitions for generics.
  54. for (auto [file_context, function_id, specific_id] :
  55. GrowingRange(specific_function_definitions_)) {
  56. file_context->BuildFunctionDefinition(function_id, specific_id);
  57. }
  58. }
  59. auto Context::Finalize() && -> std::unique_ptr<llvm::Module> {
  60. LowerPendingDefinitions();
  61. for (auto& file_context : file_contexts_.values()) {
  62. if (file_context) {
  63. file_context->Finalize();
  64. }
  65. }
  66. return clang_code_generator_ ? std::unique_ptr<llvm::Module>(
  67. clang_code_generator_->ReleaseModule())
  68. : std::move(llvm_module_owner_);
  69. }
  70. auto Context::BuildDICompileUnit(llvm::StringRef module_name,
  71. llvm::Module& llvm_module,
  72. llvm::DIBuilder& di_builder)
  73. -> llvm::DICompileUnit* {
  74. llvm_module.addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
  75. llvm_module.addModuleFlag(llvm::Module::Warning, "Debug Info Version",
  76. llvm::DEBUG_METADATA_VERSION);
  77. // TODO: Include directory path in the compile_unit_file.
  78. llvm::DIFile* compile_unit_file = di_builder.createFile(module_name, "");
  79. // TODO: Introduce a new language code for Carbon. C++ works well for now
  80. // since it's something debuggers will already know/have support for at least.
  81. return di_builder.createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus,
  82. compile_unit_file, "carbon",
  83. /*isOptimized=*/false, /*Flags=*/"",
  84. /*RV=*/0);
  85. }
  86. auto Context::GetLocForDI(SemIR::AbsoluteNodeRef abs_node_id) -> LocForDI {
  87. if (abs_node_id.is_cpp()) {
  88. const SemIR::File* file = abs_node_id.file();
  89. // TODO: Consider asking our cpp_code_generator to map the location to a
  90. // debug location, in order to use Clang's rules for (eg) macro handling.
  91. auto loc = file->clang_source_locs().Get(abs_node_id.clang_source_loc_id());
  92. auto presumed_loc = file->cpp_file()->source_manager().getPresumedLoc(loc);
  93. return {
  94. .filename = presumed_loc.getFilename(),
  95. .line_number = static_cast<int32_t>(presumed_loc.getLine()),
  96. .column_number = static_cast<int32_t>(presumed_loc.getColumn()),
  97. };
  98. }
  99. const auto& tree_and_subtrees =
  100. tree_and_subtrees_getters().Get(abs_node_id.check_ir_id())();
  101. const auto& tokens = tree_and_subtrees.tree().tokens();
  102. if (abs_node_id.node_id().has_value()) {
  103. auto token =
  104. tree_and_subtrees.GetSubtreeTokenRange(abs_node_id.node_id()).begin;
  105. return {.filename = tokens.source().filename(),
  106. .line_number = tokens.GetLineNumber(token),
  107. .column_number = tokens.GetColumnNumber(token)};
  108. } else {
  109. return {.filename = tokens.source().filename(),
  110. .line_number = 0,
  111. .column_number = 0};
  112. }
  113. }
  114. } // namespace Carbon::Lower