| //===-------------- Debug.cpp - Debug information gathering ---------------===// |
| // |
| // Copyright (C) 2005 to 2013 Jim Laskey, Duncan Sands et al. |
| // |
| // This file is part of DragonEgg. |
| // |
| // DragonEgg is free software; you can redistribute it and/or modify it under |
| // the terms of the GNU General Public License as published by the Free Software |
| // Foundation; either version 2, or (at your option) any later version. |
| // |
| // DragonEgg is distributed in the hope that it will be useful, but WITHOUT ANY |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR |
| // A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License along with |
| // DragonEgg; see the file COPYING. If not, write to the Free Software |
| // Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. |
| // |
| //===----------------------------------------------------------------------===// |
| // This file implements debug information gathering. |
| //===----------------------------------------------------------------------===// |
| |
| // Plugin headers |
| #include "dragonegg/Debug.h" |
| |
| // LLVM headers |
| #include "llvm/IR/Module.h" |
| |
| // System headers |
| #include <gmp.h> |
| |
| // GCC headers |
| #include "auto-host.h" |
| #ifndef ENABLE_BUILD_WITH_CXX |
| #include <cstring> // Otherwise included by system.h with C linkage. |
| extern "C" { |
| #endif |
| #include "config.h" |
| // Stop GCC declaring 'getopt' as it can clash with the system's declaration. |
| #undef HAVE_DECL_GETOPT |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| |
| #include "flags.h" |
| #include "langhooks.h" |
| #include "toplev.h" |
| #include "version.h" |
| #ifndef ENABLE_BUILD_WITH_CXX |
| } // extern "C" |
| #endif |
| |
| // Trees header. |
| #include "dragonegg/Trees.h" |
| |
| using namespace llvm; |
| using namespace llvm::dwarf; |
| |
| /// DirectoryAndFile - Extract the directory and file name from a path. If no |
| /// directory is specified, then use the source working directory. |
| static void DirectoryAndFile(const std::string &FullPath, |
| std::string &Directory, std::string &FileName) { |
| // Look for the directory slash. |
| size_t Slash = FullPath.rfind('/'); |
| |
| // If no slash |
| if (Slash == std::string::npos) { |
| // The entire path is the file name. |
| Directory = ""; |
| FileName = FullPath; |
| } else { |
| // Separate the directory from the file name. |
| Directory = FullPath.substr(0, Slash); |
| FileName = FullPath.substr(Slash + 1); |
| } |
| |
| // If no directory present then use source working directory. |
| if (Directory.empty() || Directory[0] != '/') { |
| Directory = std::string(get_src_pwd()) + "/" + Directory; |
| } |
| } |
| |
| /// NodeSizeInBits - Returns the size in bits stored in a tree node regardless |
| /// of whether the node is a TYPE or DECL. |
| static uint64_t NodeSizeInBits(tree Node) { |
| if (isa<ERROR_MARK>(Node)) { |
| return BITS_PER_WORD; |
| } else if (isa<TYPE>(Node)) { |
| if (TYPE_SIZE(Node) == NULL_TREE) |
| return 0; |
| else if (isInt64(TYPE_SIZE(Node), true)) |
| return getInt64(TYPE_SIZE(Node), true); |
| else |
| return TYPE_ALIGN(Node); |
| } else if (DECL_P(Node)) { |
| if (DECL_SIZE(Node) == NULL_TREE) |
| return 0; |
| else if (isInt64(DECL_SIZE(Node), 1)) |
| return getInt64(DECL_SIZE(Node), 1); |
| else |
| return DECL_ALIGN(Node); |
| } |
| |
| return 0; |
| } |
| |
| /// NodeAlignInBits - Returns the alignment in bits stored in a tree node |
| /// regardless of whether the node is a TYPE or DECL. |
| static uint64_t NodeAlignInBits(tree Node) { |
| if (isa<ERROR_MARK>(Node)) |
| return BITS_PER_WORD; |
| if (isa<TYPE>(Node)) |
| return TYPE_ALIGN(Node); |
| if (DECL_P(Node)) |
| return DECL_ALIGN(Node); |
| return BITS_PER_WORD; |
| } |
| |
| /// FieldType - Returns the type node of a structure member field. |
| /// |
| static tree FieldType(tree Field) { |
| if (isa<ERROR_MARK>(Field)) |
| return integer_type_node; |
| return DECL_BIT_FIELD_TYPE(Field) ? DECL_BIT_FIELD_TYPE(Field) |
| : TREE_TYPE(Field); |
| } |
| |
| /// GetNodeName - Returns the name stored in a node regardless of whether the |
| /// node is a TYPE or DECL. |
| static StringRef GetNodeName(tree Node) { |
| tree Name = NULL; |
| |
| if (DECL_P(Node)) { |
| Name = DECL_NAME(Node); |
| } else if (isa<TYPE>(Node)) { |
| Name = TYPE_NAME(Node); |
| } |
| |
| if (Name) { |
| if (isa<IDENTIFIER_NODE>(Name)) { |
| return IDENTIFIER_POINTER(Name); |
| } else if (isa<TYPE_DECL>(Name) && DECL_NAME(Name) && |
| !DECL_IGNORED_P(Name)) { |
| return StringRef(IDENTIFIER_POINTER(DECL_NAME(Name))); |
| } |
| } |
| |
| return StringRef(); |
| } |
| |
| /// GetNodeLocation - Returns the location stored in a node regardless of |
| /// whether the node is a TYPE or DECL. UseStub is true if we should consider |
| /// the type stub as the actually location (ignored in struct/unions/enums.) |
| static expanded_location GetNodeLocation(tree Node, bool UseStub = true) { |
| expanded_location Location = {}; |
| |
| if (Node == NULL_TREE) |
| return Location; |
| |
| tree Name = NULL; |
| |
| if (DECL_P(Node)) { |
| Name = DECL_NAME(Node); |
| } else if (isa<TYPE>(Node)) { |
| Name = TYPE_NAME(Node); |
| } |
| |
| if (Name) { |
| if (isa<TYPE>(Name) && TYPE_STUB_DECL(Name)) { |
| tree Stub = TYPE_STUB_DECL(Name); |
| Location = expand_location(DECL_SOURCE_LOCATION(Stub)); |
| } else if (DECL_P(Name)) { |
| Location = expand_location(DECL_SOURCE_LOCATION(Name)); |
| } |
| } |
| |
| if (!Location.line) { |
| if (UseStub && isa<TYPE>(Node) && TYPE_STUB_DECL(Node)) { |
| tree Stub = TYPE_STUB_DECL(Node); |
| Location = expand_location(DECL_SOURCE_LOCATION(Stub)); |
| } else if (DECL_P(Node)) { |
| Location = expand_location(DECL_SOURCE_LOCATION(Node)); |
| } |
| } |
| |
| return Location; |
| } |
| |
| static StringRef getLinkageName(tree Node) { |
| |
| // Use llvm value name as linkage name if it is available. |
| if (DECL_LLVM_SET_P(Node)) { |
| Value *V = DECL_LLVM(Node); |
| return V->getName(); |
| } |
| |
| tree decl_name = DECL_NAME(Node); |
| if (decl_name != NULL && IDENTIFIER_POINTER(decl_name) != NULL) { |
| if (TREE_PUBLIC(Node) && DECL_ASSEMBLER_NAME(Node) != DECL_NAME(Node) && |
| !DECL_ABSTRACT(Node)) { |
| return StringRef(IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(Node))); |
| } |
| } |
| return StringRef(); |
| } |
| |
| DebugInfo::DebugInfo(Module *m) |
| : M(*m), VMContext(M.getContext()), Builder(M), DeclareFn(0), |
| ValueFn(0), CurFullPath(""), PrevFullPath(""), CurLineNo(0), PrevLineNo(0), |
| PrevBB(NULL) {} |
| |
| /// getFunctionName - Get function name for the given FnDecl. If the |
| /// name is constructred on demand (e.g. C++ destructor) then the name |
| /// is stored on the side. |
| StringRef DebugInfo::getFunctionName(tree FnDecl) { |
| StringRef FnNodeName = GetNodeName(FnDecl); |
| // Use dwarf_name to construct function names. In C++ this is used to |
| // create human readable destructor names. |
| StringRef FnName = lang_hooks.dwarf_name(FnDecl, 0); |
| if (FnNodeName.equals(FnName)) |
| return FnNodeName; |
| |
| // Use name returned by dwarf_name. It is in a temp. storage so make a |
| // copy first. |
| char *StrPtr = FunctionNames.Allocate<char>(FnName.size() + 1); |
| strncpy(StrPtr, FnName.data(), FnName.size()); |
| StrPtr[FnName.size()] = 0; |
| return StringRef(StrPtr); |
| } |
| |
| /// EmitFunctionStart - Constructs the debug code for entering a function. |
| void DebugInfo::EmitFunctionStart(tree FnDecl, Function *Fn) { |
| DIType FNType = getOrCreateType(TREE_TYPE(FnDecl)); |
| |
| unsigned lineno = CurLineNo; |
| |
| std::map<tree_node *, WeakVH>::iterator I = SPCache.find(FnDecl); |
| if (I != SPCache.end()) { |
| DISubprogram SPDecl(cast<MDNode>(I->second)); |
| DISubprogram SP = CreateSubprogramDefinition(SPDecl, lineno, Fn); |
| SPDecl->replaceAllUsesWith(SP); |
| |
| // Push function on region stack. |
| RegionStack.push_back(WeakVH(SP)); |
| RegionMap[FnDecl] = WeakVH(SP); |
| return; |
| } |
| |
| bool ArtificialFnWithAbstractOrigin = false; |
| // If this artificial function has abstract origin then put this function |
| // at module scope. The abstract copy will be placed in appropriate region. |
| if (DECL_ARTIFICIAL(FnDecl) && DECL_ABSTRACT_ORIGIN(FnDecl) && |
| DECL_ABSTRACT_ORIGIN(FnDecl) != FnDecl) |
| ArtificialFnWithAbstractOrigin = true; |
| |
| DIDescriptor SPContext = |
| ArtificialFnWithAbstractOrigin ? getOrCreateFile(main_input_filename) |
| : findRegion(DECL_CONTEXT(FnDecl)); |
| |
| // Creating context may have triggered creation of this SP descriptor. So |
| // check the cache again. |
| I = SPCache.find(FnDecl); |
| if (I != SPCache.end()) { |
| DISubprogram SPDecl(cast<MDNode>(I->second)); |
| DISubprogram SP = CreateSubprogramDefinition(SPDecl, lineno, Fn); |
| SPDecl->replaceAllUsesWith(SP); |
| |
| // Push function on region stack. |
| RegionStack.push_back(WeakVH(SP)); |
| RegionMap[FnDecl] = WeakVH(SP); |
| return; |
| } |
| |
| // Gather location information. |
| expanded_location Loc = GetNodeLocation(FnDecl, false); |
| StringRef LinkageName = getLinkageName(FnDecl); |
| |
| unsigned Virtuality = 0; |
| unsigned VIndex = 0; |
| DIType ContainingType; |
| if (DECL_VINDEX(FnDecl) && DECL_CONTEXT(FnDecl) && |
| isa<TYPE>((DECL_CONTEXT(FnDecl)))) { // Workaround GCC PR42653 |
| if (host_integerp(DECL_VINDEX(FnDecl), 0)) |
| VIndex = tree_low_cst(DECL_VINDEX(FnDecl), 0); |
| Virtuality = dwarf::DW_VIRTUALITY_virtual; |
| ContainingType = getOrCreateType(DECL_CONTEXT(FnDecl)); |
| } |
| |
| StringRef FnName = getFunctionName(FnDecl); |
| |
| DISubprogram SP = CreateSubprogram( |
| SPContext, FnName, FnName, LinkageName, getOrCreateFile(Loc.file), lineno, |
| FNType, Fn->hasInternalLinkage(), true /*definition*/, Virtuality, VIndex, |
| ContainingType, DECL_ARTIFICIAL(FnDecl), optimize, Fn); |
| |
| SPCache[FnDecl] = WeakVH(SP); |
| |
| // Push function on region stack. |
| RegionStack.push_back(WeakVH(SP)); |
| RegionMap[FnDecl] = WeakVH(SP); |
| } |
| |
| /// getOrCreateNameSpace - Get name space descriptor for the tree node. |
| DINameSpace DebugInfo::getOrCreateNameSpace(tree Node, DIDescriptor Context) { |
| std::map<tree_node *, WeakVH>::iterator I = NameSpaceCache.find(Node); |
| if (I != NameSpaceCache.end()) |
| return DINameSpace(cast<MDNode>(I->second)); |
| |
| expanded_location Loc = GetNodeLocation(Node, false); |
| DINameSpace DNS = Builder.createNameSpace( |
| Context, GetNodeName(Node), getOrCreateFile(Loc.file), Loc.line); |
| |
| NameSpaceCache[Node] = WeakVH(DNS); |
| return DNS; |
| } |
| |
| /// findRegion - Find tree_node N's region. |
| DIDescriptor DebugInfo::findRegion(tree Node) { |
| if (Node == NULL_TREE) |
| return getOrCreateFile(main_input_filename); |
| |
| std::map<tree_node *, WeakVH>::iterator I = RegionMap.find(Node); |
| if (I != RegionMap.end()) |
| if (MDNode *R = dyn_cast_or_null<MDNode>(&*I->second)) |
| return DIDescriptor(R); |
| |
| if (isa<TYPE>(Node)) { |
| DIType Ty = getOrCreateType(Node); |
| return DIDescriptor(Ty); |
| } else if (DECL_P(Node)) { |
| if (isa<NAMESPACE_DECL>(Node)) { |
| DIDescriptor NSContext = findRegion(DECL_CONTEXT(Node)); |
| DINameSpace NS = getOrCreateNameSpace(Node, NSContext); |
| return DIDescriptor(NS); |
| } |
| return findRegion(DECL_CONTEXT(Node)); |
| } |
| |
| // Otherwise main compile unit covers everything. |
| return getOrCreateFile(main_input_filename); |
| } |
| |
| /// EmitFunctionEnd - Pop the region stack and reset current lexical block. |
| void DebugInfo::EmitFunctionEnd(bool EndFunction) { |
| assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); |
| RegionStack.pop_back(); |
| // Blocks get erased; clearing these is needed for determinism, and also |
| // a good idea if the next function gets inlined. |
| if (EndFunction) { |
| PrevBB = NULL; |
| PrevLineNo = 0; |
| PrevFullPath = NULL; |
| } |
| } |
| |
| /// EmitDeclare - Constructs the debug code for allocation of a new variable. |
| void DebugInfo::EmitDeclare(tree decl, unsigned Tag, StringRef Name, tree type, |
| Value *AI, LLVMBuilder &IRBuilder) { |
| |
| // Ignore compiler generated temporaries. |
| if (DECL_IGNORED_P(decl)) |
| return; |
| |
| assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); |
| |
| expanded_location Loc = GetNodeLocation(decl, false); |
| |
| // Construct variable. |
| DIScope VarScope = DIScope(cast<MDNode>(RegionStack.back())); |
| DIType Ty = getOrCreateType(type); |
| if (Ty && DECL_ARTIFICIAL(decl)) |
| Ty = Builder.createArtificialType(Ty); |
| // If type info is not available then do not emit debug info for this var. |
| if (!Ty) |
| return; |
| llvm::DIVariable D = Builder.createLocalVariable( |
| Tag, VarScope, Name, getOrCreateFile(Loc.file), Loc.line, Ty, optimize); |
| |
| Instruction *Call = InsertDeclare(AI, D, IRBuilder.GetInsertBlock()); |
| |
| Call->setDebugLoc(DebugLoc::get(Loc.line, 0, VarScope)); |
| } |
| |
| /// EmitStopPoint - Set current source location. |
| void DebugInfo::EmitStopPoint(BasicBlock *CurBB, LLVMBuilder &Builder) { |
| // Don't bother if things are the same as last time. |
| if (PrevLineNo == CurLineNo && PrevBB == CurBB && |
| (PrevFullPath == CurFullPath || !strcmp(PrevFullPath, CurFullPath))) |
| return; |
| if (!CurFullPath[0] || CurLineNo == 0) |
| return; |
| |
| // Update last state. |
| PrevFullPath = CurFullPath; |
| PrevLineNo = CurLineNo; |
| PrevBB = CurBB; |
| |
| if (RegionStack.empty()) |
| return; |
| MDNode *Scope = cast<MDNode>(RegionStack.back()); |
| Builder.SetCurrentDebugLocation(DebugLoc::get(CurLineNo, 0 /*col*/, Scope)); |
| } |
| |
| /// EmitGlobalVariable - Emit information about a global variable. |
| /// |
| void DebugInfo::EmitGlobalVariable(GlobalVariable *GV, tree decl) { |
| if (DECL_ARTIFICIAL(decl) || DECL_IGNORED_P(decl)) |
| return; |
| // Gather location information. |
| expanded_location Loc = expand_location(DECL_SOURCE_LOCATION(decl)); |
| DIType TyD = getOrCreateType(TREE_TYPE(decl)); |
| StringRef DispName = GV->getName(); |
| if (DispName.empty()) |
| DispName = "__unknown__"; |
| if (DECL_NAME(decl)) { |
| if (IDENTIFIER_POINTER(DECL_NAME(decl))) |
| DispName = IDENTIFIER_POINTER(DECL_NAME(decl)); |
| } |
| StringRef LinkageName; |
| // The gdb does not expect linkage names for function local statics. |
| if (DECL_CONTEXT(decl)) |
| if (!isa<FUNCTION_DECL>(DECL_CONTEXT(decl))) |
| LinkageName = GV->getName(); |
| Builder.createStaticVariable( |
| findRegion(DECL_CONTEXT(decl)), DispName, LinkageName, |
| getOrCreateFile(Loc.file), Loc.line, TyD, GV->hasInternalLinkage(), GV); |
| } |
| |
| /// createBasicType - Create BasicType. |
| DIType DebugInfo::createBasicType(tree type) { |
| |
| StringRef TypeName = GetNodeName(type); |
| if (TypeName.empty()) |
| TypeName = "__unknown__"; |
| uint64_t Size = NodeSizeInBits(type); |
| uint64_t Align = NodeAlignInBits(type); |
| |
| unsigned Encoding = 0; |
| |
| switch (TREE_CODE(type)) { |
| case INTEGER_TYPE: |
| if (TYPE_STRING_FLAG(type)) { |
| if (TYPE_UNSIGNED(type)) |
| Encoding = DW_ATE_unsigned_char; |
| else |
| Encoding = DW_ATE_signed_char; |
| } else if (TYPE_UNSIGNED(type)) |
| Encoding = DW_ATE_unsigned; |
| else |
| Encoding = DW_ATE_signed; |
| break; |
| case REAL_TYPE: |
| Encoding = DW_ATE_float; |
| break; |
| case COMPLEX_TYPE: |
| Encoding = |
| isa<REAL_TYPE>(TREE_TYPE(type)) ? DW_ATE_complex_float : DW_ATE_lo_user; |
| break; |
| case BOOLEAN_TYPE: |
| Encoding = DW_ATE_boolean; |
| break; |
| default: |
| llvm_unreachable("Basic type case missing"); |
| } |
| |
| return Builder.createBasicType(TypeName, Size, Align, Encoding); |
| } |
| |
| /// isArtificialArgumentType - Return true if arg_type represents artificial, |
| /// i.e. "this" in c++, argument. |
| static bool isArtificialArgumentType(tree arg_type, tree method_type) { |
| if (!isa<METHOD_TYPE>(method_type)) |
| return false; |
| if (!isa<POINTER_TYPE>(arg_type)) |
| return false; |
| if (TREE_TYPE(arg_type) == TYPE_METHOD_BASETYPE(method_type)) |
| return true; |
| if (main_type(arg_type) && main_type(arg_type) != TREE_TYPE(arg_type) && |
| (main_type(arg_type) == TYPE_METHOD_BASETYPE(method_type))) |
| return true; |
| return false; |
| } |
| |
| /// createMethodType - Create MethodType. |
| DIType DebugInfo::createMethodType(tree type) { |
| |
| // Create a place holder type first. The may be used as a context |
| // for the argument types. |
| llvm::DIType FwdType = Builder.createReplaceableForwardDecl( |
| llvm::dwarf::DW_TAG_subroutine_type, StringRef(), |
| findRegion(TYPE_CONTEXT(type)), getOrCreateFile(main_input_filename), |
| 0, 0, 0, 0); |
| llvm::MDNode *FTN = FwdType; |
| llvm::TrackingVH<llvm::MDNode> FwdTypeNode = FTN; |
| TypeCache[type] = WeakVH(FwdType); |
| // Push the struct on region stack. |
| RegionStack.push_back(WeakVH(FwdType)); |
| RegionMap[type] = WeakVH(FwdType); |
| |
| llvm::SmallVector<Value*, 16> EltTys; |
| |
| // Add the result type at least. |
| EltTys.push_back(getOrCreateType(TREE_TYPE(type))); |
| |
| // Set up remainder of arguments. |
| bool ProcessedFirstArg = false; |
| for (tree arg = TYPE_ARG_TYPES(type); arg; arg = TREE_CHAIN(arg)) { |
| tree formal_type = TREE_VALUE(arg); |
| if (formal_type == void_type_node) |
| break; |
| llvm::DIType FormalType = getOrCreateType(formal_type); |
| if (!ProcessedFirstArg && isArtificialArgumentType(formal_type, type)) { |
| DIType AFormalType = Builder.createArtificialType(FormalType); |
| EltTys.push_back(AFormalType); |
| } else |
| EltTys.push_back(FormalType); |
| if (!ProcessedFirstArg) |
| ProcessedFirstArg = true; |
| } |
| |
| llvm::DIArray EltTypeArray = Builder.getOrCreateArray(EltTys); |
| |
| RegionStack.pop_back(); |
| std::map<tree_node *, WeakVH>::iterator RI = RegionMap.find(type); |
| if (RI != RegionMap.end()) |
| RegionMap.erase(RI); |
| |
| llvm::DIType RealType = CreateCompositeType( |
| llvm::dwarf::DW_TAG_subroutine_type, findRegion(TYPE_CONTEXT(type)), |
| StringRef(), getOrCreateFile(main_input_filename), 0, 0, 0, 0, 0, |
| llvm::DIType(), EltTypeArray); |
| |
| // Now that we have a real decl for the struct, replace anything using the |
| // old decl with the new one. This will recursively update the debug info. |
| llvm::DIType(FwdTypeNode).replaceAllUsesWith(RealType); |
| |
| return RealType; |
| } |
| |
| /// createPointerType - Create PointerType. |
| DIType DebugInfo::createPointerType(tree type) { |
| |
| DIType FromTy = getOrCreateType(TREE_TYPE(type)); |
| // type* and type& |
| // FIXME: Should BLOCK_POINTER_TYP have its own DW_TAG? |
| unsigned Tag = |
| isa<REFERENCE_TYPE>(type) ? DW_TAG_reference_type : DW_TAG_pointer_type; |
| unsigned Flags = 0; |
| |
| // Check if this pointer type has a name. |
| if (tree TyName = TYPE_NAME(type)) |
| if (isa<TYPE_DECL>(TyName) && !DECL_ORIGINAL_TYPE(TyName)) { |
| expanded_location TypeNameLoc = GetNodeLocation(TyName); |
| DIType Ty = CreateDerivedType( |
| Tag, findRegion(DECL_CONTEXT(TyName)), GetNodeName(TyName), |
| getOrCreateFile(TypeNameLoc.file), TypeNameLoc.line, 0 /*size*/, |
| 0 /*align*/, 0 /*offset */, 0 /*flags*/, FromTy); |
| TypeCache[TyName] = WeakVH(Ty); |
| return Ty; |
| } |
| |
| StringRef PName = FromTy.getName(); |
| DIType PTy = CreateDerivedType( |
| Tag, findRegion(TYPE_CONTEXT(type)), |
| Tag == DW_TAG_pointer_type ? StringRef() : PName, |
| getOrCreateFile(main_input_filename), 0 /*line no*/, NodeSizeInBits(type), |
| NodeAlignInBits(type), 0 /*offset */, Flags, FromTy); |
| return PTy; |
| } |
| |
| /// createArrayType - Create ArrayType. |
| DIType DebugInfo::createArrayType(tree type) { |
| // Add the dimensions of the array. FIXME: This loses CV qualifiers from |
| // interior arrays, do we care? Why aren't nested arrays represented the |
| // obvious/recursive way? |
| llvm::SmallVector<Value*, 8> Subscripts; |
| |
| // There will be ARRAY_TYPE nodes for each rank. Followed by the derived |
| // type. |
| tree EltTy = TREE_TYPE(type); |
| if (isa<ARRAY_TYPE>(type)) { |
| tree atype = type; |
| for (; isa<ARRAY_TYPE>(atype); atype = TREE_TYPE(atype)) { |
| tree Domain = TYPE_DOMAIN(atype); |
| if (Domain) { |
| // FIXME - handle dynamic ranges |
| tree MinValue = TYPE_MIN_VALUE(Domain); |
| tree MaxValue = TYPE_MAX_VALUE(Domain); |
| int64_t Low = 0; |
| int64_t Hi = 0; |
| if (isInt64(MinValue, false)) |
| Low = getInt64(MinValue, false); |
| if (isInt64(MaxValue, false)) |
| Hi = getInt64(MaxValue, false); |
| Subscripts.push_back(Builder.getOrCreateSubrange(Low, Hi)); |
| } |
| EltTy = TREE_TYPE(atype); |
| } |
| } else { |
| assert(isa<VECTOR_TYPE>(type) && "Not an array or vector type!"); |
| unsigned Length = TYPE_VECTOR_SUBPARTS(type); |
| Subscripts.push_back(Builder.getOrCreateSubrange(0, Length)); |
| } |
| |
| llvm::DIArray SubscriptArray = Builder.getOrCreateArray(Subscripts); |
| expanded_location Loc = GetNodeLocation(type); |
| return CreateCompositeType( |
| llvm::dwarf::DW_TAG_array_type, findRegion(TYPE_CONTEXT(type)), |
| StringRef(), getOrCreateFile(Loc.file), 0, NodeSizeInBits(type), |
| NodeAlignInBits(type), 0, 0, getOrCreateType(EltTy), SubscriptArray); |
| } |
| |
| /// createEnumType - Create EnumType. |
| DIType DebugInfo::createEnumType(tree type) { |
| // enum { a, b, ..., z }; |
| llvm::SmallVector<Value*, 32> Elements; |
| |
| if (TYPE_SIZE(type)) { |
| for (tree Link = TYPE_VALUES(type); Link; Link = TREE_CHAIN(Link)) { |
| tree EnumValue = TREE_VALUE(Link); |
| if (isa<CONST_DECL>(EnumValue)) |
| EnumValue = DECL_INITIAL(EnumValue); |
| uint64_t Value = getAPIntValue(EnumValue, 64).getZExtValue(); |
| const char *EnumName = IDENTIFIER_POINTER(TREE_PURPOSE(Link)); |
| Elements.push_back(Builder.createEnumerator(EnumName, Value)); |
| } |
| } |
| |
| llvm::DIArray EltArray = Builder.getOrCreateArray(Elements); |
| |
| expanded_location Loc = {}; |
| |
| if (TYPE_SIZE(type)) |
| // Incomplete enums do not have any location info. |
| Loc = GetNodeLocation(TREE_CHAIN(type), false); |
| |
| return CreateCompositeType( |
| llvm::dwarf::DW_TAG_enumeration_type, findRegion(TYPE_CONTEXT(type)), |
| GetNodeName(type), getOrCreateFile(Loc.file), Loc.line, |
| NodeSizeInBits(type), NodeAlignInBits(type), 0, 0, llvm::DIType(), |
| EltArray); |
| } |
| |
| /// createStructType - Create StructType for struct or union or class. |
| DIType DebugInfo::createStructType(tree type) { |
| |
| // struct { a; b; ... z; }; | union { a; b; ... z; }; |
| unsigned Tag = |
| isa<RECORD_TYPE>(type) ? DW_TAG_structure_type : DW_TAG_union_type; |
| |
| unsigned RunTimeLang = 0; |
| //TODO if (TYPE_LANG_SPECIFIC (type) |
| //TODO && lang_hooks.types.is_runtime_specific_type (type)) |
| //TODO { |
| //TODO unsigned CULang = TheCU.getLanguage(); |
| //TODO switch (CULang) { |
| //TODO case DW_LANG_ObjC_plus_plus : |
| //TODO RunTimeLang = DW_LANG_ObjC_plus_plus; |
| //TODO break; |
| //TODO case DW_LANG_ObjC : |
| //TODO RunTimeLang = DW_LANG_ObjC; |
| //TODO break; |
| //TODO case DW_LANG_C_plus_plus : |
| //TODO RunTimeLang = DW_LANG_C_plus_plus; |
| //TODO break; |
| //TODO default: |
| //TODO break; |
| //TODO } |
| //TODO } |
| |
| // Records and classes and unions can all be recursive. To handle them, |
| // we first generate a debug descriptor for the struct as a forward |
| // declaration. Then (if it is a definition) we go through and get debug |
| // info for all of its members. Finally, we create a descriptor for the |
| // complete type (which may refer to the forward decl if the struct is |
| // recursive) and replace all uses of the forward declaration with the |
| // final definition. |
| expanded_location Loc = GetNodeLocation(TREE_CHAIN(type), false); |
| unsigned SFlags = 0; |
| DIDescriptor TyContext = findRegion(TYPE_CONTEXT(type)); |
| |
| // Check if this type is created while creating context information |
| // descriptor. |
| { |
| std::map<tree_node *, WeakVH>::iterator I = TypeCache.find(type); |
| if (I != TypeCache.end()) |
| if (MDNode *TN = dyn_cast_or_null<MDNode>(&*I->second)) |
| return DIType(TN); |
| } |
| |
| llvm::DIType FwdDecl = Builder.createReplaceableForwardDecl( |
| Tag, GetNodeName(type), TyContext, getOrCreateFile(Loc.file), Loc.line, |
| 0, 0, 0); |
| |
| if (TYPE_SIZE(type) == 0) |
| // forward declaration, |
| return FwdDecl; |
| |
| // Insert into the TypeCache so that recursive uses will find it. |
| llvm::MDNode *FDN = FwdDecl; |
| llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FDN; |
| TypeCache[type] = WeakVH(FwdDecl); |
| |
| // Push the struct on region stack. |
| RegionStack.push_back(WeakVH(FwdDecl)); |
| RegionMap[type] = WeakVH(FwdDecl); |
| |
| // Convert all the elements. |
| llvm::SmallVector<Value*, 16> EltTys; |
| |
| if (tree binfo = TYPE_BINFO(type)) { |
| for (unsigned i = 0, e = BINFO_N_BASE_BINFOS(binfo); i != e; ++i) { |
| tree BInfo = BINFO_BASE_BINFO(binfo, i); |
| tree BInfoType = BINFO_TYPE(BInfo); |
| DIType BaseClass = getOrCreateType(BInfoType); |
| unsigned BFlags = 0; |
| if (BINFO_VIRTUAL_P(BInfo)) |
| BFlags = llvm::DIType::FlagVirtual; |
| if (BINFO_BASE_ACCESSES(binfo)) { |
| tree access = BINFO_BASE_ACCESS(binfo, i); |
| if (access == access_protected_node) |
| BFlags |= llvm::DIType::FlagProtected; |
| else if (access == access_private_node) |
| BFlags |= llvm::DIType::FlagPrivate; |
| } |
| |
| // Check for zero BINFO_OFFSET. |
| // FIXME : Is this correct ? |
| unsigned Offset = |
| BINFO_OFFSET(BInfo) ? getInt64(BINFO_OFFSET(BInfo), true) * 8 : 0; |
| |
| if (BINFO_VIRTUAL_P(BInfo)) |
| Offset = 0 - getInt64(BINFO_VPTR_FIELD(BInfo), false); |
| // FIXME : name, size, align etc... |
| DIType DTy = CreateDerivedType( |
| DW_TAG_inheritance, findRegion(type), StringRef(), llvm::DIFile(), 0, |
| 0, 0, Offset, BFlags, BaseClass); |
| EltTys.push_back(DTy); |
| } |
| } |
| |
| // Now add members of this class. |
| for (tree Member = TYPE_FIELDS(type); Member; Member = TREE_CHAIN(Member)) { |
| // Should we skip. |
| if (DECL_P(Member) && DECL_IGNORED_P(Member)) |
| continue; |
| |
| // Get the location of the member. |
| expanded_location MemLoc = GetNodeLocation(Member, false); |
| |
| if (!isa<FIELD_DECL>(Member)) |
| // otherwise is a static variable, whose debug info is emitted |
| // when through EmitGlobalVariable(). |
| continue; |
| |
| if (!OffsetIsLLVMCompatible(Member)) |
| // FIXME: field with variable or humongous offset. |
| // Skip it for now. |
| continue; |
| |
| /* Ignore nameless fields. */ |
| if (DECL_NAME(Member) == NULL_TREE && |
| !isa<RECORD_OR_UNION_TYPE>(TREE_TYPE(Member))) |
| continue; |
| |
| // Field type is the declared type of the field. |
| tree FieldNodeType = FieldType(Member); |
| DIType MemberType = getOrCreateType(FieldNodeType); |
| StringRef MemberName = GetNodeName(Member); |
| unsigned MFlags = 0; |
| if (TREE_PROTECTED(Member)) |
| MFlags = llvm::DIType::FlagProtected; |
| else if (TREE_PRIVATE(Member)) |
| MFlags = llvm::DIType::FlagPrivate; |
| |
| DIType DTy = CreateDerivedType( |
| DW_TAG_member, findRegion(DECL_CONTEXT(Member)), MemberName, |
| getOrCreateFile(MemLoc.file), MemLoc.line, NodeSizeInBits(Member), |
| NodeAlignInBits(FieldNodeType), int_bit_position(Member), MFlags, |
| MemberType); |
| EltTys.push_back(DTy); |
| } |
| |
| for (tree Member = TYPE_METHODS(type); Member; Member = TREE_CHAIN(Member)) { |
| |
| if (DECL_ABSTRACT_ORIGIN(Member)) |
| continue; |
| // Ignore unused aritificial members. |
| if (DECL_ARTIFICIAL(Member) && !TREE_USED(Member)) |
| continue; |
| // In C++, TEMPLATE_DECLs are marked Ignored, and should be. |
| if (DECL_P(Member) && DECL_IGNORED_P(Member)) |
| continue; |
| |
| std::map<tree_node *, WeakVH>::iterator I = SPCache.find(Member); |
| if (I != SPCache.end()) |
| EltTys.push_back(DISubprogram(cast<MDNode>(I->second))); |
| else { |
| // Get the location of the member. |
| expanded_location MemLoc = GetNodeLocation(Member, false); |
| StringRef MemberName = getFunctionName(Member); |
| StringRef LinkageName = getLinkageName(Member); |
| DIType SPTy = getOrCreateType(TREE_TYPE(Member)); |
| unsigned Virtuality = 0; |
| unsigned VIndex = 0; |
| DIType ContainingType; |
| if (DECL_VINDEX(Member)) { |
| if (host_integerp(DECL_VINDEX(Member), 0)) |
| VIndex = tree_low_cst(DECL_VINDEX(Member), 0); |
| Virtuality = dwarf::DW_VIRTUALITY_virtual; |
| ContainingType = getOrCreateType(DECL_CONTEXT(Member)); |
| } |
| DISubprogram SP = CreateSubprogram( |
| findRegion(DECL_CONTEXT(Member)), MemberName, MemberName, LinkageName, |
| getOrCreateFile(MemLoc.file), MemLoc.line, SPTy, false, false, |
| Virtuality, VIndex, ContainingType, DECL_ARTIFICIAL(Member), |
| optimize); |
| EltTys.push_back(SP); |
| SPCache[Member] = WeakVH(SP); |
| } |
| } |
| |
| llvm::DIArray Elements = Builder.getOrCreateArray(EltTys); |
| |
| RegionStack.pop_back(); |
| std::map<tree_node *, WeakVH>::iterator RI = RegionMap.find(type); |
| if (RI != RegionMap.end()) |
| RegionMap.erase(RI); |
| |
| llvm::DIType ContainingType; |
| if (TYPE_VFIELD(type)) { |
| tree vtype = DECL_FCONTEXT(TYPE_VFIELD(type)); |
| ContainingType = getOrCreateType(vtype); |
| } |
| llvm::DICompositeType RealDecl = CreateCompositeType( |
| Tag, findRegion(TYPE_CONTEXT(type)), GetNodeName(type), |
| getOrCreateFile(Loc.file), Loc.line, NodeSizeInBits(type), |
| NodeAlignInBits(type), 0, SFlags, llvm::DIType(), Elements, RunTimeLang, |
| ContainingType); |
| RegionMap[type] = WeakVH(RealDecl); |
| |
| // Now that we have a real decl for the struct, replace anything using the |
| // old decl with the new one. This will recursively update the debug info. |
| llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl); |
| |
| return RealDecl; |
| } |
| |
| /// createVariantType - Create variant type or return MainTy. |
| DIType DebugInfo::createVariantType(tree type, DIType MainTy) { |
| |
| DIType Ty; |
| if (tree TyDef = TYPE_NAME(type)) { |
| std::map<tree_node *, WeakVH>::iterator I = TypeCache.find(TyDef); |
| if (I != TypeCache.end()) |
| if (I->second) |
| return DIType(cast<MDNode>(I->second)); |
| if (isa<TYPE_DECL>(TyDef) && DECL_ORIGINAL_TYPE(TyDef)) { |
| expanded_location TypeDefLoc = GetNodeLocation(TyDef); |
| Ty = CreateDerivedType( |
| DW_TAG_typedef, findRegion(DECL_CONTEXT(TyDef)), GetNodeName(TyDef), |
| getOrCreateFile(TypeDefLoc.file), TypeDefLoc.line, 0 /*size*/, |
| 0 /*align*/, 0 /*offset */, 0 /*flags*/, MainTy); |
| TypeCache[TyDef] = WeakVH(Ty); |
| return Ty; |
| } |
| } |
| |
| if (TYPE_VOLATILE(type)) { |
| Ty = CreateDerivedType( |
| DW_TAG_volatile_type, findRegion(TYPE_CONTEXT(type)), StringRef(), |
| getOrCreateFile(main_input_filename), 0 /*line no*/, |
| NodeSizeInBits(type), NodeAlignInBits(type), 0 /*offset */, |
| 0 /* flags */, MainTy); |
| MainTy = Ty; |
| } |
| |
| if (TYPE_READONLY(type)) |
| Ty = CreateDerivedType( |
| DW_TAG_const_type, findRegion(TYPE_CONTEXT(type)), StringRef(), |
| getOrCreateFile(main_input_filename), 0 /*line no*/, |
| NodeSizeInBits(type), NodeAlignInBits(type), 0 /*offset */, |
| 0 /* flags */, MainTy); |
| |
| if (TYPE_VOLATILE(type) || TYPE_READONLY(type)) { |
| TypeCache[type] = WeakVH(Ty); |
| return Ty; |
| } |
| |
| // If, for some reason, main type variant type is seen then use it. |
| return MainTy; |
| } |
| |
| /// getOrCreateType - Get the type from the cache or create a new type if |
| /// necessary. |
| DIType DebugInfo::getOrCreateType(tree type) { |
| if (type == NULL_TREE || type == error_mark_node) |
| llvm_unreachable("Not a type."); |
| |
| // Should only be void if a pointer/reference/return type. Returning NULL |
| // allows the caller to produce a non-derived type. |
| if (isa<VOID_TYPE>(type)) |
| return DIType(); |
| |
| // Check to see if the compile unit already has created this type. |
| std::map<tree_node *, WeakVH>::iterator I = TypeCache.find(type); |
| if (I != TypeCache.end()) |
| if (I->second) |
| return DIType(cast<MDNode>(I->second)); |
| |
| if (type != TYPE_MAIN_VARIANT(type) && TYPE_MAIN_VARIANT(type)) { |
| DIType MainTy = getOrCreateType(TYPE_MAIN_VARIANT(type)); |
| DIType Ty = createVariantType(type, MainTy); |
| if (Ty.isValid()) |
| return Ty; |
| } |
| |
| // Work out details of type. |
| DIType Ty; |
| switch (TREE_CODE(type)) { |
| case ERROR_MARK: |
| case TRANSLATION_UNIT_DECL: |
| default: |
| llvm_unreachable("Unsupported type"); |
| |
| #if (GCC_MINOR > 5) |
| case NULLPTR_TYPE: |
| #endif |
| case LANG_TYPE: { |
| tree name = TYPE_NAME(type); |
| if (TREE_CODE(name) == TYPE_DECL) |
| name = DECL_NAME(name); |
| return Builder.createUnspecifiedType(IDENTIFIER_POINTER(name)); |
| } |
| |
| case OFFSET_TYPE: |
| case POINTER_TYPE: |
| case REFERENCE_TYPE: |
| // Do not cache pointer type. The pointer may point to forward declared |
| // struct. |
| return createPointerType(type); |
| |
| case FUNCTION_TYPE: |
| case METHOD_TYPE: |
| Ty = createMethodType(type); |
| break; |
| |
| case VECTOR_TYPE: |
| case ARRAY_TYPE: |
| Ty = createArrayType(type); |
| break; |
| |
| case ENUMERAL_TYPE: |
| Ty = createEnumType(type); |
| break; |
| |
| case RECORD_TYPE: |
| case QUAL_UNION_TYPE: |
| case UNION_TYPE: |
| return createStructType(type); |
| |
| case INTEGER_TYPE: |
| case REAL_TYPE: |
| case COMPLEX_TYPE: |
| case BOOLEAN_TYPE: |
| Ty = createBasicType(type); |
| break; |
| } |
| TypeCache[type] = WeakVH(Ty); |
| return Ty; |
| } |
| |
| /// Initialize - Initialize debug info by creating compile unit for |
| /// main_input_filename. This must be invoked after language dependent |
| /// initialization is done. |
| void DebugInfo::Initialize() { |
| |
| // Debug info metadata without a version or with an outdated version will be |
| // dropped. Add a version here to avoid that. |
| M.addModuleFlag(llvm::Module::Error, "Debug Info Version", |
| llvm::DEBUG_METADATA_VERSION); |
| // Each input file is encoded as a separate compile unit in LLVM |
| // debugging information output. However, many target specific tool chains |
| // prefer to encode only one compile unit in an object file. In this |
| // situation, the LLVM code generator will include debugging information |
| // entities in the compile unit that is marked as main compile unit. The |
| // code generator accepts maximum one main compile unit per module. If a |
| // module does not contain any main compile unit then the code generator |
| // will emit multiple compile units in the output object file. |
| getOrCreateCompileUnit(main_input_filename, true); |
| } |
| |
| /// getOrCreateCompileUnit - Get the compile unit from the cache or |
| /// create a new one if necessary. |
| void DebugInfo::getOrCreateCompileUnit(const char *FullPath, bool isMain) { |
| if (!FullPath) |
| FullPath = main_input_filename; |
| if (!strcmp(FullPath, "")) |
| FullPath = "<stdin>"; |
| |
| // Get source file information. |
| std::string Directory; |
| std::string FileName; |
| DirectoryAndFile(FullPath, Directory, FileName); |
| |
| // Set up Language number. |
| unsigned LangTag; |
| const std::string LanguageName(lang_hooks.name); |
| if (LanguageName == "GNU C") |
| LangTag = DW_LANG_C89; |
| else if (LanguageName == "GNU C++") |
| LangTag = DW_LANG_C_plus_plus; |
| else if (LanguageName == "GNU Ada") |
| LangTag = DW_LANG_Ada95; |
| else if (LanguageName == "GNU F77") |
| LangTag = DW_LANG_Fortran77; |
| else if (LanguageName == "GNU Pascal") |
| LangTag = DW_LANG_Pascal83; |
| else if (LanguageName == "GNU Java") |
| LangTag = DW_LANG_Java; |
| else if (LanguageName == "GNU Objective-C") |
| LangTag = DW_LANG_ObjC; |
| else if (LanguageName == "GNU Objective-C++") |
| LangTag = DW_LANG_ObjC_plus_plus; |
| else |
| LangTag = DW_LANG_C89; |
| |
| StringRef Flags; |
| |
| // flag_objc_abi represents Objective-C runtime version number. It is zero |
| // for all other language. |
| unsigned ObjcRunTimeVer = 0; |
| // if (flag_objc_abi != 0 && flag_objc_abi != -1) |
| // ObjcRunTimeVer = flag_objc_abi; |
| Builder.createCompileUnit(LangTag, FileName, Directory, version_string, |
| optimize, Flags, ObjcRunTimeVer); |
| } |
| |
| /// getOrCreateFile - Get DIFile descriptor. |
| DIFile DebugInfo::getOrCreateFile(const char *FullPath) { |
| if (!FullPath) |
| FullPath = main_input_filename; |
| if (!strcmp(FullPath, "")) |
| FullPath = "<stdin>"; |
| |
| // Get source file information. |
| std::string Directory; |
| std::string FileName; |
| DirectoryAndFile(FullPath, Directory, FileName); |
| return Builder.createFile(FileName, Directory); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| // Primary Constructors |
| //===----------------------------------------------------------------------===// |
| |
| /// CreateDerivedType - Create a derived type like const qualified type, |
| /// pointer, typedef, etc. |
| DIDerivedType DebugInfo::CreateDerivedType( |
| unsigned Tag, DIDescriptor Context, StringRef Name, DIFile F, |
| unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, |
| uint64_t OffsetInBits, unsigned Flags, DIType DerivedFrom) { |
| switch (Tag) { |
| case dwarf::DW_TAG_typedef: |
| return Builder.createTypedef(DerivedFrom, Name, F, LineNumber, Context); |
| case dwarf::DW_TAG_pointer_type: |
| return Builder.createPointerType(DerivedFrom, SizeInBits, AlignInBits, |
| Name); |
| case dwarf::DW_TAG_reference_type: |
| case dwarf::DW_TAG_rvalue_reference_type: |
| return Builder.createReferenceType(Tag, DerivedFrom); |
| case dwarf::DW_TAG_const_type: |
| case dwarf::DW_TAG_volatile_type: |
| case dwarf::DW_TAG_restrict_type: |
| return Builder.createQualifiedType(Tag, DerivedFrom); |
| case dwarf::DW_TAG_member: |
| return Builder.createMemberType(Context, Name, F, LineNumber, SizeInBits, |
| AlignInBits, OffsetInBits, Flags, |
| DerivedFrom); |
| case dwarf::DW_TAG_inheritance: |
| return Builder.createInheritance(DIType(Context), DerivedFrom, OffsetInBits, |
| Flags); |
| case dwarf::DW_TAG_friend: |
| case dwarf::DW_TAG_ptr_to_member_type: |
| break; |
| } |
| llvm_unreachable("Unimplemented derived type tag"); |
| } |
| |
| /// CreateCompositeType - Create a composite type like array, struct, etc. |
| DICompositeType DebugInfo::CreateCompositeType( |
| unsigned Tag, DIDescriptor Context, StringRef Name, DIFile F, |
| unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, |
| uint64_t OffsetInBits, unsigned Flags, DIType DerivedFrom, DIArray Elements, |
| unsigned RuntimeLang, MDNode *ContainingType) { |
| switch (Tag) { |
| case dwarf::DW_TAG_array_type: |
| return Builder.createArrayType(SizeInBits, AlignInBits, DerivedFrom, |
| Elements); |
| case dwarf::DW_TAG_structure_type: |
| return Builder.createStructType(Context, Name, F, LineNumber, SizeInBits, |
| AlignInBits, Flags, DerivedFrom, Elements, |
| 0, DIType(ContainingType)); |
| case dwarf::DW_TAG_union_type: |
| return Builder.createUnionType(Context, Name, F, LineNumber, SizeInBits, |
| AlignInBits, Flags, Elements, RuntimeLang); |
| case dwarf::DW_TAG_enumeration_type: |
| return Builder.createEnumerationType(Context, Name, F, LineNumber, |
| SizeInBits, AlignInBits, Elements, |
| DerivedFrom); |
| case dwarf::DW_TAG_subroutine_type: |
| return Builder.createSubroutineType(F, Elements); |
| case dwarf::DW_TAG_class_type: |
| break; |
| } |
| llvm_unreachable("Unimplemented composite type tag"); |
| } |
| |
| /// CreateSubprogram - Create a new descriptor for the specified subprogram. |
| /// See comments in DISubprogram for descriptions of these fields. This |
| /// method does not unique the generated descriptors. |
| DISubprogram DebugInfo::CreateSubprogram( |
| DIDescriptor Context, StringRef Name, StringRef DisplayName, |
| StringRef LinkageName, DIFile F, unsigned LineNo, DIType Ty, |
| bool isLocalToUnit, bool isDefinition, unsigned VK, unsigned VIndex, |
| DIType ContainingType, unsigned Flags, bool isOptimized, Function *Fn) { |
| DICompositeType CTy = getDICompositeType(Ty); |
| assert(CTy.Verify() && "Expected a composite type!"); |
| if (ContainingType.isValid() || VK || VIndex) |
| return Builder.createMethod(Context, Name, LinkageName, F, LineNo, CTy, |
| isLocalToUnit, isDefinition, VK, VIndex, |
| DIType(), |
| Flags, isOptimized, Fn, NULL); |
| return Builder.createFunction(Context, Name, LinkageName, F, LineNo, CTy, |
| isLocalToUnit, isDefinition, LineNo, Flags, |
| isOptimized, Fn, NULL, NULL); |
| } |
| |
| /// CreateSubprogramDefinition - Create new subprogram descriptor for the |
| /// given declaration. |
| DISubprogram DebugInfo::CreateSubprogramDefinition( |
| DISubprogram &SP, unsigned LineNo, Function *Fn) { |
| if (SP.isDefinition()) |
| return DISubprogram(SP); |
| |
| DIFile File = Builder.createFile(SP.getFilename(), SP.getDirectory()); |
| return Builder.createFunction( |
| SP.getContext(), SP.getName(), SP.getLinkageName(), File, |
| SP.getLineNumber(), SP.getType(), SP.isLocalToUnit(), true, LineNo, |
| SP.getFlags(), SP.isOptimized(), Fn, SP.getTemplateParams(), SP); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Routines for inserting code into a function |
| //===----------------------------------------------------------------------===// |
| |
| /// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call. |
| Instruction *DebugInfo::InsertDeclare(Value *Storage, DIVariable D, |
| Instruction *InsertBefore) { |
| assert(Storage && "no storage passed to dbg.declare"); |
| assert(D.Verify() && "empty DIVariable passed to dbg.declare"); |
| if (!DeclareFn) |
| DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare); |
| |
| Value *Args[] = { MDNode::get(Storage->getContext(), Storage), D }; |
| return CallInst::Create(DeclareFn, Args, "", InsertBefore); |
| } |
| |
| /// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call. |
| Instruction *DebugInfo::InsertDeclare(Value *Storage, DIVariable D, |
| BasicBlock *InsertAtEnd) { |
| assert(Storage && "no storage passed to dbg.declare"); |
| assert(D.Verify() && "invalid DIVariable passed to dbg.declare"); |
| if (!DeclareFn) |
| DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare); |
| |
| Value *Args[] = { MDNode::get(Storage->getContext(), Storage), D }; |
| |
| // If this block already has a terminator then insert this intrinsic |
| // before the terminator. |
| if (TerminatorInst *T = InsertAtEnd->getTerminator()) |
| return CallInst::Create(DeclareFn, Args, "", T); |
| else |
| return CallInst::Create(DeclareFn, Args, "", InsertAtEnd); |
| } |
| |
| /// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call. |
| Instruction *DebugInfo::InsertDbgValueIntrinsic( |
| Value *V, uint64_t Offset, DIVariable D, Instruction *InsertBefore) { |
| assert(V && "no value passed to dbg.value"); |
| assert(D.Verify() && "invalid DIVariable passed to dbg.value"); |
| if (!ValueFn) |
| ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value); |
| |
| Value *Args[] = { MDNode::get(V->getContext(), V), |
| ConstantInt::get(Type::getInt64Ty(V->getContext()), Offset), |
| D }; |
| return CallInst::Create(ValueFn, Args, "", InsertBefore); |
| } |
| |
| /// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call. |
| Instruction *DebugInfo::InsertDbgValueIntrinsic( |
| Value *V, uint64_t Offset, DIVariable D, BasicBlock *InsertAtEnd) { |
| assert(V && "no value passed to dbg.value"); |
| assert(D.Verify() && "invalid DIVariable passed to dbg.value"); |
| if (!ValueFn) |
| ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value); |
| |
| Value *Args[] = { MDNode::get(V->getContext(), V), |
| ConstantInt::get(Type::getInt64Ty(V->getContext()), Offset), |
| D }; |
| return CallInst::Create(ValueFn, Args, "", InsertAtEnd); |
| } |