From 744016dde06fcffd50931e94a98c850f8b12cd87 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 6 Jul 2010 23:57:41 +0000 Subject: [PATCH] Provide a hook for the benefit of clients using clang IR gen as a subroutine: emit metadata associating allocas and global values with a Decl*. This feature is controlled by an option that (intentionally) cannot be enabled on the command line. To use this feature, simply set CodeGenOptions.EmitDeclMetadata = true; and then interpret the completely underspecified metadata. :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107739 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Frontend/CodeGenOptions.h | 4 ++ lib/CodeGen/CodeGenFunction.cpp | 3 + lib/CodeGen/CodeGenFunction.h | 2 + lib/CodeGen/CodeGenModule.cpp | 73 +++++++++++++++++++++++++ lib/CodeGen/CodeGenModule.h | 2 + 5 files changed, 84 insertions(+) diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index c25cfb32e6..2918f4e9d3 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -67,6 +67,9 @@ public: unsigned UnwindTables : 1; /// Emit unwind tables. unsigned VerifyModule : 1; /// Control whether the module should be run /// through the LLVM Verifier. + unsigned EmitDeclMetadata : 1; /// Emit special metadata indicating what Decl* + /// various IR entities came from. Only useful + /// when running CodeGen as a subroutine. /// The code model to use (-mcmodel). std::string CodeModel; @@ -122,6 +125,7 @@ public: UnrollLoops = 0; UnwindTables = 0; VerifyModule = 1; + EmitDeclMetadata = 0; Inlining = NoInlining; RelocationModel = "pic"; diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 9375b77360..5e505c2d82 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -173,6 +173,9 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { EmitIfUsed(*this, TerminateLandingPad); EmitIfUsed(*this, TerminateHandler); EmitIfUsed(*this, UnreachableBlock); + + if (CGM.getCodeGenOpts().EmitDeclMetadata) + EmitDeclMetadata(); } /// ShouldInstrumentFunction - Return true if the current function should be diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 850df7ee7c..00a0936044 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1548,6 +1548,8 @@ private: const TargetCodeGenInfo &getTargetHooks() const { return CGM.getTargetCodeGenInfo(); } + + void EmitDeclMetadata(); }; diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 7984db12d5..86aaf9925a 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -104,6 +104,9 @@ void CodeGenModule::Release() { EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitAnnotations(); EmitLLVMUsed(); + + if (getCodeGenOpts().EmitDeclMetadata) + EmitDeclMetadata(); } bool CodeGenModule::isTargetDarwin() const { @@ -2036,3 +2039,73 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { assert(isa(D) && "Unsupported decl kind"); } } + +/// Turns the given pointer into a constant. +static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context, + const void *Ptr) { + uintptr_t PtrInt = reinterpret_cast(Ptr); + const llvm::Type *i64 = llvm::Type::getInt64Ty(Context); + return llvm::ConstantInt::get(i64, PtrInt); +} + +static void EmitGlobalDeclMetadata(CodeGenModule &CGM, + llvm::NamedMDNode *&GlobalMetadata, + GlobalDecl D, + llvm::GlobalValue *Addr) { + if (!GlobalMetadata) + GlobalMetadata = + CGM.getModule().getOrInsertNamedMetadata("clang.global.decl.ptrs"); + + // TODO: should we report variant information for ctors/dtors? + llvm::Value *Ops[] = { + Addr, + GetPointerConstant(CGM.getLLVMContext(), D.getDecl()) + }; + GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops, 2)); +} + +/// Emits metadata nodes associating all the global values in the +/// current module with the Decls they came from. This is useful for +/// projects using IR gen as a subroutine. +/// +/// Since there's currently no way to associate an MDNode directly +/// with an llvm::GlobalValue, we create a global named metadata +/// with the name 'clang.global.decl.ptrs'. +void CodeGenModule::EmitDeclMetadata() { + llvm::NamedMDNode *GlobalMetadata = 0; + + // StaticLocalDeclMap + for (llvm::DenseMap::iterator + I = MangledDeclNames.begin(), E = MangledDeclNames.end(); + I != E; ++I) { + llvm::GlobalValue *Addr = getModule().getNamedValue(I->second); + EmitGlobalDeclMetadata(*this, GlobalMetadata, I->first, Addr); + } +} + +/// Emits metadata nodes for all the local variables in the current +/// function. +void CodeGenFunction::EmitDeclMetadata() { + if (LocalDeclMap.empty()) return; + + llvm::LLVMContext &Context = getLLVMContext(); + + // Find the unique metadata ID for this name. + unsigned DeclPtrKind = Context.getMDKindID("clang.decl.ptr"); + + llvm::NamedMDNode *GlobalMetadata = 0; + + for (llvm::DenseMap::iterator + I = LocalDeclMap.begin(), E = LocalDeclMap.end(); I != E; ++I) { + const Decl *D = I->first; + llvm::Value *Addr = I->second; + + if (llvm::AllocaInst *Alloca = dyn_cast(Addr)) { + llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D); + Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, &DAddr, 1)); + } else if (llvm::GlobalValue *GV = dyn_cast(Addr)) { + GlobalDecl GD = GlobalDecl(cast(D)); + EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV); + } + } +} diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index d0d3c7caee..a1ea0ec667 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -594,6 +594,8 @@ private: /// references to global which may otherwise be optimized out. void EmitLLVMUsed(void); + void EmitDeclMetadata(); + /// MayDeferGeneration - Determine if the given decl can be emitted /// lazily; this is only relevant for definitions. The given decl /// must be either a function or var decl. -- 2.40.0