Files
carbon-lang/toolchain/lower/context.cpp
T
Jon Ross-PerkinsandDana Jansens c3b0c2e425 Use LLVM verifier in lowering (#5733)
Suggested by zygoloid while looking at #5678 

```
CHECK failure at toolchain/lower/context.cpp:62: !llvm::verifyModule(*llvm_module_, &errs): Verifier errors: Instruction does not dominate all uses!
  %.loc17_46.1.temp = alloca { i1, i32, i32 }, align 8, !dbg !13
  %tuple.elem0.loc17_46.2.tuple.elem = getelementptr inbounds nuw { i1, i32, i32 }, ptr %.loc17_46.1.temp, i32 0, i32 0, !dbg !13
Instruction does not dominate all uses!
  %.loc17_46.1.temp = alloca { i1, i32, i32 }, align 8, !dbg !13
  %tuple.elem1.loc17_46.2.tuple.elem = getelementptr inbounds nuw { i1, i32, i32 }, ptr %.loc17_46.1.temp, i32 0, i32 1, !dbg !13
Instruction does not dominate all uses!
  %.loc17_46.1.temp = alloca { i1, i32, i32 }, align 8, !dbg !13
  %tuple.elem2.loc17_46.2.tuple.elem = getelementptr inbounds nuw { i1, i32, i32 }, ptr %.loc17_46.1.temp, i32 0, i32 2, !dbg !13
```

Adds a `--llvm-verifier` flag to be able to turn this off easily,
particularly for debugging the LLVM IR.

The call workaround is due to a verifier requirement `inlinable function
call in a function with debug info must have a !dbg location`. It
specifically comes up for the `++x` case, with `%1 = call i32
@"_CConvert.8b3d5d6a6c17be04:ImplicitAs.Core.b88d1103f417c6d4"(i32
%other)`. I think #5397 is in the direction of a fix for that, but #5397
was set aside because it puts the debug info in too many places.
Instead, address this by adding a stub location for calls that don't
have a good location. I'm deliberately putting this next to the TODO so
that it's easier to understand the association.

---------

Co-authored-by: Dana Jansens <danakj@orodu.net>
2025-06-26 21:34:09 +00:00

106 lines
4.0 KiB
C++

// 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/lower/context.h"
#include "common/check.h"
#include "common/growing_range.h"
#include "common/raw_string_ostream.h"
#include "common/vlog.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "toolchain/lower/file_context.h"
#include "toolchain/sem_ir/inst_namer.h"
namespace Carbon::Lower {
Context::Context(
llvm::LLVMContext& llvm_context,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs, bool want_debug_info,
llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> tree_and_subtrees_getters,
llvm::StringRef module_name, llvm::raw_ostream* vlog_stream)
: llvm_context_(&llvm_context),
llvm_module_(std::make_unique<llvm::Module>(module_name, llvm_context)),
file_system_(std::move(fs)),
di_builder_(*llvm_module_),
di_compile_unit_(
want_debug_info
? BuildDICompileUnit(module_name, *llvm_module_, di_builder_)
: nullptr),
tree_and_subtrees_getters_(tree_and_subtrees_getters),
vlog_stream_(vlog_stream) {}
auto Context::GetFileContext(const SemIR::File* file,
const SemIR::InstNamer* inst_namer)
-> FileContext& {
auto insert_result = file_contexts_.Insert(file->check_ir_id(), [&] {
auto file_context =
std::make_unique<FileContext>(*this, *file, inst_namer, vlog_stream_);
file_context->PrepareToLower();
return file_context;
});
return *insert_result.value();
}
auto Context::LowerPendingDefinitions() -> void {
// Lower function definitions for generics.
for (auto [file_context, function_id, specific_id] :
GrowingRange(specific_function_definitions_)) {
file_context->BuildFunctionDefinition(function_id, specific_id);
}
}
auto Context::Finalize(
llvm::raw_ostream*
llvm_verifier_stream) && -> std::unique_ptr<llvm::Module> {
LowerPendingDefinitions();
file_contexts_.ForEach(
[](auto, auto& file_context) { file_context->Finalize(); });
if (llvm_verifier_stream) {
CARBON_CHECK(!llvm::verifyModule(*llvm_module_, llvm_verifier_stream));
}
return std::move(llvm_module_);
}
auto Context::BuildDICompileUnit(llvm::StringRef module_name,
llvm::Module& llvm_module,
llvm::DIBuilder& di_builder)
-> llvm::DICompileUnit* {
llvm_module.addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
llvm_module.addModuleFlag(llvm::Module::Warning, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
// TODO: Include directory path in the compile_unit_file.
llvm::DIFile* compile_unit_file = di_builder.createFile(module_name, "");
// TODO: Introduce a new language code for Carbon. C works well for now since
// it's something debuggers will already know/have support for at least.
// Probably have to bump to C++ at some point for virtual functions,
// templates, etc.
return di_builder.createCompileUnit(llvm::dwarf::DW_LANG_C, compile_unit_file,
"carbon",
/*isOptimized=*/false, /*Flags=*/"",
/*RV=*/0);
}
auto Context::GetLocForDI(SemIR::AbsoluteNodeId abs_node_id) -> LocForDI {
const auto& tree_and_subtrees =
tree_and_subtrees_getters()[abs_node_id.check_ir_id().index]();
const auto& tokens = tree_and_subtrees.tree().tokens();
if (abs_node_id.node_id().has_value()) {
auto token =
tree_and_subtrees.GetSubtreeTokenRange(abs_node_id.node_id()).begin;
return {.filename = tokens.source().filename(),
.line_number = tokens.GetLineNumber(token),
.column_number = tokens.GetColumnNumber(token)};
} else {
return {.filename = tokens.source().filename(),
.line_number = 0,
.column_number = 0};
}
}
} // namespace Carbon::Lower