Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -213,16 +213,18 @@ /// Create debugging information entry for a /// C++ static data member. - /// \param Scope Member scope. - /// \param Name Member name. - /// \param File File where this member is declared. - /// \param LineNo Line number. - /// \param Ty Type of the static member. - /// \param Flags Flags to encode member attribute, e.g. private. - /// \param Val Const initializer of the member. + /// \param Scope Member scope. + /// \param Name Member name. + /// \param File File where this member is declared. + /// \param LineNo Line number. + /// \param Ty Type of the static member. + /// \param AlignInBits Member alignment. + /// \param Flags Flags to encode member attribute, e.g. private. + /// \param Val Const initializer of the member. DIDerivedType *createStaticMemberType(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, - DIType *Ty, DINode::DIFlags Flags, + DIType *Ty, uint64_t AlignInBits, + DINode::DIFlags Flags, llvm::Constant *Val); /// Create debugging information entry for Objective-C @@ -378,13 +380,16 @@ /// \param LineNumber Line number. /// \param SizeInBits Member size. /// \param AlignInBits Member alignment. + /// \param Flags Debug Info flags. /// \param Elements Enumeration elements. /// \param UnderlyingType Underlying type of a C++11/ObjC fixed enum. /// \param UniqueIdentifier A unique identifier for the enum. - DICompositeType *createEnumerationType( - DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, - uint64_t SizeInBits, uint64_t AlignInBits, DINodeArray Elements, - DIType *UnderlyingType, StringRef UniqueIdentifier = ""); + DICompositeType * + createEnumerationType(DIScope *Scope, StringRef Name, DIFile *File, + unsigned LineNumber, uint64_t SizeInBits, + uint64_t AlignInBits, DINode::DIFlags Flags, + DINodeArray Elements, DIType *UnderlyingType, + StringRef UniqueIdentifier = ""); /// Create subroutine type. /// \param ParameterTypes An array of subroutine parameter types. This @@ -454,21 +459,22 @@ /// \param Ty Variable Type. /// \param isLocalToUnit Boolean flag indicate whether this variable is /// externally visible or not. + /// \param AlignInBits Variable alignment(or 0 if no alignment attr was + /// specified) + /// \param Flags Debug Info flags /// \param Val llvm::Value of the variable. /// \param Decl Reference to the corresponding declaration. - DIGlobalVariable *createGlobalVariable(DIScope *Context, StringRef Name, - StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, - bool isLocalToUnit, - llvm::Constant *Val, - MDNode *Decl = nullptr); + DIGlobalVariable *createGlobalVariable( + DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, + unsigned LineNo, DIType *Ty, bool isLocalToUnit, uint64_t AlignInBits, + DINode::DIFlags Flags, llvm::Constant *Val, MDNode *Decl = nullptr); /// Identical to createGlobalVariable /// except that the resulting DbgNode is temporary and meant to be RAUWed. DIGlobalVariable *createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, bool isLocalToUnit, llvm::Constant *Val, - MDNode *Decl = nullptr); + unsigned LineNo, DIType *Ty, bool isLocalToUnit, uint64_t AlignInBits, + DINode::DIFlags Flags, llvm::Constant *Val, MDNode *Decl = nullptr); /// Create a new descriptor for an auto variable. This is a local variable /// that is not a subprogram parameter. @@ -481,6 +487,7 @@ DILocalVariable * createAutoVariable(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve = false, + uint64_t AlignInBits = 0, DINode::DIFlags Flags = DINode::FlagZero); /// Create a new descriptor for a parameter variable. Index: include/llvm/IR/DebugInfoFlags.def =================================================================== --- include/llvm/IR/DebugInfoFlags.def +++ include/llvm/IR/DebugInfoFlags.def @@ -41,11 +41,12 @@ HANDLE_DI_FLAG((1 << 18), IntroducedVirtual) HANDLE_DI_FLAG((1 << 19), BitField) HANDLE_DI_FLAG((1 << 20), NoReturn) +HANDLE_DI_FLAG((1 << 21), Alignment) #ifdef DI_FLAG_LARGEST_NEEDED // intended to be used with ADT/BitmaskEnum.h // NOTE: always must be equal to largest flag, check this when adding new flag -HANDLE_DI_FLAG((1 << 20), Largest) +HANDLE_DI_FLAG((1 << 21), Largest) #undef DI_FLAG_LARGEST_NEEDED #endif Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -550,6 +550,7 @@ unsigned getLine() const { return Line; } uint64_t getSizeInBits() const { return SizeInBits; } uint64_t getAlignInBits() const { return AlignInBits; } + uint64_t getAlignInChars() const { return AlignInBits / CHAR_BIT; } uint64_t getOffsetInBits() const { return OffsetInBits; } DIFlags getFlags() const { return Flags; } @@ -1826,19 +1827,28 @@ /// \brief Base class for variables. class DIVariable : public DINode { unsigned Line; + uint64_t AlignInBits; + DIFlags Flags; protected: DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Line, - ArrayRef Ops) - : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line) {} + ArrayRef Ops, uint64_t AlignInBits = 0, + DIFlags Flags = DINode::FlagZero) + : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line), + AlignInBits(AlignInBits), Flags(Flags) {} ~DIVariable() = default; - public: unsigned getLine() const { return Line; } DIScope *getScope() const { return cast_or_null(getRawScope()); } StringRef getName() const { return getStringOperand(1); } DIFile *getFile() const { return cast_or_null(getRawFile()); } DITypeRef getType() const { return DITypeRef(getRawType()); } + uint64_t getAlignInBits() const { return AlignInBits; } + uint64_t getAlignInChars() const { return AlignInBits / CHAR_BIT; } + DIFlags getFlags() const { return Flags; } + + bool isArtificial() const { return getFlags() & FlagArtificial; } + bool isObjectPointer() const { return getFlags() & FlagObjectPointer; } StringRef getFilename() const { if (auto *F = getFile()) @@ -1873,53 +1883,59 @@ bool IsDefinition; DIGlobalVariable(LLVMContext &C, StorageType Storage, unsigned Line, - bool IsLocalToUnit, bool IsDefinition, - ArrayRef Ops) - : DIVariable(C, DIGlobalVariableKind, Storage, Line, Ops), + bool IsLocalToUnit, bool IsDefinition, uint64_t Align, + DIFlags Flags, ArrayRef Ops) + : DIVariable(C, DIGlobalVariableKind, Storage, Line, Ops, Align, Flags), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition) {} ~DIGlobalVariable() = default; static DIGlobalVariable * getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, - bool IsLocalToUnit, bool IsDefinition, Constant *Variable, + bool IsLocalToUnit, bool IsDefinition, uint64_t Align, + DINode::DIFlags Flags, Constant *Variable, DIDerivedType *StaticDataMemberDeclaration, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, - IsLocalToUnit, IsDefinition, + IsLocalToUnit, IsDefinition, Align, Flags, Variable ? ConstantAsMetadata::get(Variable) : nullptr, StaticDataMemberDeclaration, Storage, ShouldCreate); } static DIGlobalVariable * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, + bool IsLocalToUnit, bool IsDefinition, uint64_t Align, + DINode::DIFlags Flags, Metadata *Variable, Metadata *StaticDataMemberDeclaration, StorageType Storage, bool ShouldCreate = true); TempDIGlobalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getLinkageName(), getFile(), getLine(), getType(), isLocalToUnit(), - isDefinition(), getVariable(), - getStaticDataMemberDeclaration()); + isDefinition(), getAlignInBits(), getFlags(), + getVariable(), getStaticDataMemberDeclaration()); } public: DEFINE_MDNODE_GET(DIGlobalVariable, (DIScope * Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, - bool IsLocalToUnit, bool IsDefinition, Constant *Variable, + bool IsLocalToUnit, bool IsDefinition, uint64_t Align, + DINode::DIFlags Flags, Constant *Variable, DIDerivedType *StaticDataMemberDeclaration), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Variable, StaticDataMemberDeclaration)) + IsDefinition, Align, Flags, Variable, + StaticDataMemberDeclaration)) DEFINE_MDNODE_GET(DIGlobalVariable, (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, + bool IsLocalToUnit, bool IsDefinition, uint64_t Align, + DINode::DIFlags Flags, Metadata *Variable, Metadata *StaticDataMemberDeclaration), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Variable, StaticDataMemberDeclaration)) + IsDefinition, Align, Flags, Variable, + StaticDataMemberDeclaration)) TempDIGlobalVariable clone() const { return cloneImpl(); } @@ -1953,46 +1969,47 @@ friend class MDNode; unsigned Arg : 16; - DIFlags Flags; DILocalVariable(LLVMContext &C, StorageType Storage, unsigned Line, - unsigned Arg, DIFlags Flags, ArrayRef Ops) - : DIVariable(C, DILocalVariableKind, Storage, Line, Ops), Arg(Arg), - Flags(Flags) { + unsigned Arg, uint64_t Align, DIFlags Flags, + ArrayRef Ops) + : DIVariable(C, DILocalVariableKind, Storage, Line, Ops, Align, Flags), + Arg(Arg) { assert(Arg < (1 << 16) && "DILocalVariable: Arg out of range"); } ~DILocalVariable() = default; static DILocalVariable *getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, DIFile *File, unsigned Line, - DITypeRef Type, unsigned Arg, DIFlags Flags, - StorageType Storage, + DITypeRef Type, unsigned Arg, uint64_t Align, + DIFlags Flags, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File, - Line, Type, Arg, Flags, Storage, ShouldCreate); + Line, Type, Arg, Align, Flags, Storage, ShouldCreate); } static DILocalVariable *getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, - Metadata *Type, unsigned Arg, DIFlags Flags, - StorageType Storage, + Metadata *Type, unsigned Arg, uint64_t Align, + DIFlags Flags, StorageType Storage, bool ShouldCreate = true); TempDILocalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getFile(), - getLine(), getType(), getArg(), getFlags()); + getLine(), getType(), getArg(), getAlignInBits(), + getFlags()); } public: DEFINE_MDNODE_GET(DILocalVariable, (DILocalScope * Scope, StringRef Name, DIFile *File, unsigned Line, DITypeRef Type, unsigned Arg, - DIFlags Flags), - (Scope, Name, File, Line, Type, Arg, Flags)) + uint64_t Align, DIFlags Flags), + (Scope, Name, File, Line, Type, Arg, Align, Flags)) DEFINE_MDNODE_GET(DILocalVariable, (Metadata * Scope, MDString *Name, Metadata *File, unsigned Line, Metadata *Type, unsigned Arg, - DIFlags Flags), - (Scope, Name, File, Line, Type, Arg, Flags)) + uint64_t Align, DIFlags Flags), + (Scope, Name, File, Line, Type, Arg, Align, Flags)) TempDILocalVariable clone() const { return cloneImpl(); } @@ -2005,10 +2022,6 @@ bool isParameter() const { return Arg; } unsigned getArg() const { return Arg; } - DIFlags getFlags() const { return Flags; } - - bool isArtificial() const { return getFlags() & FlagArtificial; } - bool isObjectPointer() const { return getFlags() & FlagObjectPointer; } /// \brief Check that a location is valid for this variable. /// Index: include/llvm/Support/Dwarf.h =================================================================== --- include/llvm/Support/Dwarf.h +++ include/llvm/Support/Dwarf.h @@ -198,6 +198,7 @@ DW_AT_rvalue_reference = 0x78, DW_AT_macros = 0x79, DW_AT_noreturn = 0x87, + DW_AT_alignment = 0x88, DW_AT_lo_user = 0x2000, DW_AT_hi_user = 0x3fff, Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -4201,15 +4201,18 @@ OPTIONAL(type, MDField, ); \ OPTIONAL(isLocal, MDBoolField, ); \ OPTIONAL(isDefinition, MDBoolField, (true)); \ + OPTIONAL(align, MDUnsignedField, (0, UINT64_MAX)); \ + OPTIONAL(flags, DIFlagField, ); \ OPTIONAL(variable, MDConstant, ); \ OPTIONAL(declaration, MDField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DIGlobalVariable, - (Context, scope.Val, name.Val, linkageName.Val, - file.Val, line.Val, type.Val, isLocal.Val, - isDefinition.Val, variable.Val, declaration.Val)); + Result = + GET_OR_DISTINCT(DIGlobalVariable, + (Context, scope.Val, name.Val, linkageName.Val, file.Val, + line.Val, type.Val, isLocal.Val, isDefinition.Val, + align.Val, flags.Val, variable.Val, declaration.Val)); return false; } @@ -4226,13 +4229,14 @@ OPTIONAL(file, MDField, ); \ OPTIONAL(line, LineField, ); \ OPTIONAL(type, MDField, ); \ + OPTIONAL(align, MDUnsignedField, (0, UINT64_MAX)); \ OPTIONAL(flags, DIFlagField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS Result = GET_OR_DISTINCT(DILocalVariable, (Context, scope.Val, name.Val, file.Val, line.Val, - type.Val, arg.Val, flags.Val)); + type.Val, arg.Val, align.Val, flags.Val)); return false; } Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -2675,17 +2675,31 @@ break; } case bitc::METADATA_GLOBAL_VAR: { - if (Record.size() != 11) + if (Record.size() != 11 && Record.size() != 13) return error("Invalid record"); IsDistinct = Record[0]; + uint64_t AlignInBits = 0; + DINode::DIFlags Flags = DINode::FlagZero; + Metadata *Variable = nullptr; + Metadata *StaticDataMemberDeclaration = nullptr; + if (Record.size() == 13) { + AlignInBits = Record[9]; + Flags = static_cast(Record[10]); + Variable = getMDOrNull(Record[11]); + StaticDataMemberDeclaration = getMDOrNull(Record[12]); + } else { + Variable = getMDOrNull(Record[9]); + StaticDataMemberDeclaration = getMDOrNull(Record[10]); + } + MetadataList.assignValue( - GET_OR_DISTINCT(DIGlobalVariable, - (Context, getMDOrNull(Record[1]), - getMDString(Record[2]), getMDString(Record[3]), - getMDOrNull(Record[4]), Record[5], - getDITypeRefOrNull(Record[6]), Record[7], Record[8], - getMDOrNull(Record[9]), getMDOrNull(Record[10]))), + GET_OR_DISTINCT( + DIGlobalVariable, + (Context, getMDOrNull(Record[1]), getMDString(Record[2]), + getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], + getDITypeRefOrNull(Record[6]), Record[7], Record[8], AlignInBits, + Flags, Variable, StaticDataMemberDeclaration)), NextMetadataNo++); break; } @@ -2697,15 +2711,25 @@ // 2nd field used to be an artificial tag, either DW_TAG_auto_variable or // DW_TAG_arg_variable. IsDistinct = Record[0]; - bool HasTag = Record.size() > 8; - DINode::DIFlags Flags = static_cast(Record[7 + HasTag]); + bool HasTag = false; + uint64_t AlignInBits = 0; + DINode::DIFlags Flags = DINode::FlagZero; + if (Record.size() == 10 && Record[9] == UINT64_MAX) { + // We are using "new" format w/o obsolete fields + AlignInBits = Record[7]; + Flags = static_cast(Record[8]); + } else { + // "old" format: no align field, we should process "artificial tag" + HasTag = Record.size() > 8; + Flags = static_cast(Record[7 + HasTag]); + } MetadataList.assignValue( GET_OR_DISTINCT(DILocalVariable, (Context, getMDOrNull(Record[1 + HasTag]), getMDString(Record[2 + HasTag]), getMDOrNull(Record[3 + HasTag]), Record[4 + HasTag], getDITypeRefOrNull(Record[5 + HasTag]), - Record[6 + HasTag], Flags)), + Record[6 + HasTag], AlignInBits, Flags)), NextMetadataNo++); break; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1710,6 +1710,8 @@ Record.push_back(VE.getMetadataOrNullID(N->getType())); Record.push_back(N->isLocalToUnit()); Record.push_back(N->isDefinition()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getFlags()); Record.push_back(VE.getMetadataOrNullID(N->getRawVariable())); Record.push_back(VE.getMetadataOrNullID(N->getStaticDataMemberDeclaration())); @@ -1727,7 +1729,12 @@ Record.push_back(N->getLine()); Record.push_back(VE.getMetadataOrNullID(N->getType())); Record.push_back(N->getArg()); + Record.push_back(N->getAlignInBits()); Record.push_back(N->getFlags()); + // indicate that we are using "new" format without obsolete fields: + // Record[1] == DW_TAG_auto_variable/DW_TAG_arg_variable + // Record[9] == inlinedAt + Record.push_back(UINT64_MAX); Stream.EmitRecord(bitc::METADATA_LOCAL_VAR, Record, Abbrev); Record.clear(); Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -145,6 +145,11 @@ else addGlobalName(GV->getName(), *VariableDIE, DeclContext); + if (GV->getFlags() & DINode::FlagAlignment) { + addUInt(*VariableDIE, dwarf::DW_AT_alignment, dwarf::DW_FORM_data8, + GV->getAlignInChars()); + } + // Add location. bool addToAccelTable = false; if (auto *Global = dyn_cast_or_null(GV->getVariable())) { @@ -802,6 +807,12 @@ StringRef Name = Var.getName(); if (!Name.empty()) addString(VariableDie, dwarf::DW_AT_name, Name); + const auto *DIVar = Var.getVariable(); + const auto Flags = DIVar->getFlags(); + if (Flags & DINode::FlagAlignment) { + addUInt(VariableDie, dwarf::DW_AT_alignment, dwarf::DW_FORM_data8, + DIVar->getAlignInChars()); + } addSourceLine(VariableDie, Var.getVariable()); addType(VariableDie, Var.getType()); if (Var.isArtificial()) Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1007,6 +1007,12 @@ if (RLang) addUInt(Buffer, dwarf::DW_AT_APPLE_runtime_class, dwarf::DW_FORM_data1, RLang); + + // Add align info if available. + if (CTy->getFlags() & DINode::FlagAlignment) + if (uint64_t AlignInBytes = CTy->getAlignInChars()) + addUInt(Buffer, dwarf::DW_AT_alignment, dwarf::DW_FORM_data8, + AlignInBytes); } } @@ -1394,6 +1400,7 @@ } else { uint64_t Size = DT->getSizeInBits(); uint64_t FieldSize = DD->getBaseTypeSize(DT); + uint64_t AlignInBytes = DT->getAlignInChars(); uint64_t OffsetInBytes; bool IsBitfield = FieldSize && Size != FieldSize; @@ -1428,6 +1435,9 @@ } else { // This is not a bitfield. OffsetInBytes = DT->getOffsetInBits() / 8; + if (AlignInBytes && (DT->getFlags() & DINode::FlagAlignment)) + addUInt(MemberDie, dwarf::DW_AT_alignment, dwarf::DW_FORM_data8, + AlignInBytes); } if (DD->getDwarfVersion() <= 2) { @@ -1504,6 +1514,11 @@ if (const ConstantFP *CFP = dyn_cast_or_null(DT->getConstant())) addConstantFPValue(StaticMemberDIE, CFP); + uint64_t AlignInBytes = DT->getAlignInChars(); + if (AlignInBytes && (DT->getFlags() & DINode::FlagAlignment)) + addUInt(StaticMemberDIE, dwarf::DW_AT_alignment, dwarf::DW_FORM_data8, + AlignInBytes); + return &StaticMemberDIE; } Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1816,6 +1816,8 @@ Printer.printMetadata("type", N->getRawType()); Printer.printBool("isLocal", N->isLocalToUnit()); Printer.printBool("isDefinition", N->isDefinition()); + Printer.printInt("align", N->getAlignInBits()); + Printer.printDIFlags("flags", N->getFlags()); Printer.printMetadata("variable", N->getRawVariable()); Printer.printMetadata("declaration", N->getRawStaticDataMemberDeclaration()); Out << ")"; @@ -1832,6 +1834,7 @@ Printer.printMetadata("file", N->getRawFile()); Printer.printInt("line", N->getLine()); Printer.printMetadata("type", N->getRawType()); + Printer.printInt("align", N->getAlignInBits()); Printer.printDIFlags("flags", N->getFlags()); Out << ")"; } Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -290,11 +290,12 @@ DIDerivedType * DIBuilder::createStaticMemberType(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, DIType *Ty, - DINode::DIFlags Flags, llvm::Constant *Val) { + uint64_t AlignInBits, DINode::DIFlags Flags, + llvm::Constant *Val) { Flags |= DINode::FlagStaticMember; return DIDerivedType::get(VMContext, dwarf::DW_TAG_member, Name, File, - LineNumber, getNonCompileUnitScope(Scope), Ty, 0, 0, - 0, Flags, getConstantOrNull(Val)); + LineNumber, getNonCompileUnitScope(Scope), Ty, 0, + AlignInBits, 0, Flags, getConstantOrNull(Val)); } DIDerivedType * @@ -413,12 +414,12 @@ DICompositeType *DIBuilder::createEnumerationType( DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, - uint64_t SizeInBits, uint64_t AlignInBits, DINodeArray Elements, - DIType *UnderlyingType, StringRef UniqueIdentifier) { + uint64_t SizeInBits, uint64_t AlignInBits, DINode::DIFlags Flags, + DINodeArray Elements, DIType *UnderlyingType, StringRef UniqueIdentifier) { auto *CTy = DICompositeType::get( VMContext, dwarf::DW_TAG_enumeration_type, Name, File, LineNumber, getNonCompileUnitScope(Scope), UnderlyingType, SizeInBits, AlignInBits, 0, - DINode::FlagZero, Elements, 0, nullptr, nullptr, UniqueIdentifier); + Flags, Elements, 0, nullptr, nullptr, UniqueIdentifier); AllEnumTypes.push_back(CTy); trackIfUnresolved(CTy); return CTy; @@ -535,13 +536,13 @@ DIGlobalVariable *DIBuilder::createGlobalVariable( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, Constant *Val, - MDNode *Decl) { + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, uint64_t AlignInBits, + DINode::DIFlags Flags, Constant *Val, MDNode *Decl) { checkGlobalVariableScope(Context); auto *N = DIGlobalVariable::getDistinct( VMContext, cast_or_null(Context), Name, LinkageName, F, - LineNumber, Ty, isLocalToUnit, true, Val, + LineNumber, Ty, isLocalToUnit, true, AlignInBits, Flags, Val, cast_or_null(Decl)); AllGVs.push_back(N); return N; @@ -549,13 +550,13 @@ DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, Constant *Val, - MDNode *Decl) { + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, uint64_t AlignInBits, + DINode::DIFlags Flags, Constant *Val, MDNode *Decl) { checkGlobalVariableScope(Context); return DIGlobalVariable::getTemporary( VMContext, cast_or_null(Context), Name, LinkageName, F, - LineNumber, Ty, isLocalToUnit, false, Val, + LineNumber, Ty, isLocalToUnit, false, AlignInBits, Flags, Val, cast_or_null(Decl)) .release(); } @@ -564,7 +565,8 @@ LLVMContext &VMContext, DenseMap> &PreservedVariables, DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File, - unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags) { + unsigned LineNo, DIType *Ty, bool AlwaysPreserve, uint64_t AlignInBits, + DINode::DIFlags Flags) { // FIXME: Why getNonCompileUnitScope()? // FIXME: Why is "!Context" okay here? // FIXME: Why doesn't this check for a subprogram or lexical block (AFAICT @@ -573,7 +575,7 @@ auto *Node = DILocalVariable::get(VMContext, cast_or_null(Context), Name, - File, LineNo, Ty, ArgNo, Flags); + File, LineNo, Ty, ArgNo, AlignInBits, Flags); if (AlwaysPreserve) { // The optimizer may remove local variables. If there is an interest // to preserve variable info in such situation then stash it in a @@ -588,10 +590,11 @@ DILocalVariable *DIBuilder::createAutoVariable(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve, + uint64_t AlignInBits, DINode::DIFlags Flags) { return createLocalVariable(VMContext, PreservedVariables, Scope, Name, /* ArgNo */ 0, File, LineNo, Ty, AlwaysPreserve, - Flags); + AlignInBits, Flags); } DILocalVariable *DIBuilder::createParameterVariable( @@ -599,7 +602,8 @@ unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags) { assert(ArgNo && "Expected non-zero argument number for parameter"); return createLocalVariable(VMContext, PreservedVariables, Scope, Name, ArgNo, - File, LineNo, Ty, AlwaysPreserve, Flags); + File, LineNo, Ty, AlwaysPreserve, /* Align */ 0, + Flags); } DIExpression *DIBuilder::createExpression(ArrayRef Addr) { Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -508,6 +508,7 @@ DIGlobalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, + uint64_t Align, DINode::DIFlags Flags, Metadata *Variable, Metadata *StaticDataMemberDeclaration, StorageType Storage, bool ShouldCreate) { @@ -515,19 +516,19 @@ assert(isCanonical(LinkageName) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIGlobalVariable, (Scope, Name, LinkageName, File, Line, Type, - IsLocalToUnit, IsDefinition, Variable, + IsLocalToUnit, IsDefinition, Align, Flags, Variable, StaticDataMemberDeclaration)); Metadata *Ops[] = {Scope, Name, File, Type, Name, LinkageName, Variable, StaticDataMemberDeclaration}; - DEFINE_GETIMPL_STORE(DIGlobalVariable, (Line, IsLocalToUnit, IsDefinition), - Ops); + DEFINE_GETIMPL_STORE(DIGlobalVariable, + (Line, IsLocalToUnit, IsDefinition, Align, Flags), Ops); } DILocalVariable *DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, Metadata *Type, - unsigned Arg, DIFlags Flags, - StorageType Storage, + unsigned Arg, uint64_t Align, + DIFlags Flags, StorageType Storage, bool ShouldCreate) { // 64K ought to be enough for any frontend. assert(Arg <= UINT16_MAX && "Expected argument number to fit in 16-bits"); @@ -535,9 +536,9 @@ assert(Scope && "Expected scope"); assert(isCanonical(Name) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DILocalVariable, - (Scope, Name, File, Line, Type, Arg, Flags)); + (Scope, Name, File, Line, Type, Arg, Align, Flags)); Metadata *Ops[] = {Scope, Name, File, Type}; - DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags), Ops); + DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Align, Flags), Ops); } DIExpression *DIExpression::getImpl(LLVMContext &Context, Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -758,22 +758,27 @@ Metadata *Type; bool IsLocalToUnit; bool IsDefinition; + uint64_t AlignInBits; + DINode::DIFlags Flags; Metadata *Variable; Metadata *StaticDataMemberDeclaration; MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, + bool IsLocalToUnit, bool IsDefinition, uint64_t AlignInBits, + DINode::DIFlags Flags, Metadata *Variable, Metadata *StaticDataMemberDeclaration) : Scope(Scope), Name(Name), LinkageName(LinkageName), File(File), Line(Line), Type(Type), IsLocalToUnit(IsLocalToUnit), - IsDefinition(IsDefinition), Variable(Variable), + IsDefinition(IsDefinition), AlignInBits(AlignInBits), Flags(Flags), + Variable(Variable), StaticDataMemberDeclaration(StaticDataMemberDeclaration) {} MDNodeKeyImpl(const DIGlobalVariable *N) : Scope(N->getRawScope()), Name(N->getRawName()), LinkageName(N->getRawLinkageName()), File(N->getRawFile()), Line(N->getLine()), Type(N->getRawType()), IsLocalToUnit(N->isLocalToUnit()), IsDefinition(N->isDefinition()), + AlignInBits(N->getAlignInBits()), Flags(N->getFlags()), Variable(N->getRawVariable()), StaticDataMemberDeclaration(N->getRawStaticDataMemberDeclaration()) {} @@ -783,14 +788,15 @@ File == RHS->getRawFile() && Line == RHS->getLine() && Type == RHS->getRawType() && IsLocalToUnit == RHS->isLocalToUnit() && IsDefinition == RHS->isDefinition() && + AlignInBits == RHS->getAlignInBits() && Flags == RHS->getFlags() && Variable == RHS->getRawVariable() && StaticDataMemberDeclaration == RHS->getRawStaticDataMemberDeclaration(); } unsigned getHashValue() const { return hash_combine(Scope, Name, LinkageName, File, Line, Type, - IsLocalToUnit, IsDefinition, Variable, - StaticDataMemberDeclaration); + IsLocalToUnit, IsDefinition, AlignInBits, Flags, + Variable, StaticDataMemberDeclaration); } }; @@ -801,25 +807,34 @@ unsigned Line; Metadata *Type; unsigned Arg; - unsigned Flags; + uint64_t AlignInBits; + DINode::DIFlags Flags; MDNodeKeyImpl(Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, - Metadata *Type, unsigned Arg, unsigned Flags) + Metadata *Type, unsigned Arg, uint64_t AlignInBits, + DINode::DIFlags Flags) : Scope(Scope), Name(Name), File(File), Line(Line), Type(Type), Arg(Arg), - Flags(Flags) {} + AlignInBits(AlignInBits), Flags(Flags) {} MDNodeKeyImpl(const DILocalVariable *N) : Scope(N->getRawScope()), Name(N->getRawName()), File(N->getRawFile()), Line(N->getLine()), Type(N->getRawType()), Arg(N->getArg()), - Flags(N->getFlags()) {} + AlignInBits(N->getAlignInBits()), Flags(N->getFlags()) {} bool isKeyOf(const DILocalVariable *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && File == RHS->getRawFile() && Line == RHS->getLine() && Type == RHS->getRawType() && Arg == RHS->getArg() && - Flags == RHS->getFlags(); + AlignInBits == RHS->getAlignInBits() && Flags == RHS->getFlags(); } unsigned getHashValue() const { - return hash_combine(Scope, Name, File, Line, Type, Arg, Flags); + // We do not use Align in hashing function here on purpose: + // in most cases this param for local variable is zero (for function param + // it is always zero). This leads to lots of hash collisions and errors on + // cases with lots of similar variables. + // clang/test/CodeGen/debug-info-257-args.c is an example of this problem, + // generated IR is random for each run and test fails with Align included. + // TODO: make hashing work fine with such situations + return hash_combine(Scope, Name, File, Line, Type, Arg, /* Align, */ Flags); } }; Index: lib/Support/Dwarf.cpp =================================================================== --- lib/Support/Dwarf.cpp +++ lib/Support/Dwarf.cpp @@ -148,6 +148,8 @@ case DW_AT_reference: return "DW_AT_reference"; case DW_AT_rvalue_reference: return "DW_AT_rvalue_reference"; case DW_AT_noreturn: return "DW_AT_noreturn"; + case DW_AT_alignment: + return "DW_AT_alignment"; case DW_AT_MIPS_loop_begin: return "DW_AT_MIPS_loop_begin"; case DW_AT_MIPS_tail_loop_begin: return "DW_AT_MIPS_tail_loop_begin"; case DW_AT_MIPS_epilog_begin: return "DW_AT_MIPS_epilog_begin"; Index: test/Assembler/dilocalvariable.ll =================================================================== --- test/Assembler/dilocalvariable.ll +++ test/Assembler/dilocalvariable.ll @@ -3,10 +3,10 @@ @foo = global i32 0 -; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} -!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} +; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11} -!llvm.module.flags = !{!10} +!llvm.module.flags = !{!12} !llvm.dbg.cu = !{!1} !0 = distinct !DISubprogram(unit: !1) @@ -26,10 +26,20 @@ !6 = !DILocalVariable(name: "foo", scope: !0, file: !2, line: 7, type: !3, flags: DIFlagArtificial) -; CHECK: !7 = !DILocalVariable(arg: 1, scope: !0) -; CHECK: !8 = !DILocalVariable(scope: !0) -!7 = !DILocalVariable(scope: !0, arg: 1) -!8 = !DILocalVariable(scope: !0) -!9 = distinct !{} +; CHECK: !7 = !DILocalVariable(name: "foo", arg: 3, scope: !0, file: !2, line: 7, type: !3, align: 256, flags: DIFlagAlignment) +; CHECK: !8 = !DILocalVariable(name: "foo", scope: !0, file: !2, line: 7, type: !3, align: 256, flags: DIFlagAlignment) +!7 = !DILocalVariable(name: "foo", arg: 3, + scope: !0, file: !2, line: 7, type: !3, align: 256, + flags: DIFlagAlignment) +!8 = !DILocalVariable(name: "foo", scope: !0, + file: !2, line: 7, type: !3, align: 256, + flags: DIFlagAlignment) -!10 = !{i32 2, !"Debug Info Version", i32 3} + +; CHECK: !9 = !DILocalVariable(arg: 1, scope: !0) +; CHECK: !10 = !DILocalVariable(scope: !0) +!9 = !DILocalVariable(scope: !0, arg: 1) +!10 = !DILocalVariable(scope: !0) +!11 = distinct !{} + +!12 = !{i32 2, !"Debug Info Version", i32 3} Index: test/DebugInfo/X86/align_c11.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/align_c11.ll @@ -0,0 +1,83 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s +; REQUIRES: object-emission + +; Generated by clang -c -g -std=c11 -S -emit-llvm from the following C11 source +; +; // every object of type struct data will be aligned to 128-byte boundary +; struct data { +; char x; +; _Alignas(128) char arr[2]; +; }; +; +; _Alignas(2048) struct data d; // this instance of data is aligned even stricter +; int foo(void) +; { +; struct data local_data; +; return 0; +; } + +; CHECK: DW_TAG_variable +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"d" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000800 +; CHECK: DW_TAG_structure_type +; CHECK: DW_TAG_member +; CHECK: DW_TAG_member +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"arr" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000080 + +; ModuleID = 'test.c' +source_filename = "test.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.data = type { i8, [127 x i8], [2 x i8], [126 x i8] } + +@d = common global %struct.data zeroinitializer, align 2048 + +; Function Attrs: nounwind uwtable +define i32 @foo() #0 !dbg !17 { +entry: + %local_data = alloca %struct.data, align 128 + call void @llvm.dbg.declare(metadata %struct.data* %local_data, metadata !21, metadata !22), !dbg !23 + ret i32 0, !dbg !24 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15} +!llvm.ident = !{!16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (http://llvm.org/git/clang.git 6a13bc54e10105c54e01adceb719e57136b21e71)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3) +!1 = !DIFile(filename: "test.c", directory: "/tmp") +!2 = !{} +!3 = !{!4} +!4 = distinct !DIGlobalVariable(name: "d", scope: !0, file: !5, line: 7, type: !6, isLocal: false, isDefinition: true, align: 16384, flags: DIFlagAlignment, variable: %struct.data* @d) +!5 = !DIFile(filename: "test.c", directory: "/tmp") +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "data", file: !5, line: 2, size: 2048, align: 1024, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !6, file: !5, line: 3, baseType: !9, size: 8, align: 8) +!9 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "arr", scope: !6, file: !5, line: 4, baseType: !11, size: 16, align: 1024, offset: 1024, flags: DIFlagAlignment) +!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 16, align: 8, elements: !12) +!12 = !{!13} +!13 = !DISubrange(count: 2) +!14 = !{i32 2, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 6a13bc54e10105c54e01adceb719e57136b21e71)"} +!17 = distinct !DISubprogram(name: "foo", scope: !5, file: !5, line: 8, type: !18, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!18 = !DISubroutineType(types: !19) +!19 = !{!20} +!20 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!21 = !DILocalVariable(name: "local_data", scope: !17, file: !5, line: 10, type: !6) +!22 = !DIExpression() +!23 = !DILocation(line: 10, column: 17, scope: !17) +!24 = !DILocation(line: 11, column: 5, scope: !17) Index: test/DebugInfo/X86/align_cpp11.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/align_cpp11.ll @@ -0,0 +1,172 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s +; REQUIRES: object-emission + +; Generated by clang++ -c -g -std=c++11 -S -emit-llvm from the following C++11 source +; struct S { +; char x; +; alignas(128) char xx; +; }; +; +; class alignas(64) C0 { +; }; +; +; class C1 { +; alignas(64) static void *p; +; }; +; +; enum alignas(16) E { +; A, +; B, +; C, +; }; +; +; C0 c0; +; +; alignas(2048) S s; +; +; void foo() +; { +; S ss; +; E e; +; C1 c1; +; alignas(32) int i = 42; +; auto Lambda = [i](){}; +; } + +; CHECK: DW_TAG_class_type +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"C0" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000040 + +; CHECK: DW_TAG_variable +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"s" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000800 + +; CHECK: DW_TAG_structure_type +; CHECK: DW_TAG_member +; CHECK: DW_AT_name{{.*}}"xx" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000080 + +; CHECK: DW_TAG_enumeration_type +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000010 + +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name{{.*}}"i" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000020 +; CHECK: DW_TAG_class_type +; CHECK: DW_TAG_member +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"i" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000020 + +; CHECK: DW_TAG_class_type +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"C1" +; CHECK: DW_TAG_member +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"p" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000040 + +; ModuleID = 'test.cpp' +source_filename = "test.cpp" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%class.C0 = type { [64 x i8] } +%struct.S = type { i8, [127 x i8], i8, [127 x i8] } +%class.C1 = type { i8 } +%class.anon = type { i32 } + +@c0 = global %class.C0 zeroinitializer, align 64 +@s = global %struct.S zeroinitializer, align 2048 + +; Function Attrs: nounwind uwtable +define void @_Z3foov() #0 !dbg !22 { +entry: + %ss = alloca %struct.S, align 128 + %e = alloca i32, align 16 + %c1 = alloca %class.C1, align 1 + %i = alloca i32, align 32 + %Lambda = alloca %class.anon, align 4 + call void @llvm.dbg.declare(metadata %struct.S* %ss, metadata !25, metadata !26), !dbg !27 + call void @llvm.dbg.declare(metadata i32* %e, metadata !28, metadata !26), !dbg !29 + call void @llvm.dbg.declare(metadata %class.C1* %c1, metadata !30, metadata !26), !dbg !35 + call void @llvm.dbg.declare(metadata i32* %i, metadata !36, metadata !26), !dbg !38 + store i32 42, i32* %i, align 32, !dbg !38 + call void @llvm.dbg.declare(metadata %class.anon* %Lambda, metadata !39, metadata !26), !dbg !48 + %0 = getelementptr inbounds %class.anon, %class.anon* %Lambda, i32 0, i32 0, !dbg !49 + %1 = load i32, i32* %i, align 32, !dbg !50 + store i32 %1, i32* %0, align 4, !dbg !49 + ret void, !dbg !51 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!19, !20} +!llvm.ident = !{!21} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 4.0.0 (http://llvm.org/git/clang.git 60d6ba31ce8467424abdb7e29610a6537f483540)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !9) +!1 = !DIFile(filename: "test.cpp", directory: "/tmp") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E", file: !4, line: 14, size: 32, align: 128, flags: DIFlagAlignment, elements: !5, identifier: "_ZTS1E") +!4 = !DIFile(filename: "test.cpp", directory: "/tmp") +!5 = !{!6, !7, !8} +!6 = !DIEnumerator(name: "A", value: 0) +!7 = !DIEnumerator(name: "B", value: 1) +!8 = !DIEnumerator(name: "C", value: 2) +!9 = !{!10, !13} +!10 = distinct !DIGlobalVariable(name: "c0", scope: !0, file: !4, line: 20, type: !11, isLocal: false, isDefinition: true, variable: %class.C0* @c0) +!11 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C0", file: !4, line: 6, size: 512, align: 512, flags: DIFlagAlignment, elements: !12, identifier: "_ZTS2C0") +!12 = !{} +!13 = distinct !DIGlobalVariable(name: "s", scope: !0, file: !4, line: 22, type: !14, isLocal: false, isDefinition: true, align: 16384, flags: DIFlagAlignment, variable: %struct.S* @s) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !4, line: 1, size: 2048, align: 1024, elements: !15, identifier: "_ZTS1S") +!15 = !{!16, !18} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !14, file: !4, line: 2, baseType: !17, size: 8, align: 8) +!17 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!18 = !DIDerivedType(tag: DW_TAG_member, name: "xx", scope: !14, file: !4, line: 3, baseType: !17, size: 8, align: 1024, offset: 1024, flags: DIFlagAlignment) +!19 = !{i32 2, !"Dwarf Version", i32 4} +!20 = !{i32 2, !"Debug Info Version", i32 3} +!21 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 60d6ba31ce8467424abdb7e29610a6537f483540)"} +!22 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !4, file: !4, line: 24, type: !23, isLocal: false, isDefinition: true, scopeLine: 25, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !12) +!23 = !DISubroutineType(types: !24) +!24 = !{null} +!25 = !DILocalVariable(name: "ss", scope: !22, file: !4, line: 26, type: !14) +!26 = !DIExpression() +!27 = !DILocation(line: 26, column: 7, scope: !22) +!28 = !DILocalVariable(name: "e", scope: !22, file: !4, line: 27, type: !3) +!29 = !DILocation(line: 27, column: 7, scope: !22) +!30 = !DILocalVariable(name: "c1", scope: !22, file: !4, line: 28, type: !31) +!31 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C1", file: !4, line: 9, size: 8, align: 8, elements: !32, identifier: "_ZTS2C1") +!32 = !{!33} +!33 = !DIDerivedType(tag: DW_TAG_member, name: "p", scope: !31, file: !4, line: 11, baseType: !34, align: 512, flags: DIFlagPublic | DIFlagStaticMember | DIFlagAlignment) +!34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64, align: 64) +!35 = !DILocation(line: 28, column: 8, scope: !22) +!36 = !DILocalVariable(name: "i", scope: !22, file: !4, line: 29, type: !37, align: 256, flags: DIFlagAlignment) +!37 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!38 = !DILocation(line: 29, column: 21, scope: !22) +!39 = !DILocalVariable(name: "Lambda", scope: !22, file: !4, line: 30, type: !40) +!40 = distinct !DICompositeType(tag: DW_TAG_class_type, scope: !22, file: !4, line: 30, size: 32, align: 32, elements: !41) +!41 = !{!42, !43} +!42 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !40, file: !4, line: 30, baseType: !37, size: 32, align: 256, flags: DIFlagAlignment) +!43 = !DISubprogram(name: "operator()", scope: !40, file: !4, line: 30, type: !44, isLocal: false, isDefinition: false, scopeLine: 30, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: false) +!44 = !DISubroutineType(types: !45) +!45 = !{null, !46} +!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !47, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!47 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !40) +!48 = !DILocation(line: 30, column: 10, scope: !22) +!49 = !DILocation(line: 30, column: 19, scope: !22) +!50 = !DILocation(line: 30, column: 20, scope: !22) +!51 = !DILocation(line: 31, column: 1, scope: !22) Index: test/DebugInfo/X86/align_objc.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/align_objc.ll @@ -0,0 +1,99 @@ +; RUN: %llc_dwarf -filetype=obj < %s | llvm-dwarfdump -debug-dump=info - | FileCheck %s +; REQUIRES: object-emission + +; typedef struct __attribute__((aligned (128))) { +; char c; +; } S0; +; +; +; typedef struct { +; __attribute__((aligned (64))) char c; +; } S1; +; +; S0 s0; +; +; void f() { +; S1 s1; +; __attribute__((aligned (32))) int i; +; } + +; CHECK: DW_TAG_typedef +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"S0" +; CHECK: DW_TAG_structure_type +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000080 + +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name{{.*}}"i" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000020 + +; CHECK: DW_TAG_typedef +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"S1" +; CHECK: DW_TAG_structure_type +; CHECK: DW_TAG_member +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name{{.*}}"c" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_alignment{{.*}}0x0000000000000040 + +; ModuleID = 'test.m' +source_filename = "test.m" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.S0 = type { i8, [127 x i8] } +%struct.S1 = type { i8, [63 x i8] } + +@s0 = common global %struct.S0 zeroinitializer, align 128 + +; Function Attrs: nounwind uwtable +define void @f() #0 !dbg !14 { +entry: + %s1 = alloca %struct.S1, align 64 + %i = alloca i32, align 32 + call void @llvm.dbg.declare(metadata %struct.S1* %s1, metadata !17, metadata !22), !dbg !23 + call void @llvm.dbg.declare(metadata i32* %i, metadata !24, metadata !22), !dbg !26 + ret void, !dbg !27 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12} +!llvm.ident = !{!13} + +!0 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !1, producer: "clang version 4.0.0 (http://llvm.org/git/clang.git 60d6ba31ce8467424abdb7e29610a6537f483540)", isOptimized: false, runtimeVersion: 1, emissionKind: FullDebug, enums: !2, globals: !3) +!1 = !DIFile(filename: "test.m", directory: "/tmp") +!2 = !{} +!3 = !{!4} +!4 = distinct !DIGlobalVariable(name: "s0", scope: !0, file: !5, line: 10, type: !6, isLocal: false, isDefinition: true, variable: %struct.S0* @s0) +!5 = !DIFile(filename: "./test.m", directory: "/tmp") +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "S0", file: !5, line: 3, baseType: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !5, line: 1, size: 1024, align: 1024, flags: DIFlagAlignment, elements: !8) +!8 = !{!9} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !7, file: !5, line: 2, baseType: !10, size: 8, align: 8) +!10 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 60d6ba31ce8467424abdb7e29610a6537f483540)"} +!14 = distinct !DISubprogram(name: "f", scope: !5, file: !5, line: 12, type: !15, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: false, unit: !0, variables: !2) +!15 = !DISubroutineType(types: !16) +!16 = !{null} +!17 = !DILocalVariable(name: "s1", scope: !14, file: !5, line: 13, type: !18) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "S1", file: !5, line: 8, baseType: !19) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !5, line: 6, size: 512, align: 512, elements: !20) +!20 = !{!21} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !19, file: !5, line: 7, baseType: !10, size: 8, align: 512, flags: DIFlagAlignment) +!22 = !DIExpression() +!23 = !DILocation(line: 13, column: 6, scope: !14) +!24 = !DILocalVariable(name: "i", scope: !14, file: !5, line: 14, type: !25, align: 256, flags: DIFlagAlignment) +!25 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!26 = !DILocation(line: 14, column: 37, scope: !14) +!27 = !DILocation(line: 15, column: 1, scope: !14) Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -1820,13 +1820,15 @@ DIType *Type = getDerivedType(); bool IsLocalToUnit = false; bool IsDefinition = true; + uint64_t AlignInBits = 64; + DINode::DIFlags Flags = DINode::FlagAlignment; Constant *Variable = getConstant(); DIDerivedType *StaticDataMemberDeclaration = cast(getDerivedType()); - auto *N = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, Variable, - StaticDataMemberDeclaration); + auto *N = DIGlobalVariable::get( + Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, + IsDefinition, AlignInBits, Flags, Variable, StaticDataMemberDeclaration); EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag()); EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(Name, N->getName()); @@ -1836,48 +1838,63 @@ EXPECT_EQ(Type, N->getType()); EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); EXPECT_EQ(IsDefinition, N->isDefinition()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); + EXPECT_EQ(Flags, N->getFlags()); EXPECT_EQ(Variable, N->getVariable()); EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration()); EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); + AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); - EXPECT_NE(N, - DIGlobalVariable::get(Context, getSubprogram(), Name, LinkageName, - File, Line, Type, IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get( + Context, getSubprogram(), Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, AlignInBits, Flags, + Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other", LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); + AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other", File, Line, Type, IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); - EXPECT_NE(N, - DIGlobalVariable::get(Context, Scope, Name, LinkageName, getFile(), - Line, Type, IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); - EXPECT_NE(N, - DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, - Line + 1, Type, IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); - EXPECT_NE(N, - DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - getDerivedType(), IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); + AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, + getFile(), Line, Type, IsLocalToUnit, + IsDefinition, AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line + 1, Type, IsLocalToUnit, + IsDefinition, AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, getDerivedType(), IsLocalToUnit, + IsDefinition, AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, !IsLocalToUnit, IsDefinition, - Variable, StaticDataMemberDeclaration)); + AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, !IsDefinition, - Variable, StaticDataMemberDeclaration)); - EXPECT_NE(N, - DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, - getConstant(), StaticDataMemberDeclaration)); - EXPECT_NE(N, - DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, Variable, - cast(getDerivedType()))); + AlignInBits, Flags, Variable, + StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, !IsDefinition, + (AlignInBits << 1), Flags, Variable, + StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, !IsDefinition, + 0, DINode::FlagZero, Variable, + StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + AlignInBits, Flags, getConstant(), + StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + AlignInBits, Flags, Variable, + cast(getDerivedType()))); TempDIGlobalVariable Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1892,10 +1909,12 @@ unsigned Line = 5; DIType *Type = getDerivedType(); unsigned Arg = 6; - DINode::DIFlags Flags = static_cast(7); + uint64_t AlignInBits = 1 << 7; + DINode::DIFlags Flags = + static_cast(8) | DINode::FlagAlignment; - auto *N = - DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags); + auto *N = DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, + AlignInBits, Flags); EXPECT_TRUE(N->isParameter()); EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(Name, N->getName()); @@ -1903,25 +1922,30 @@ EXPECT_EQ(Line, N->getLine()); EXPECT_EQ(Type, N->getType()); EXPECT_EQ(Arg, N->getArg()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); EXPECT_EQ(Flags, N->getFlags()); EXPECT_EQ(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, - Flags)); + AlignInBits, Flags)); - EXPECT_FALSE( - DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, Flags) - ->isParameter()); + EXPECT_FALSE(DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, + AlignInBits, Flags) + ->isParameter()); EXPECT_NE(N, DILocalVariable::get(Context, getSubprogram(), Name, File, Line, - Type, Arg, Flags)); + Type, Arg, AlignInBits, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, "other", File, Line, Type, - Arg, Flags)); + Arg, AlignInBits, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, getFile(), Line, Type, - Arg, Flags)); + Arg, AlignInBits, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line + 1, Type, - Arg, Flags)); + Arg, AlignInBits, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, - getDerivedType(), Arg, Flags)); + getDerivedType(), Arg, AlignInBits, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, - Arg + 1, Flags)); + Arg + 1, AlignInBits, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, + (AlignInBits << 1), Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, + 0, (Flags &= ~DINode::FlagAlignment))); TempDILocalVariable Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1929,17 +1953,17 @@ TEST_F(DILocalVariableTest, getArg256) { EXPECT_EQ(255u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, 255, DINode::FlagZero) + 0, nullptr, 255, 0, DINode::FlagZero) ->getArg()); EXPECT_EQ(256u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, 256, DINode::FlagZero) + 0, nullptr, 256, 0, DINode::FlagZero) ->getArg()); EXPECT_EQ(257u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, 257, DINode::FlagZero) + 0, nullptr, 257, 0, DINode::FlagZero) ->getArg()); unsigned Max = UINT16_MAX; EXPECT_EQ(Max, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, Max, DINode::FlagZero) + 0, nullptr, Max, 0, DINode::FlagZero) ->getArg()); } Index: unittests/IR/VerifierTest.cpp =================================================================== --- unittests/IR/VerifierTest.cpp +++ unittests/IR/VerifierTest.cpp @@ -135,8 +135,10 @@ "unittest", false, "", 0); auto File = dbuilder.createFile("test.jl", "."); auto Ty = dbuilder.createBasicType("Int8", 8, 8, dwarf::DW_ATE_signed); + uint64_t Align = newGV->getAlignment(); + DINode::DIFlags Flags = Align ? DINode::FlagAlignment : DINode::FlagZero; dbuilder.createGlobalVariable(CU, "_SOME_GLOBAL", "_SOME_GLOBAL", File, 1, Ty, - false, newGV); + false, Align, Flags, newGV); dbuilder.finalize(); std::string Error;