context.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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/IR/Verifier.h"
  10. #include "llvm/Transforms/Utils/ModuleUtils.h"
  11. #include "toolchain/lower/file_context.h"
  12. #include "toolchain/sem_ir/inst_namer.h"
  13. namespace Carbon::Lower {
  14. Context::Context(
  15. llvm::LLVMContext& llvm_context,
  16. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs, bool want_debug_info,
  17. llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> tree_and_subtrees_getters,
  18. llvm::StringRef module_name, llvm::raw_ostream* vlog_stream)
  19. : llvm_context_(&llvm_context),
  20. llvm_module_(std::make_unique<llvm::Module>(module_name, llvm_context)),
  21. file_system_(std::move(fs)),
  22. di_builder_(*llvm_module_),
  23. di_compile_unit_(
  24. want_debug_info
  25. ? BuildDICompileUnit(module_name, *llvm_module_, di_builder_)
  26. : nullptr),
  27. tree_and_subtrees_getters_(tree_and_subtrees_getters),
  28. vlog_stream_(vlog_stream) {}
  29. auto Context::GetFileContext(const SemIR::File* file,
  30. const SemIR::InstNamer* inst_namer)
  31. -> FileContext& {
  32. auto insert_result = file_contexts_.Insert(file->check_ir_id(), [&] {
  33. auto file_context =
  34. std::make_unique<FileContext>(*this, *file, inst_namer, vlog_stream_);
  35. file_context->PrepareToLower();
  36. return file_context;
  37. });
  38. return *insert_result.value();
  39. }
  40. auto Context::LowerPendingDefinitions() -> void {
  41. // Lower function definitions for generics.
  42. for (auto [file_context, function_id, specific_id] :
  43. GrowingRange(specific_function_definitions_)) {
  44. file_context->BuildFunctionDefinition(function_id, specific_id);
  45. }
  46. }
  47. auto Context::Finalize(
  48. llvm::raw_ostream*
  49. llvm_verifier_stream) && -> std::unique_ptr<llvm::Module> {
  50. LowerPendingDefinitions();
  51. file_contexts_.ForEach(
  52. [](auto, auto& file_context) { file_context->Finalize(); });
  53. if (llvm_verifier_stream) {
  54. CARBON_CHECK(!llvm::verifyModule(*llvm_module_, llvm_verifier_stream));
  55. }
  56. return std::move(llvm_module_);
  57. }
  58. auto Context::BuildDICompileUnit(llvm::StringRef module_name,
  59. llvm::Module& llvm_module,
  60. llvm::DIBuilder& di_builder)
  61. -> llvm::DICompileUnit* {
  62. llvm_module.addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
  63. llvm_module.addModuleFlag(llvm::Module::Warning, "Debug Info Version",
  64. llvm::DEBUG_METADATA_VERSION);
  65. // TODO: Include directory path in the compile_unit_file.
  66. llvm::DIFile* compile_unit_file = di_builder.createFile(module_name, "");
  67. // TODO: Introduce a new language code for Carbon. C works well for now since
  68. // it's something debuggers will already know/have support for at least.
  69. // Probably have to bump to C++ at some point for virtual functions,
  70. // templates, etc.
  71. return di_builder.createCompileUnit(llvm::dwarf::DW_LANG_C, compile_unit_file,
  72. "carbon",
  73. /*isOptimized=*/false, /*Flags=*/"",
  74. /*RV=*/0);
  75. }
  76. auto Context::GetLocForDI(SemIR::AbsoluteNodeId abs_node_id) -> LocForDI {
  77. const auto& tree_and_subtrees =
  78. tree_and_subtrees_getters()[abs_node_id.check_ir_id().index]();
  79. const auto& tokens = tree_and_subtrees.tree().tokens();
  80. if (abs_node_id.node_id().has_value()) {
  81. auto token =
  82. tree_and_subtrees.GetSubtreeTokenRange(abs_node_id.node_id()).begin;
  83. return {.filename = tokens.source().filename(),
  84. .line_number = tokens.GetLineNumber(token),
  85. .column_number = tokens.GetColumnNumber(token)};
  86. } else {
  87. return {.filename = tokens.source().filename(),
  88. .line_number = 0,
  89. .column_number = 0};
  90. }
  91. }
  92. } // namespace Carbon::Lower