Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -120,10 +120,9 @@ /// type. /// \param Name Type name. /// \param SizeInBits Size of the type. - /// \param AlignInBits Type alignment. /// \param Encoding DWARF encoding code, e.g. dwarf::DW_ATE_float. DIBasicType *createBasicType(StringRef Name, uint64_t SizeInBits, - uint64_t AlignInBits, unsigned Encoding); + unsigned Encoding); /// Create debugging information entry for a qualified /// type, e.g. 'const int'. @@ -201,14 +200,13 @@ /// \param File File where this member is defined. /// \param LineNo Line number. /// \param SizeInBits Member size. - /// \param AlignInBits Member alignment. /// \param OffsetInBits Member offset. /// \param StorageOffsetInBits Member storage offset. /// \param Flags Flags to encode member attribute. /// \param Ty Parent type. DIDerivedType *createBitFieldMemberType( DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, - uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, + uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits, DINode::DIFlags Flags, DIType *Ty); /// Create debugging information entry for a @@ -220,10 +218,12 @@ /// \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 AlignInBits Member alignment. DIDerivedType *createStaticMemberType(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, DIType *Ty, DINode::DIFlags Flags, - llvm::Constant *Val); + llvm::Constant *Val, + uint64_t AlignInBits = 0); /// Create debugging information entry for Objective-C /// instance variable. @@ -457,19 +457,22 @@ /// \param Expr The location of the global relative to the attached /// GlobalVariable. /// \param Decl Reference to the corresponding declaration. + /// \param AlignInBits Variable alignment(or 0 if no alignment attr was + /// specified) DIGlobalVariable *createGlobalVariable(DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DIType *Ty, bool isLocalToUnit, DIExpression *Expr = nullptr, - MDNode *Decl = nullptr); + MDNode *Decl = nullptr, + uint64_t AlignInBits = 0); /// 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, DIExpression *Expr, - MDNode *Decl = nullptr); + MDNode *Decl = nullptr, uint64_t AlignInBits = 0); /// Create a new descriptor for an auto variable. This is a local variable /// that is not a subprogram parameter. @@ -482,7 +485,8 @@ DILocalVariable * createAutoVariable(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve = false, - DINode::DIFlags Flags = DINode::FlagZero); + DINode::DIFlags Flags = DINode::FlagZero, + uint64_t AlignInBits = 0); /// Create a new descriptor for a parameter variable. /// Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -1826,11 +1826,13 @@ /// \brief Base class for variables. class DIVariable : public DINode { unsigned Line; + uint64_t AlignInBits; 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) + : DINode(C, ID, Storage, dwarf::DW_TAG_variable, Ops), Line(Line), + AlignInBits(AlignInBits) {} ~DIVariable() = default; public: @@ -1839,6 +1841,7 @@ 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; } StringRef getFilename() const { if (auto *F = getFile()) @@ -2026,9 +2029,9 @@ bool IsDefinition; DIGlobalVariable(LLVMContext &C, StorageType Storage, unsigned Line, - bool IsLocalToUnit, bool IsDefinition, + bool IsLocalToUnit, bool IsDefinition, uint64_t AlignInBits, ArrayRef Ops) - : DIVariable(C, DIGlobalVariableKind, Storage, Line, Ops), + : DIVariable(C, DIGlobalVariableKind, Storage, Line, Ops, AlignInBits), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition) {} ~DIGlobalVariable() = default; @@ -2036,42 +2039,48 @@ getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, bool IsLocalToUnit, bool IsDefinition, DIExpression *Expr, - DIDerivedType *StaticDataMemberDeclaration, StorageType Storage, - bool ShouldCreate = true) { + DIDerivedType *StaticDataMemberDeclaration, uint64_t AlignInBits, + StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, IsLocalToUnit, IsDefinition, Expr, - StaticDataMemberDeclaration, Storage, ShouldCreate); + StaticDataMemberDeclaration, AlignInBits, Storage, + ShouldCreate); } static DIGlobalVariable * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, Metadata *Expr, - Metadata *StaticDataMemberDeclaration, StorageType Storage, - bool ShouldCreate = true); + Metadata *StaticDataMemberDeclaration, uint64_t AlignInBits, + StorageType Storage, bool ShouldCreate = true); TempDIGlobalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getLinkageName(), getFile(), getLine(), getType(), isLocalToUnit(), isDefinition(), getExpr(), - getStaticDataMemberDeclaration()); + getStaticDataMemberDeclaration(), getAlignInBits()); } public: DEFINE_MDNODE_GET(DIGlobalVariable, (DIScope * Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, - bool IsLocalToUnit, bool IsDefinition, DIExpression *Expr, - DIDerivedType *StaticDataMemberDeclaration), + bool IsLocalToUnit, bool IsDefinition, + DIExpression *Expr, + DIDerivedType *StaticDataMemberDeclaration, + uint64_t AlignInBits), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Expr, StaticDataMemberDeclaration)) + IsDefinition, Expr, StaticDataMemberDeclaration, + AlignInBits)) DEFINE_MDNODE_GET(DIGlobalVariable, (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Expr, - Metadata *StaticDataMemberDeclaration), + bool IsLocalToUnit, bool IsDefinition, + Metadata *Expr, Metadata *StaticDataMemberDeclaration, + uint64_t AlignInBits), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Expr, StaticDataMemberDeclaration)) + IsDefinition, Expr, StaticDataMemberDeclaration, + AlignInBits)) TempDIGlobalVariable clone() const { return cloneImpl(); } @@ -2109,9 +2118,10 @@ 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, DIFlags Flags, uint64_t AlignInBits, + ArrayRef Ops) + : DIVariable(C, DILocalVariableKind, Storage, Line, Ops, AlignInBits), + Arg(Arg), Flags(Flags) { assert(Arg < (1 << 16) && "DILocalVariable: Arg out of range"); } ~DILocalVariable() = default; @@ -2119,33 +2129,34 @@ static DILocalVariable *getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, DIFile *File, unsigned Line, DITypeRef Type, unsigned Arg, DIFlags Flags, - StorageType Storage, + uint64_t AlignInBits, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File, - Line, Type, Arg, Flags, Storage, ShouldCreate); + Line, Type, Arg, Flags, AlignInBits, Storage, ShouldCreate); } static DILocalVariable *getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, Metadata *Type, unsigned Arg, DIFlags Flags, - StorageType Storage, + uint64_t AlignInBits, StorageType Storage, bool ShouldCreate = true); TempDILocalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getFile(), - getLine(), getType(), getArg(), getFlags()); + getLine(), getType(), getArg(), getFlags(), + getAlignInBits()); } 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)) + DIFlags Flags, uint64_t AlignInBits), + (Scope, Name, File, Line, Type, Arg, Flags, AlignInBits)) 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)) + DIFlags Flags, uint64_t AlignInBits), + (Scope, Name, File, Line, Type, Arg, Flags, AlignInBits)) TempDILocalVariable clone() const { return cloneImpl(); } Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -4185,7 +4185,7 @@ /// ::= !DIGlobalVariable(scope: !0, name: "foo", linkageName: "foo", /// file: !1, line: 7, type: !2, isLocal: false, /// isDefinition: true, variable: i32* @foo, -/// declaration: !3) +/// declaration: !3, align: 8) bool LLParser::ParseDIGlobalVariable(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(name, MDStringField, (/* AllowEmpty */ false)); \ @@ -4197,22 +4197,26 @@ OPTIONAL(isLocal, MDBoolField, ); \ OPTIONAL(isDefinition, MDBoolField, (true)); \ OPTIONAL(expr, MDField, ); \ - OPTIONAL(declaration, MDField, ); + OPTIONAL(declaration, MDField, ); \ + OPTIONAL(align, MDUnsignedField, (0, UINT64_MAX)); 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, expr.Val, declaration.Val)); + isDefinition.Val, expr.Val, declaration.Val, + align.Val)); return false; } /// ParseDILocalVariable: /// ::= !DILocalVariable(arg: 7, scope: !0, name: "foo", -/// file: !1, line: 7, type: !2, arg: 2, flags: 7) +/// file: !1, line: 7, type: !2, arg: 2, flags: 7, +/// align: 8) /// ::= !DILocalVariable(scope: !0, name: "foo", -/// file: !1, line: 7, type: !2, arg: 2, flags: 7) +/// file: !1, line: 7, type: !2, arg: 2, flags: 7, +/// align: 8) bool LLParser::ParseDILocalVariable(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(scope, MDField, (/* AllowNull */ false)); \ @@ -4221,13 +4225,14 @@ OPTIONAL(file, MDField, ); \ OPTIONAL(line, LineField, ); \ OPTIONAL(type, MDField, ); \ - OPTIONAL(flags, DIFlagField, ); + OPTIONAL(flags, DIFlagField, ); \ + OPTIONAL(align, MDUnsignedField, (0, UINT64_MAX)); 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, flags.Val, align.Val)); return false; } Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -2732,7 +2732,7 @@ break; } case bitc::METADATA_GLOBAL_VAR: { - if (Record.size() != 11) + if (Record.size() < 11 || Record.size() > 12) return error("Invalid record"); IsDistinct = Record[0]; @@ -2740,6 +2740,7 @@ // Upgrade old metadata, which stored a global variable reference or a // ConstantInt here. Metadata *Expr = getMDOrNull(Record[9]); + uint64_t AlignInBits = (Record.size() > 11) ? Record[11] : 0; GlobalVariable *Attach = nullptr; if (auto *CMD = dyn_cast_or_null(Expr)) { if (auto *GV = dyn_cast(CMD->getValue())) { @@ -2759,7 +2760,7 @@ (Context, getMDOrNull(Record[1]), getMDString(Record[2]), getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], getDITypeRefOrNull(Record[6]), Record[7], Record[8], Expr, - getMDOrNull(Record[10]))); + getMDOrNull(Record[10]), AlignInBits)); MetadataList.assignValue(DGV, NextMetadataNo++); if (Attach) @@ -2769,7 +2770,7 @@ } case bitc::METADATA_LOCAL_VAR: { // 10th field is for the obseleted 'inlinedAt:' field. - if (Record.size() < 8 || Record.size() > 10) + if (Record.size() < 8 || Record.size() > 11) return error("Invalid record"); // 2nd field used to be an artificial tag, either DW_TAG_auto_variable or @@ -2777,13 +2778,15 @@ IsDistinct = Record[0]; bool HasTag = Record.size() > 8; DINode::DIFlags Flags = static_cast(Record[7 + HasTag]); + // 11th field if exists contains alignment value. + uint64_t AlignInBits = (Record.size() > 10) ? Record[10] : 0; 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], Flags, AlignInBits)), NextMetadataNo++); break; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1712,6 +1712,7 @@ Record.push_back(N->isDefinition()); Record.push_back(VE.getMetadataOrNullID(N->getRawExpr())); Record.push_back(VE.getMetadataOrNullID(N->getStaticDataMemberDeclaration())); + Record.push_back(N->getAlignInBits()); Stream.EmitRecord(bitc::METADATA_GLOBAL_VAR, Record, Abbrev); Record.clear(); @@ -1720,7 +1721,24 @@ void ModuleBitcodeWriter::writeDILocalVariable( const DILocalVariable *N, SmallVectorImpl &Record, unsigned Abbrev) { + // In order to support older bitcode formats in BitcodeReader we need to + // distiguish the following cases for "old" format: + // 1) Record has no artificial tag (Record[1]), + // has no obsolete inlignedAt field (Record[9]). + // In this case Record size will be 8. + // 2) Record has artificial tag (Record[1]), + // has no obsolete inlignedAt field (Record[9]). + // In this case Record size will be 9. + // 3) Record has both artificial tag (Record[1]) and + // obsolete inlignedAt field (Record[9]). + // In this case Record size will be 10. + // Thus if we "drop" either of DW_TAG* or inlinedAt fields, + // Record.size() will no longer allow us to detect actual format. + // We just fill in Record[1] and Record[9] with "fake" zero values + // and put any of "new" format fields in further Record members. Record.push_back(N->isDistinct()); + // Fake tag value for backwards compatibility. + Record.push_back(0); Record.push_back(VE.getMetadataOrNullID(N->getScope())); Record.push_back(VE.getMetadataOrNullID(N->getRawName())); Record.push_back(VE.getMetadataOrNullID(N->getFile())); @@ -1728,6 +1746,9 @@ Record.push_back(VE.getMetadataOrNullID(N->getType())); Record.push_back(N->getArg()); Record.push_back(N->getFlags()); + // Fake inlignedAt value for backwards compatibility. + Record.push_back(0); + Record.push_back(N->getAlignInBits()); Stream.EmitRecord(bitc::METADATA_LOCAL_VAR, Record, Abbrev); Record.clear(); Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1404,8 +1404,11 @@ addUInt(MemberDie, dwarf::DW_AT_bit_size, None, Size); uint64_t Offset = DT->getOffsetInBits(); - uint64_t Align = DT->getAlignInBits() ? DT->getAlignInBits() : FieldSize; - uint64_t AlignMask = ~(Align - 1); + // We can't use DT->getAlignInBits() here: AlignInBits for member type + // is non-zero if and only if alignment was forced (e.g. _Alignas()), + // which can't be done with bitfields. Thus we use FieldSize here. + uint64_t AlignInBits = FieldSize; + uint64_t AlignMask = ~(AlignInBits - 1); // The bits from the start of the storage unit to the start of the field. uint64_t StartBitOffset = Offset - (Offset & AlignMask); // The byte offset of the field's aligned storage unit inside the struct. Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1821,6 +1821,7 @@ Printer.printBool("isDefinition", N->isDefinition()); Printer.printMetadata("expr", N->getExpr()); Printer.printMetadata("declaration", N->getRawStaticDataMemberDeclaration()); + Printer.printInt("align", N->getAlignInBits()); Out << ")"; } @@ -1836,6 +1837,7 @@ Printer.printInt("line", N->getLine()); Printer.printMetadata("type", N->getRawType()); Printer.printDIFlags("flags", N->getFlags()); + Printer.printInt("align", N->getAlignInBits()); Out << ")"; } Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -195,11 +195,10 @@ } DIBasicType *DIBuilder::createBasicType(StringRef Name, uint64_t SizeInBits, - uint64_t AlignInBits, unsigned Encoding) { assert(!Name.empty() && "Unable to create type without name"); return DIBasicType::get(VMContext, dwarf::DW_TAG_base_type, Name, SizeInBits, - AlignInBits, Encoding); + 0, Encoding); } DIDerivedType *DIBuilder::createQualifiedType(unsigned Tag, DIType *FromTy) { @@ -277,24 +276,26 @@ DIDerivedType *DIBuilder::createBitFieldMemberType( DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, - uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, - uint64_t StorageOffsetInBits, DINode::DIFlags Flags, DIType *Ty) { + uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits, + DINode::DIFlags Flags, DIType *Ty) { Flags |= DINode::FlagBitField; return DIDerivedType::get( VMContext, dwarf::DW_TAG_member, Name, File, LineNumber, - getNonCompileUnitScope(Scope), Ty, SizeInBits, AlignInBits, OffsetInBits, - Flags, ConstantAsMetadata::get(ConstantInt::get( - IntegerType::get(VMContext, 64), StorageOffsetInBits))); + getNonCompileUnitScope(Scope), Ty, SizeInBits, /* AlignInBits */ 0, + OffsetInBits, Flags, + ConstantAsMetadata::get(ConstantInt::get(IntegerType::get(VMContext, 64), + StorageOffsetInBits))); } DIDerivedType * DIBuilder::createStaticMemberType(DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber, DIType *Ty, - DINode::DIFlags Flags, llvm::Constant *Val) { + DINode::DIFlags Flags, llvm::Constant *Val, + uint64_t AlignInBits) { 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 * @@ -535,28 +536,28 @@ DIGlobalVariable *DIBuilder::createGlobalVariable( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, DIExpression *Expr, - MDNode *Decl) { + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, + DIExpression *Expr, MDNode *Decl, uint64_t AlignInBits) { checkGlobalVariableScope(Context); auto *N = DIGlobalVariable::getDistinct( VMContext, cast_or_null(Context), Name, LinkageName, F, LineNumber, Ty, isLocalToUnit, true, Expr, - cast_or_null(Decl)); + cast_or_null(Decl), AlignInBits); AllGVs.push_back(N); return N; } DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, DIExpression *Expr, - MDNode *Decl) { + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, + DIExpression *Expr, MDNode *Decl, uint64_t AlignInBits) { checkGlobalVariableScope(Context); return DIGlobalVariable::getTemporary( VMContext, cast_or_null(Context), Name, LinkageName, F, LineNumber, Ty, isLocalToUnit, false, Expr, - cast_or_null(Decl)) + cast_or_null(Decl), AlignInBits) .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, DINode::DIFlags Flags, + uint64_t AlignInBits) { // 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, Flags, AlignInBits); 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, - DINode::DIFlags Flags) { + DINode::DIFlags Flags, + uint64_t AlignInBits) { return createLocalVariable(VMContext, PreservedVariables, Scope, Name, /* ArgNo */ 0, File, LineNo, Ty, AlwaysPreserve, - Flags); + Flags, AlignInBits); } 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, Flags, + /* AlignInBits */0); } DIExpression *DIBuilder::createExpression(ArrayRef Addr) { Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -510,16 +510,18 @@ Metadata *Type, bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, Metadata *StaticDataMemberDeclaration, + uint64_t AlignInBits, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIGlobalVariable, (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, Variable, - StaticDataMemberDeclaration)); + StaticDataMemberDeclaration, AlignInBits)); Metadata *Ops[] = {Scope, Name, File, Type, Name, LinkageName, Variable, StaticDataMemberDeclaration}; - DEFINE_GETIMPL_STORE(DIGlobalVariable, (Line, IsLocalToUnit, IsDefinition), + DEFINE_GETIMPL_STORE(DIGlobalVariable, + (Line, IsLocalToUnit, IsDefinition, AlignInBits), Ops); } @@ -527,6 +529,7 @@ MDString *Name, Metadata *File, unsigned Line, Metadata *Type, unsigned Arg, DIFlags Flags, + uint64_t AlignInBits, StorageType Storage, bool ShouldCreate) { // 64K ought to be enough for any frontend. @@ -535,9 +538,10 @@ 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, Flags, + AlignInBits)); Metadata *Ops[] = {Scope, Name, File, Type}; - DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags), Ops); + DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags, AlignInBits), Ops); } DIExpression *DIExpression::getImpl(LLVMContext &Context, Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -761,22 +761,26 @@ bool IsDefinition; Metadata *Expr; Metadata *StaticDataMemberDeclaration; + uint64_t AlignInBits; MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Expr, - Metadata *StaticDataMemberDeclaration) + bool IsLocalToUnit, bool IsDefinition, + Metadata *Expr, Metadata *StaticDataMemberDeclaration, + uint64_t AlignInBits) : Scope(Scope), Name(Name), LinkageName(LinkageName), File(File), Line(Line), Type(Type), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), Expr(Expr), - StaticDataMemberDeclaration(StaticDataMemberDeclaration) {} + StaticDataMemberDeclaration(StaticDataMemberDeclaration), + AlignInBits(AlignInBits) {} 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()), Expr(N->getRawExpr()), - StaticDataMemberDeclaration(N->getRawStaticDataMemberDeclaration()) {} + StaticDataMemberDeclaration(N->getRawStaticDataMemberDeclaration()), + AlignInBits(N->getAlignInBits()) {} bool isKeyOf(const DIGlobalVariable *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && @@ -786,11 +790,19 @@ IsDefinition == RHS->isDefinition() && Expr == RHS->getRawExpr() && StaticDataMemberDeclaration == - RHS->getRawStaticDataMemberDeclaration(); + RHS->getRawStaticDataMemberDeclaration() && + AlignInBits == RHS->getAlignInBits(); } unsigned getHashValue() const { + // We do not use AlignInBits 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, LinkageName, File, Line, Type, - IsLocalToUnit, IsDefinition, Expr, + IsLocalToUnit, IsDefinition, /* AlignInBits, */ Expr, StaticDataMemberDeclaration); } }; @@ -803,23 +815,32 @@ Metadata *Type; unsigned Arg; unsigned Flags; + uint64_t AlignInBits; MDNodeKeyImpl(Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, - Metadata *Type, unsigned Arg, unsigned Flags) + Metadata *Type, unsigned Arg, unsigned Flags, + uint64_t AlignInBits) : Scope(Scope), Name(Name), File(File), Line(Line), Type(Type), Arg(Arg), - Flags(Flags) {} + Flags(Flags), AlignInBits(AlignInBits) {} 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()) {} + Flags(N->getFlags()), AlignInBits(N->getAlignInBits()) {} 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(); + Flags == RHS->getFlags() && AlignInBits == RHS->getAlignInBits(); } unsigned getHashValue() const { + // We do not use AlignInBits 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, Flags); } }; Index: test/Assembler/diglobalvariable.ll =================================================================== --- test/Assembler/diglobalvariable.ll +++ test/Assembler/diglobalvariable.ll @@ -12,10 +12,10 @@ !3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) !4 = distinct !{} -; CHECK: !5 = !DIGlobalVariable(name: "foo", linkageName: "foo", scope: !0, file: !2, line: 7, type: !3, isLocal: true, isDefinition: false) +; CHECK: !5 = !DIGlobalVariable(name: "foo", linkageName: "foo", scope: !0, file: !2, line: 7, type: !3, isLocal: true, isDefinition: false, align: 32) !5 = !DIGlobalVariable(name: "foo", linkageName: "foo", scope: !0, file: !2, line: 7, type: !3, isLocal: true, - isDefinition: false) + isDefinition: false, align: 32) ; CHECK: !6 = !DIGlobalVariable(name: "foo", scope: !0, isLocal: false, isDefinition: true, expr: !7) ; CHECK: !7 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value) Index: test/Assembler/dilocalvariable.ll =================================================================== --- test/Assembler/dilocalvariable.ll +++ test/Assembler/dilocalvariable.ll @@ -18,11 +18,11 @@ !3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) !4 = !DILocation(scope: !0) -; CHECK: !5 = !DILocalVariable(name: "foo", arg: 3, scope: !0, file: !2, line: 7, type: !3, flags: DIFlagArtificial) +; CHECK: !5 = !DILocalVariable(name: "foo", arg: 3, scope: !0, file: !2, line: 7, type: !3, flags: DIFlagArtificial, align: 32) ; CHECK: !6 = !DILocalVariable(name: "foo", scope: !0, file: !2, line: 7, type: !3, flags: DIFlagArtificial) !5 = !DILocalVariable(name: "foo", arg: 3, scope: !0, file: !2, line: 7, type: !3, - flags: DIFlagArtificial) + flags: DIFlagArtificial, align: 32) !6 = !DILocalVariable(name: "foo", scope: !0, file: !2, line: 7, type: !3, flags: DIFlagArtificial) Index: test/Bitcode/dilocalvariable-3.9.ll =================================================================== --- /dev/null +++ test/Bitcode/dilocalvariable-3.9.ll @@ -0,0 +1,43 @@ +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +; CHECK: !9 = !DILocalVariable(name: "i", scope: !6, file: !1, line: 3, type: !10) +; CHECK: !10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) + +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" + +; Function Attrs: nounwind uwtable +define void @_Z1fv() #0 !dbg !6 { +entry: + %i = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %i, metadata !10, metadata !12), !dbg !13 + store i32 42, i32* %i, align 4, !dbg !13 + ret void, !dbg !14 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind uwtable } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.1 (http://llvm.org/git/clang.git c3709e72d22432f53f8e2f14354def31a96734fe)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "test.cpp", directory: "/tmp") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 3.9.1 (http://llvm.org/git/clang.git c3709e72d22432f53f8e2f14354def31a96734fe)"} +!6 = distinct !DISubprogram(name: "f", linkageName: "_Z1fv", scope: !7, file: !7, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!7 = !DIFile(filename: "test.cpp", directory: "/tmp") +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocalVariable(name: "i", scope: !6, file: !7, line: 3, type: !11) +!11 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!12 = !DIExpression() +!13 = !DILocation(line: 3, column: 7, scope: !6) +!14 = !DILocation(line: 4, column: 1, scope: !6) Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -1824,10 +1824,12 @@ auto *Expr2 = DIExpression::get(Context, {1, 2, 3}); DIDerivedType *StaticDataMemberDeclaration = cast(getDerivedType()); + uint64_t AlignInBits = 8; auto *N = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration); + Expr, StaticDataMemberDeclaration, + AlignInBits); EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag()); EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(Name, N->getName()); @@ -1839,45 +1841,61 @@ EXPECT_EQ(IsDefinition, N->isDefinition()); EXPECT_EQ(Expr, N->getExpr()); EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration)); + Expr, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, getSubprogram(), Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration)); + Expr, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other", LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration)); + Expr, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other", File, Line, Type, IsLocalToUnit, IsDefinition, Expr, - StaticDataMemberDeclaration)); + StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, getFile(), Line, Type, IsLocalToUnit, IsDefinition, Expr, - StaticDataMemberDeclaration)); + StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line + 1, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration)); + Expr, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, getDerivedType(), IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration)); + Expr, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, !IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration)); + Expr, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, !IsDefinition, - Expr, StaticDataMemberDeclaration)); + Expr, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr2, StaticDataMemberDeclaration)); + Expr2, StaticDataMemberDeclaration, + AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, Expr, - cast(getDerivedType()))); + cast(getDerivedType()), + AlignInBits)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + Expr, StaticDataMemberDeclaration, + (AlignInBits << 1))); TempDIGlobalVariable Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1893,9 +1911,11 @@ DIType *Type = getDerivedType(); unsigned Arg = 6; DINode::DIFlags Flags = static_cast(7); + uint64_t AlignInBits = 8; auto *N = - DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags); + DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags, + AlignInBits); EXPECT_TRUE(N->isParameter()); EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(Name, N->getName()); @@ -1904,24 +1924,27 @@ EXPECT_EQ(Type, N->getType()); EXPECT_EQ(Arg, N->getArg()); EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); EXPECT_EQ(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, - Flags)); + Flags, AlignInBits)); EXPECT_FALSE( - DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, Flags) - ->isParameter()); + DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, Flags, + AlignInBits)->isParameter()); EXPECT_NE(N, DILocalVariable::get(Context, getSubprogram(), Name, File, Line, - Type, Arg, Flags)); + Type, Arg, Flags, AlignInBits)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, "other", File, Line, Type, - Arg, Flags)); + Arg, Flags, AlignInBits)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, getFile(), Line, Type, - Arg, Flags)); + Arg, Flags, AlignInBits)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line + 1, Type, - Arg, Flags)); + Arg, Flags, AlignInBits)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, - getDerivedType(), Arg, Flags)); + getDerivedType(), Arg, Flags, AlignInBits)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, + Arg + 1, Flags, AlignInBits)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, - Arg + 1, Flags)); + Arg, Flags, (AlignInBits << 1))); TempDILocalVariable Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1929,17 +1952,17 @@ TEST_F(DILocalVariableTest, getArg256) { EXPECT_EQ(255u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, 255, DINode::FlagZero) + 0, nullptr, 255, DINode::FlagZero, 0) ->getArg()); EXPECT_EQ(256u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, 256, DINode::FlagZero) + 0, nullptr, 256, DINode::FlagZero, 0) ->getArg()); EXPECT_EQ(257u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, 257, DINode::FlagZero) + 0, nullptr, 257, DINode::FlagZero, 0) ->getArg()); unsigned Max = UINT16_MAX; EXPECT_EQ(Max, DILocalVariable::get(Context, getSubprogram(), "", getFile(), - 0, nullptr, Max, DINode::FlagZero) + 0, nullptr, Max, DINode::FlagZero, 0) ->getArg()); } Index: unittests/Transforms/Utils/Cloning.cpp =================================================================== --- unittests/Transforms/Utils/Cloning.cpp +++ unittests/Transforms/Utils/Cloning.cpp @@ -253,8 +253,7 @@ Instruction* Terminator = IBuilder.CreateRetVoid(); // Create a local variable around the alloca - auto *IntType = - DBuilder.createBasicType("int", 32, 0, dwarf::DW_ATE_signed); + auto *IntType = DBuilder.createBasicType("int", 32, dwarf::DW_ATE_signed); auto *E = DBuilder.createExpression(); auto *Variable = DBuilder.createAutoVariable(Subprogram, "x", File, 5, IntType, true);