diff --git a/Driver/Makefile b/Driver/Makefile index 7262cdc74a..66031d6fdd 100644 --- a/Driver/Makefile +++ b/Driver/Makefile @@ -6,7 +6,7 @@ TOOLNAME = clang USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSEMA.a \ clangAST.a clangParse.a clangLex.a clangBasic.a \ LLVMCore.a LLVMSupport.a LLVMSystem.a \ - LLVMBitWriter.a LLVMBitReader.a LLVMTarget.a + LLVMBitWriter.a LLVMBitReader.a LLVMCodeGen.a LLVMTarget.a diff --git a/Driver/clang.cpp b/Driver/clang.cpp index d3c40dcd25..c6ace84ea1 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -148,6 +148,13 @@ OutputFile("o", llvm::cl::value_desc("path"), llvm::cl::desc("Specify output file (for --serialize, this is a directory)")); +//===----------------------------------------------------------------------===// +// Code Generator Options +//===----------------------------------------------------------------------===// +static llvm::cl::opt +GenerateDebugInfo("g", + llvm::cl::desc("Generate source level debug information")); + //===----------------------------------------------------------------------===// // Diagnostic Options //===----------------------------------------------------------------------===// @@ -1161,7 +1168,7 @@ static ASTConsumer* CreateASTConsumer(const std::string& InFile, case EmitLLVM: case EmitBC: DestModule = new llvm::Module(InFile); - return CreateLLVMCodeGen(Diag, LangOpts, DestModule); + return CreateLLVMCodeGen(Diag, LangOpts, DestModule, GenerateDebugInfo); case SerializeAST: // FIXME: Allow user to tailor where the file is written. diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h index 8abb377f80..b6ec1cf142 100644 --- a/include/clang/CodeGen/ModuleBuilder.h +++ b/include/clang/CodeGen/ModuleBuilder.h @@ -24,7 +24,8 @@ namespace clang { class ASTConsumer; ASTConsumer *CreateLLVMCodeGen(Diagnostic &Diags, const LangOptions &Features, - llvm::Module *&DestModule); + llvm::Module *&DestModule, + bool GenerateDebugInfo); } #endif diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp new file mode 100644 index 0000000000..e0c76d32fb --- /dev/null +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -0,0 +1,171 @@ +//===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This coordinates the debug information generation while generating code. +// +//===----------------------------------------------------------------------===// + +#include "CGDebugInfo.h" +#include "CodeGenModule.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Module.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/IRBuilder.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/AST/ASTContext.h" +using namespace clang; +using namespace clang::CodeGen; + +CGDebugInfo::CGDebugInfo(CodeGenModule *m) +: M(m) +, CurLoc() +, PrevLoc() +, CompileUnitCache() +, StopPointFn(NULL) +, RegionStartFn(NULL) +, RegionEndFn(NULL) +, RegionStack() +{ + SR = new llvm::DISerializer(); + SR->setModule (&M->getModule()); +} + +CGDebugInfo::~CGDebugInfo() +{ + delete SR; +} + + +/// getCastValueFor - Return a llvm representation for a given debug information +/// descriptor cast to an empty struct pointer. +llvm::Value *CGDebugInfo::getCastValueFor(llvm::DebugInfoDesc *DD) { + return llvm::ConstantExpr::getBitCast(SR->Serialize(DD), + SR->getEmptyStructPtrType()); +} + +/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new +/// one if necessary. +llvm::CompileUnitDesc +*CGDebugInfo::getOrCreateCompileUnit(const SourceLocation Loc) { + + // See if this compile unit has been used before. + llvm::CompileUnitDesc *&Slot = CompileUnitCache[Loc.getFileID()]; + if (Slot) return Slot; + + // Create new compile unit. + // FIXME: Where to free these? + // One way is to iterate over the CompileUnitCache in ~CGDebugInfo. + llvm::CompileUnitDesc *Unit = new llvm::CompileUnitDesc(); + + // Make sure we have an anchor. + if (!CompileUnitAnchor) { + CompileUnitAnchor = new llvm::AnchorDesc(Unit); + } + + // Get source file information. + SourceManager &SM = M->getContext().getSourceManager(); + const FileEntry *FE = SM.getFileEntryForLoc(Loc); + const char *FileName = FE->getName(); + const char *DirName = FE->getDir()->getName(); + + Unit->setAnchor(CompileUnitAnchor); + Unit->setFileName(FileName); + Unit->setDirectory(DirName); + + // Set up producer name. + // FIXME: Do not know how to get clang version yet. + Unit->setProducer("clang"); + + // Set up Language number. + // FIXME: Handle other languages as well. + Unit->setLanguage(llvm::dwarf::DW_LANG_C89); + + // Update cache. + Slot = Unit; + + return Unit; +} + + +void +CGDebugInfo::EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder) { + + // Don't bother if things are the same as last time. + SourceManager &SM = M->getContext().getSourceManager(); + if (CurLoc == PrevLoc + || (SM.getLineNumber(CurLoc) == SM.getLineNumber(PrevLoc) + && SM.isFromSameFile(CurLoc, PrevLoc))) + return; + if (CurLoc.isInvalid()) return; + + // Update last state. + PrevLoc = CurLoc; + + // Get the appropriate compile unit. + llvm::CompileUnitDesc *Unit = getOrCreateCompileUnit(CurLoc); + + // Lazily construct llvm.dbg.stoppoint function. + if (!StopPointFn) + StopPointFn = llvm::Intrinsic::getDeclaration(&M->getModule(), + llvm::Intrinsic::dbg_stoppoint); + + uint64_t CurLineNo = SM.getLogicalLineNumber(CurLoc); + uint64_t ColumnNo = SM.getLogicalColumnNumber(CurLoc); + + // Invoke llvm.dbg.stoppoint + Builder.CreateCall3(StopPointFn, + llvm::ConstantInt::get(llvm::Type::Int32Ty, CurLineNo), + llvm::ConstantInt::get(llvm::Type::Int32Ty, ColumnNo), + getCastValueFor(Unit), ""); +} + +/// EmitRegionStart- Constructs the debug code for entering a declarative +/// region - "llvm.dbg.region.start.". +void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, llvm::IRBuilder &Builder) +{ + llvm::BlockDesc *Block = new llvm::BlockDesc(); + if (RegionStack.size() > 0) + Block->setContext(RegionStack.back()); + RegionStack.push_back(Block); + + // Lazily construct llvm.dbg.region.start function. + if (!RegionStartFn) + RegionStartFn = llvm::Intrinsic::getDeclaration(&M->getModule(), + llvm::Intrinsic::dbg_region_start); + + // Call llvm.dbg.func.start. + Builder.CreateCall(RegionStartFn, getCastValueFor(Block), ""); +} + +/// EmitRegionEnd - Constructs the debug code for exiting a declarative +/// region - "llvm.dbg.region.end." +void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder) +{ + // Lazily construct llvm.dbg.region.end function. + if (!RegionEndFn) + RegionEndFn =llvm::Intrinsic::getDeclaration(&M->getModule(), + llvm::Intrinsic::dbg_region_end); + + // Provide an region stop point. + EmitStopPoint(Fn, Builder); + + // Call llvm.dbg.func.end. + Builder.CreateCall(RegionEndFn, getCastValueFor(RegionStack.back()), ""); + RegionStack.pop_back(); + // FIXME: Free here the memory created for BlockDesc in RegionStart? +} + diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h new file mode 100644 index 0000000000..2097a1d2f0 --- /dev/null +++ b/lib/CodeGen/CGDebugInfo.h @@ -0,0 +1,84 @@ +//===--- CGDebugInfo.h - DebugInfo for LLVM CodeGen -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the source level debug info generator for llvm translation. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGDEBUGINFO_H +#define CLANG_CODEGEN_CGDEBUGINFO_H + +#include "clang/Basic/SourceLocation.h" +#include +#include + + +namespace llvm { + class Function; + class IRBuilder; + class DISerializer; + class CompileUnitDesc; + class BasicBlock; + class AnchorDesc; + class DebugInfoDesc; + class Value; +} + +namespace clang { +namespace CodeGen { + class CodeGenModule; + +/// DebugInfo - This class gathers all debug information during compilation and +/// is responsible for emitting to llvm globals or pass directly to the backend. +class CGDebugInfo { +private: + CodeGenModule *M; + llvm::DISerializer *SR; + SourceLocation CurLoc; + SourceLocation PrevLoc; + + /// CompileUnitCache - Cache of previously constructed CompileUnits. + std::map CompileUnitCache; + + llvm::Function *StopPointFn; + llvm::AnchorDesc *CompileUnitAnchor; + llvm::Function *RegionStartFn; + llvm::Function *RegionEndFn; + std::vector RegionStack; + +public: + CGDebugInfo(CodeGenModule *m); + ~CGDebugInfo(); + + void setLocation(SourceLocation loc) { CurLoc = loc; }; + + /// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of + /// source line. + void EmitStopPoint(llvm::Function *Fn, llvm::IRBuilder &Builder); + + /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start + /// of a new block. + void EmitRegionStart(llvm::Function *Fn, llvm::IRBuilder &Builder); + + /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a + /// block. + void EmitRegionEnd(llvm::Function *Fn, llvm::IRBuilder &Builder); + + /// getOrCreateCompileUnit - Get the compile unit from the cache or create a + /// new one if necessary. + llvm::CompileUnitDesc *getOrCreateCompileUnit(SourceLocation loc); + + /// getCastValueFor - Return a llvm representation for a given debug + /// information descriptor cast to an empty struct pointer. + llvm::Value *getCastValueFor(llvm::DebugInfoDesc *DD); +}; +} // namespace CodeGen +} // namespace clang + +#endif diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 8217af987d..d804ee6665 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "CGDebugInfo.h" +#include "CodeGenModule.h" #include "CodeGenFunction.h" #include "clang/AST/AST.h" #include "clang/Basic/TargetInfo.h" @@ -29,6 +31,18 @@ using namespace CodeGen; void CodeGenFunction::EmitStmt(const Stmt *S) { assert(S && "Null statement?"); + // Generate stoppoints if we are emitting debug info. + // Beginning of a Compound Statement (e.g. an opening '{') does not produce + // executable code. So do not generate a stoppoint for that. + CGDebugInfo *DI = CGM.getDebugInfo(); + if (DI && S->getStmtClass() != Stmt::CompoundStmtClass) { + if (S->getLocStart().isValid()) { + DI->setLocation(S->getLocStart()); + } + + DI->EmitStopPoint(CurFn, Builder); + } + switch (S->getStmtClass()) { default: // Must be an expression in a stmt context. Emit the value (to get @@ -74,11 +88,25 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, // FIXME: handle vla's etc. if (S.body_empty() || !isa(S.body_back())) GetLast = false; + CGDebugInfo *DI = CGM.getDebugInfo(); + if (DI) { + if (S.getLBracLoc().isValid()) { + DI->setLocation(S.getLBracLoc()); + } + DI->EmitRegionStart(CurFn, Builder); + } + for (CompoundStmt::const_body_iterator I = S.body_begin(), E = S.body_end()-GetLast; I != E; ++I) EmitStmt(*I); - - + + if (DI) { + if (S.getRBracLoc().isValid()) { + DI->setLocation(S.getRBracLoc()); + } + DI->EmitRegionEnd(CurFn, Builder); + } + if (!GetLast) return RValue::get(0); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d8b1fc327a..b234788a08 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "CGDebugInfo.h" #include "CodeGenModule.h" #include "CodeGenFunction.h" #include "clang/AST/ASTContext.h" @@ -32,13 +33,19 @@ using namespace CodeGen; CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO, llvm::Module &M, const llvm::TargetData &TD, - Diagnostic &diags) + Diagnostic &diags, bool GenerateDebugInfo) : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags), Types(C, M, TD), MemCpyFn(0), MemSetFn(0), CFConstantStringClassRef(0) { //TODO: Make this selectable at runtime Runtime = CreateObjCRuntime(M, getTypes().ConvertType(getContext().IntTy), getTypes().ConvertType(getContext().LongTy)); + + // If debug info generation is enabled, create the CGDebugInfo object. + if (GenerateDebugInfo) + DebugInfo = new CGDebugInfo(this); + else + DebugInfo = NULL; } CodeGenModule::~CodeGenModule() { @@ -49,7 +56,7 @@ CodeGenModule::~CodeGenModule() { EmitGlobalCtors(); EmitAnnotations(); delete Runtime; - + delete DebugInfo; // Run the verifier to check that the generated code is consistent. assert(!verifyModule(TheModule)); } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index e048d59564..8a3069e648 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -43,7 +43,8 @@ namespace clang { namespace CodeGen { class CodeGenFunction; - + class CGDebugInfo; + /// CodeGenModule - This class organizes the cross-module state that is used /// while generating LLVM code. class CodeGenModule { @@ -54,6 +55,7 @@ class CodeGenModule { Diagnostic &Diags; CodeGenTypes Types; CGObjCRuntime *Runtime; + CGDebugInfo *DebugInfo; llvm::Function *MemCpyFn; llvm::Function *MemSetFn; @@ -70,10 +72,12 @@ class CodeGenModule { std::vector BuiltinFunctions; public: CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M, - const llvm::TargetData &TD, Diagnostic &Diags); + const llvm::TargetData &TD, Diagnostic &Diags, + bool GenerateDebugInfo); ~CodeGenModule(); CGObjCRuntime *getObjCRuntime() { return Runtime; } + CGDebugInfo *getDebugInfo() { return DebugInfo; } ASTContext &getContext() const { return Context; } const LangOptions &getLangOptions() const { return Features; } llvm::Module &getModule() const { return TheModule; } diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index 53ee2e4551..6387c62279 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -34,13 +34,15 @@ namespace { const llvm::TargetData *TD; ASTContext *Ctx; const LangOptions &Features; + bool GenerateDebugInfo; protected: llvm::Module *&M; CodeGen::CodeGenModule *Builder; public: CodeGenerator(Diagnostic &diags, const LangOptions &LO, - llvm::Module *&DestModule) - : Diags(diags), Features(LO), M(DestModule) {} + llvm::Module *&DestModule, bool DebugInfoFlag) + : Diags(diags), Features(LO), GenerateDebugInfo(DebugInfoFlag), + M(DestModule) {} ~CodeGenerator() { delete Builder; @@ -52,7 +54,8 @@ namespace { M->setTargetTriple(Ctx->Target.getTargetTriple()); M->setDataLayout(Ctx->Target.getTargetDescription()); TD = new llvm::TargetData(Ctx->Target.getTargetDescription()); - Builder = new CodeGen::CodeGenModule(Context, Features, *M, *TD, Diags); + Builder = new CodeGen::CodeGenModule(Context, Features, *M, *TD, Diags, + GenerateDebugInfo); } virtual void HandleTopLevelDecl(Decl *D) { @@ -103,7 +106,8 @@ namespace { ASTConsumer *clang::CreateLLVMCodeGen(Diagnostic &Diags, const LangOptions &Features, - llvm::Module *&DestModule) { - return new CodeGenerator(Diags, Features, DestModule); + llvm::Module *&DestModule, + bool GenerateDebugInfo) { + return new CodeGenerator(Diags, Features, DestModule, GenerateDebugInfo); }