mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-21 20:45:53 -04:00

Extern variable usage in BPF is different from traditional pure user space application. Recent discussion in linux bpf mailing list has two use cases where debug info types are required to use extern variables: - extern types are required to have a suitable interface in libbpf (bpf loader) to provide kernel config parameters to bpf programs. https://lore.kernel.org/bpf/CAEf4BzYCNo5GeVGMhp3fhysQ=_axAf=23PtwaZs-yAyafmXC9g@mail.gmail.com/T/#t - extern types are required so kernel bpf verifier can verify program which uses external functions more precisely. This will make later link with actual external function no need to reverify. https://lore.kernel.org/bpf/87eez4odqp.fsf@toke.dk/T/#m8d5c3e87ffe7f2764e02d722cb0d8cbc136880ed This patch added clang support to emit debuginfo for extern variables with a TargetInfo hook to enable it. The debuginfo for the extern variable is emitted only if that extern variable is referenced in the current compilation unit. Currently, only BPF target enables to generate debug info for extern variables. The emission of such debuginfo is disabled for C++ at this moment since BPF only supports a subset of C language. Emission with C++ can be enabled later if an appropriate use case is identified. -fstandalone-debug permits us to see more debuginfo with the cost of bloated binary size. This patch did not add emission of extern variable debug info with -fstandalone-debug. This can be re-evaluated if there is a real need. Differential Revision: https://reviews.llvm.org/D70696
347 lines
12 KiB
C++
347 lines
12 KiB
C++
//===--- ModuleBuilder.cpp - Emit LLVM Code from ASTs ---------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This builds an AST and converts it to LLVM Code.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/CodeGen/ModuleBuilder.h"
|
|
#include "CGDebugInfo.h"
|
|
#include "CodeGenModule.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/DeclObjC.h"
|
|
#include "clang/AST/Expr.h"
|
|
#include "clang/Basic/CodeGenOptions.h"
|
|
#include "clang/Basic/Diagnostic.h"
|
|
#include "clang/Basic/TargetInfo.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include <memory>
|
|
|
|
using namespace clang;
|
|
using namespace CodeGen;
|
|
|
|
namespace {
|
|
class CodeGeneratorImpl : public CodeGenerator {
|
|
DiagnosticsEngine &Diags;
|
|
ASTContext *Ctx;
|
|
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
|
|
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
|
|
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
|
|
|
|
unsigned HandlingTopLevelDecls;
|
|
|
|
/// Use this when emitting decls to block re-entrant decl emission. It will
|
|
/// emit all deferred decls on scope exit. Set EmitDeferred to false if decl
|
|
/// emission must be deferred longer, like at the end of a tag definition.
|
|
struct HandlingTopLevelDeclRAII {
|
|
CodeGeneratorImpl &Self;
|
|
bool EmitDeferred;
|
|
HandlingTopLevelDeclRAII(CodeGeneratorImpl &Self,
|
|
bool EmitDeferred = true)
|
|
: Self(Self), EmitDeferred(EmitDeferred) {
|
|
++Self.HandlingTopLevelDecls;
|
|
}
|
|
~HandlingTopLevelDeclRAII() {
|
|
unsigned Level = --Self.HandlingTopLevelDecls;
|
|
if (Level == 0 && EmitDeferred)
|
|
Self.EmitDeferredDecls();
|
|
}
|
|
};
|
|
|
|
CoverageSourceInfo *CoverageInfo;
|
|
|
|
protected:
|
|
std::unique_ptr<llvm::Module> M;
|
|
std::unique_ptr<CodeGen::CodeGenModule> Builder;
|
|
|
|
private:
|
|
SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
|
|
|
|
static llvm::StringRef ExpandModuleName(llvm::StringRef ModuleName,
|
|
const CodeGenOptions &CGO) {
|
|
if (ModuleName == "-" && !CGO.MainFileName.empty())
|
|
return CGO.MainFileName;
|
|
return ModuleName;
|
|
}
|
|
|
|
public:
|
|
CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
|
|
const HeaderSearchOptions &HSO,
|
|
const PreprocessorOptions &PPO, const CodeGenOptions &CGO,
|
|
llvm::LLVMContext &C,
|
|
CoverageSourceInfo *CoverageInfo = nullptr)
|
|
: Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO),
|
|
PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
|
|
CoverageInfo(CoverageInfo),
|
|
M(new llvm::Module(ExpandModuleName(ModuleName, CGO), C)) {
|
|
C.setDiscardValueNames(CGO.DiscardValueNames);
|
|
}
|
|
|
|
~CodeGeneratorImpl() override {
|
|
// There should normally not be any leftover inline method definitions.
|
|
assert(DeferredInlineMemberFuncDefs.empty() ||
|
|
Diags.hasErrorOccurred());
|
|
}
|
|
|
|
CodeGenModule &CGM() {
|
|
return *Builder;
|
|
}
|
|
|
|
llvm::Module *GetModule() {
|
|
return M.get();
|
|
}
|
|
|
|
CGDebugInfo *getCGDebugInfo() {
|
|
return Builder->getModuleDebugInfo();
|
|
}
|
|
|
|
llvm::Module *ReleaseModule() {
|
|
return M.release();
|
|
}
|
|
|
|
const Decl *GetDeclForMangledName(StringRef MangledName) {
|
|
GlobalDecl Result;
|
|
if (!Builder->lookupRepresentativeDecl(MangledName, Result))
|
|
return nullptr;
|
|
const Decl *D = Result.getCanonicalDecl().getDecl();
|
|
if (auto FD = dyn_cast<FunctionDecl>(D)) {
|
|
if (FD->hasBody(FD))
|
|
return FD;
|
|
} else if (auto TD = dyn_cast<TagDecl>(D)) {
|
|
if (auto Def = TD->getDefinition())
|
|
return Def;
|
|
}
|
|
return D;
|
|
}
|
|
|
|
llvm::Constant *GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) {
|
|
return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition));
|
|
}
|
|
|
|
llvm::Module *StartModule(llvm::StringRef ModuleName,
|
|
llvm::LLVMContext &C) {
|
|
assert(!M && "Replacing existing Module?");
|
|
M.reset(new llvm::Module(ExpandModuleName(ModuleName, CodeGenOpts), C));
|
|
Initialize(*Ctx);
|
|
return M.get();
|
|
}
|
|
|
|
void Initialize(ASTContext &Context) override {
|
|
Ctx = &Context;
|
|
|
|
M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
|
|
M->setDataLayout(Ctx->getTargetInfo().getDataLayout());
|
|
const auto &SDKVersion = Ctx->getTargetInfo().getSDKVersion();
|
|
if (!SDKVersion.empty())
|
|
M->setSDKVersion(SDKVersion);
|
|
Builder.reset(new CodeGen::CodeGenModule(Context, HeaderSearchOpts,
|
|
PreprocessorOpts, CodeGenOpts,
|
|
*M, Diags, CoverageInfo));
|
|
|
|
for (auto &&Lib : CodeGenOpts.DependentLibraries)
|
|
Builder->AddDependentLib(Lib);
|
|
for (auto &&Opt : CodeGenOpts.LinkerOptions)
|
|
Builder->AppendLinkerOptions(Opt);
|
|
}
|
|
|
|
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return;
|
|
|
|
Builder->HandleCXXStaticMemberVarInstantiation(VD);
|
|
}
|
|
|
|
bool HandleTopLevelDecl(DeclGroupRef DG) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return true;
|
|
|
|
HandlingTopLevelDeclRAII HandlingDecl(*this);
|
|
|
|
// Make sure to emit all elements of a Decl.
|
|
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
|
|
Builder->EmitTopLevelDecl(*I);
|
|
|
|
return true;
|
|
}
|
|
|
|
void EmitDeferredDecls() {
|
|
if (DeferredInlineMemberFuncDefs.empty())
|
|
return;
|
|
|
|
// Emit any deferred inline method definitions. Note that more deferred
|
|
// methods may be added during this loop, since ASTConsumer callbacks
|
|
// can be invoked if AST inspection results in declarations being added.
|
|
HandlingTopLevelDeclRAII HandlingDecl(*this);
|
|
for (unsigned I = 0; I != DeferredInlineMemberFuncDefs.size(); ++I)
|
|
Builder->EmitTopLevelDecl(DeferredInlineMemberFuncDefs[I]);
|
|
DeferredInlineMemberFuncDefs.clear();
|
|
}
|
|
|
|
void HandleInlineFunctionDefinition(FunctionDecl *D) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return;
|
|
|
|
assert(D->doesThisDeclarationHaveABody());
|
|
|
|
// We may want to emit this definition. However, that decision might be
|
|
// based on computing the linkage, and we have to defer that in case we
|
|
// are inside of something that will change the method's final linkage,
|
|
// e.g.
|
|
// typedef struct {
|
|
// void bar();
|
|
// void foo() { bar(); }
|
|
// } A;
|
|
DeferredInlineMemberFuncDefs.push_back(D);
|
|
|
|
// Provide some coverage mapping even for methods that aren't emitted.
|
|
// Don't do this for templated classes though, as they may not be
|
|
// instantiable.
|
|
if (!D->getLexicalDeclContext()->isDependentContext())
|
|
Builder->AddDeferredUnusedCoverageMapping(D);
|
|
}
|
|
|
|
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
|
|
/// to (e.g. struct, union, enum, class) is completed. This allows the
|
|
/// client hack on the type, which can occur at any point in the file
|
|
/// (because these can be defined in declspecs).
|
|
void HandleTagDeclDefinition(TagDecl *D) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return;
|
|
|
|
// Don't allow re-entrant calls to CodeGen triggered by PCH
|
|
// deserialization to emit deferred decls.
|
|
HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
|
|
|
|
Builder->UpdateCompletedType(D);
|
|
|
|
// For MSVC compatibility, treat declarations of static data members with
|
|
// inline initializers as definitions.
|
|
if (Ctx->getTargetInfo().getCXXABI().isMicrosoft()) {
|
|
for (Decl *Member : D->decls()) {
|
|
if (VarDecl *VD = dyn_cast<VarDecl>(Member)) {
|
|
if (Ctx->isMSStaticDataMemberInlineDefinition(VD) &&
|
|
Ctx->DeclMustBeEmitted(VD)) {
|
|
Builder->EmitGlobal(VD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// For OpenMP emit declare reduction functions, if required.
|
|
if (Ctx->getLangOpts().OpenMP) {
|
|
for (Decl *Member : D->decls()) {
|
|
if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Member)) {
|
|
if (Ctx->DeclMustBeEmitted(DRD))
|
|
Builder->EmitGlobal(DRD);
|
|
} else if (auto *DMD = dyn_cast<OMPDeclareMapperDecl>(Member)) {
|
|
if (Ctx->DeclMustBeEmitted(DMD))
|
|
Builder->EmitGlobal(DMD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return;
|
|
|
|
// Don't allow re-entrant calls to CodeGen triggered by PCH
|
|
// deserialization to emit deferred decls.
|
|
HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
|
|
|
|
if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
|
|
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
|
|
DI->completeRequiredType(RD);
|
|
}
|
|
|
|
void HandleTranslationUnit(ASTContext &Ctx) override {
|
|
// Release the Builder when there is no error.
|
|
if (!Diags.hasErrorOccurred() && Builder)
|
|
Builder->Release();
|
|
|
|
// If there are errors before or when releasing the Builder, reset
|
|
// the module to stop here before invoking the backend.
|
|
if (Diags.hasErrorOccurred()) {
|
|
if (Builder)
|
|
Builder->clear();
|
|
M.reset();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void AssignInheritanceModel(CXXRecordDecl *RD) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return;
|
|
|
|
Builder->RefreshTypeCacheForClass(RD);
|
|
}
|
|
|
|
void CompleteTentativeDefinition(VarDecl *D) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return;
|
|
|
|
Builder->EmitTentativeDefinition(D);
|
|
}
|
|
|
|
void CompleteExternalDeclaration(VarDecl *D) override {
|
|
Builder->EmitExternalDeclaration(D);
|
|
}
|
|
|
|
void HandleVTable(CXXRecordDecl *RD) override {
|
|
if (Diags.hasErrorOccurred())
|
|
return;
|
|
|
|
Builder->EmitVTable(RD);
|
|
}
|
|
};
|
|
}
|
|
|
|
void CodeGenerator::anchor() { }
|
|
|
|
CodeGenModule &CodeGenerator::CGM() {
|
|
return static_cast<CodeGeneratorImpl*>(this)->CGM();
|
|
}
|
|
|
|
llvm::Module *CodeGenerator::GetModule() {
|
|
return static_cast<CodeGeneratorImpl*>(this)->GetModule();
|
|
}
|
|
|
|
llvm::Module *CodeGenerator::ReleaseModule() {
|
|
return static_cast<CodeGeneratorImpl*>(this)->ReleaseModule();
|
|
}
|
|
|
|
CGDebugInfo *CodeGenerator::getCGDebugInfo() {
|
|
return static_cast<CodeGeneratorImpl*>(this)->getCGDebugInfo();
|
|
}
|
|
|
|
const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) {
|
|
return static_cast<CodeGeneratorImpl*>(this)->GetDeclForMangledName(name);
|
|
}
|
|
|
|
llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global,
|
|
bool isForDefinition) {
|
|
return static_cast<CodeGeneratorImpl*>(this)
|
|
->GetAddrOfGlobal(global, isForDefinition);
|
|
}
|
|
|
|
llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
|
|
llvm::LLVMContext &C) {
|
|
return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
|
|
}
|
|
|
|
CodeGenerator *clang::CreateLLVMCodeGen(
|
|
DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
|
|
const HeaderSearchOptions &HeaderSearchOpts,
|
|
const PreprocessorOptions &PreprocessorOpts, const CodeGenOptions &CGO,
|
|
llvm::LLVMContext &C, CoverageSourceInfo *CoverageInfo) {
|
|
return new CodeGeneratorImpl(Diags, ModuleName, HeaderSearchOpts,
|
|
PreprocessorOpts, CGO, C, CoverageInfo);
|
|
}
|