Index: llvm/include/llvm-c/DebugInfo.h =================================================================== --- llvm/include/llvm-c/DebugInfo.h +++ llvm/include/llvm-c/DebugInfo.h @@ -162,6 +162,7 @@ LLVMDICommonBlockMetadataKind, LLVMDIStringTypeMetadataKind, LLVMDIGenericSubrangeMetadataKind, + LLVMDISubrangeTypeMetadataKind, LLVMDIArgListMetadataKind }; typedef unsigned LLVMMetadataKind; Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -346,7 +346,8 @@ // info. METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...] METADATA_GENERIC_SUBRANGE = 45, // [distinct, count, lo, up, stride] - METADATA_ARG_LIST = 46 // [n x [type num, value num]] + METADATA_ARG_LIST = 46, // [n x [type num, value num]] + METADATA_SUBRANGE_TYPE = 47 // [distinct, scope, name, file, type, count, lo] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -623,6 +623,13 @@ DIGenericSubrange::BoundType UpperBound, DIGenericSubrange::BoundType Stride); + DISubrangeType *getSubrange(DIScope *Scope, StringRef Name, DIFile *File, + DIType *BaseTy, int64_t LowerBound, + int64_t Count); + DISubrangeType *getSubrange(DIScope *Scope, StringRef Name, DIFile *File, + DIType *BaseTy, DIExpression *LowerBound, + DIExpression *Count); + /// Create a new descriptor for the specified variable. /// \param Context Variable scope. /// \param Name Name of the variable. Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -211,6 +211,7 @@ case DIImportedEntityKind: case DIModuleKind: case DIGenericSubrangeKind: + case DISubrangeTypeKind: return true; } } @@ -518,6 +519,7 @@ case DINamespaceKind: case DICommonBlockKind: case DIModuleKind: + case DISubrangeTypeKind: return true; } } @@ -757,6 +759,7 @@ case DIDerivedTypeKind: case DICompositeTypeKind: case DISubroutineTypeKind: + case DISubrangeTypeKind: return true; } } @@ -2940,6 +2943,121 @@ static bool isEqual(const FragInfo &A, const FragInfo &B) { return A == B; } }; +class DISubrangeType : public DIType { + friend class LLVMContextImpl; + friend class MDNode; + + DISubrangeType(LLVMContext &C, StorageType Storage, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, + ArrayRef Ops) + : DIType(C, DISubrangeTypeKind, Storage, dwarf::DW_TAG_subrange_type, 0, + SizeInBits, AlignInBits, OffsetInBits, FlagZero, Ops) {} + ~DISubrangeType() = default; + + static DISubrangeType *getImpl(LLVMContext &Context, StringRef Name, + DIFile *File, DIScope *Scope, DIType *BaseType, + uint64_t SizeInBits, uint32_t AlignInBits, + uint64_t OffsetInBits, int64_t Count, + int64_t LowerBound, StorageType Storage, + bool ShouldCreate = true); + + static DISubrangeType *getImpl(LLVMContext &Context, StringRef Name, + DIFile *File, DIScope *Scope, DIType *BaseType, + uint64_t SizeInBits, uint32_t AlignInBits, + uint64_t OffsetInBits, Metadata *Count, + Metadata *LowerBound, StorageType Storage, + bool ShouldCreate = true) { + return getImpl(Context, getCanonicalMDString(Context, Name), File, Scope, + BaseType, SizeInBits, AlignInBits, OffsetInBits, Count, + LowerBound, Storage, ShouldCreate); + } + static DISubrangeType *getImpl(LLVMContext &Context, MDString *Name, + Metadata *File, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, + Metadata *Count, Metadata *LowerBound, + StorageType Storage, bool ShouldCreate = true); + static DISubrangeType *getImpl(LLVMContext &Context, MDString *Name, + Metadata *File, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, + int64_t Count, int64_t LowerBound, + StorageType Storage, bool ShouldCreate = true); + + TempDISubrangeType cloneImpl() const { + return getTemporary(getContext(), getName(), getFile(), getScope(), + getBaseType(), getSizeInBits(), getAlignInBits(), + getOffsetInBits(), getRawCountNode(), getRawLowNode()); + } + +public: + DEFINE_MDNODE_GET(DISubrangeType, + (MDString * Name, Metadata *File, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, int64_t Count, + int64_t LowerBound), + (Name, File, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Count, LowerBound)) + + DEFINE_MDNODE_GET(DISubrangeType, + (MDString * Name, Metadata *File, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, + Metadata *Count, Metadata *LowerBound), + (Name, File, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Count, LowerBound)) + + DEFINE_MDNODE_GET(DISubrangeType, + (StringRef Name, DIFile *File, DIScope *Scope, + DIType *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, + Metadata *Count, Metadata *LowerBound), + (Name, File, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Count, LowerBound)) + + DEFINE_MDNODE_GET(DISubrangeType, + (StringRef Name, DIFile *File, DIScope *Scope, + DIType *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, int64_t Count, + int64_t LowerBound), + (Name, File, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Count, LowerBound)) + + TempDISubrangeType clone() const { return cloneImpl(); } + + /// Get the base type this is derived from. + DIType *getBaseType() const { return (DIType *)(getRawBaseType()); } + Metadata *getRawBaseType() const { return getOperand(3); } + + Metadata *getRawCountNode() const { return getOperand(4).get(); } + Metadata *getRawLowNode() const { return getOperand(5).get(); } + typedef PointerUnion CountType; + + CountType getCount() const { + if (auto *MD = dyn_cast(getRawCountNode())) + return CountType(cast(MD->getValue())); + + if (auto *DV = dyn_cast(getRawCountNode())) + return CountType(DV); + + return CountType(); + } + + CountType getLowerBound() const { + if (auto *MD = dyn_cast(getRawLowNode())) + return CountType(cast(MD->getValue())); + + if (auto *DV = dyn_cast(getRawLowNode())) + return CountType(DV); + + return CountType(); + } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DISubrangeTypeKind; + } +}; + /// Global variables. /// /// TODO: Remove DisplayName. It's always equal to Name. @@ -3053,8 +3171,8 @@ } static DICommonBlock *getImpl(LLVMContext &Context, Metadata *Scope, Metadata *Decl, MDString *Name, Metadata *File, - unsigned LineNo, - StorageType Storage, bool ShouldCreate = true); + unsigned LineNo, StorageType Storage, + bool ShouldCreate = true); TempDICommonBlock cloneImpl() const { return getTemporary(getContext(), getScope(), getDecl(), getName(), Index: llvm/include/llvm/IR/Metadata.def =================================================================== --- llvm/include/llvm/IR/Metadata.def +++ llvm/include/llvm/IR/Metadata.def @@ -117,6 +117,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIArgList) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGenericSubrange) +HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DISubrangeType) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -4465,6 +4465,42 @@ return false; } +/// ParseDISubrangeType: +/// ::= !DISubrangeType(lowerBound: 2, count: 7) +/// ::= !DISubrangeType(lowerBound: !expr, count: !expr) +bool LLParser::parseDISubrangeType(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(name, MDStringField, ); \ + REQUIRED(file, MDField, ); \ + OPTIONAL(scope, MDField, ); \ + REQUIRED(baseType, MDField, ); \ + OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \ + OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \ + OPTIONAL(offset, MDUnsignedField, (0, UINT64_MAX)); \ + REQUIRED(count, MDSignedOrMDField, ); \ + REQUIRED(lowerBound, MDSignedOrMDField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + if (count.isMDSignedField() && lowerBound.isMDSignedField()) + + Result = + GET_OR_DISTINCT(DISubrangeType, (Context, name.Val, file.Val, scope.Val, + baseType.Val, size.Val, align.Val, + offset.Val, count.getMDSignedValue(), + lowerBound.getMDSignedValue())); + + else if (count.isMDField() && lowerBound.isMDField()) + + Result = + GET_OR_DISTINCT(DISubrangeType, (Context, name.Val, file.Val, scope.Val, + baseType.Val, size.Val, align.Val, + offset.Val, count.getMDFieldValue(), + lowerBound.getMDFieldValue())); + + return false; +} + /// parseDIEnumerator: /// ::= !DIEnumerator(value: 30, isUnsigned: true, name: "SomeKind") bool LLParser::parseDIEnumerator(MDNode *&Result, bool IsDistinct) { Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -875,6 +875,7 @@ case bitc::METADATA_IMPORTED_ENTITY: case bitc::METADATA_GLOBAL_VAR_EXPR: case bitc::METADATA_GENERIC_SUBRANGE: + case bitc::METADATA_SUBRANGE_TYPE: // We don't expect to see any of these, if we see one, give up on // lazy-loading and fallback. MDStringRef.clear(); @@ -1383,6 +1384,28 @@ NextMetadataNo++; break; } + case bitc::METADATA_SUBRANGE_TYPE: { + if (Record.size() != 10) + return error("Invalid record"); + + IsDistinct = Record[0]; + MetadataList.assignValue( + GET_OR_DISTINCT(DISubrangeType, + (Context, + getMDString(Record[1]), // name + getMDOrNull(Record[2]), // file + getDITypeRefOrNull(Record[3]), // scope + getDITypeRefOrNull(Record[4]), // baseteype + Record[5], // size + Record[6], // align + Record[7], // offset + getDITypeRefOrNull(Record[8]), // count + getDITypeRefOrNull(Record[9]) // low + )), + NextMetadataNo); + NextMetadataNo++; + break; + } case bitc::METADATA_ENUMERATOR: { if (Record.size() < 3) return error("Invalid record"); Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -302,6 +302,8 @@ void writeDIGenericSubrange(const DIGenericSubrange *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDISubrangeType(const DISubrangeType *N, + SmallVectorImpl &Record, unsigned Abbrev); void writeDIEnumerator(const DIEnumerator *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIBasicType(const DIBasicType *N, SmallVectorImpl &Record, @@ -1602,6 +1604,24 @@ Record.clear(); } +void ModuleBitcodeWriter::writeDISubrangeType(const DISubrangeType *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getBaseType())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getOffsetInBits()); + Record.push_back(VE.getMetadataOrNullID(N->getRawCountNode())); + Record.push_back(VE.getMetadataOrNullID(N->getRawLowNode())); + + Stream.EmitRecord(bitc::METADATA_SUBRANGE_TYPE, Record, Abbrev); + Record.clear(); +} + static void emitSignedInt64(SmallVectorImpl &Vals, uint64_t V) { if ((int64_t)V >= 0) Vals.push_back(V << 1); Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -321,6 +321,8 @@ void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy); void constructGenericSubrangeDIE(DIE &Buffer, const DIGenericSubrange *SR, DIE *IndexTy); + void constructTypeDIE(DIE &Buffer, const DISubrangeType *SR); + void addDieExpr(DIE &Buffer, DIExpression *Expr, dwarf::Attribute attr); void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy); void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy); DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT); Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -579,6 +579,8 @@ constructTypeDIE(TyDIE, ST); else if (auto *STy = dyn_cast(Ty)) constructTypeDIE(TyDIE, STy); + else if (auto *SRTy = dyn_cast(Ty)) + constructTypeDIE(TyDIE, SRTy); else if (auto *CTy = dyn_cast(Ty)) { if (DD->generateTypeUnits() && !Ty->isForwardDecl() && (Ty->getRawName() || CTy->getRawIdentifier())) { @@ -1014,6 +1016,39 @@ } } +void DwarfUnit::constructTypeDIE(DIE &Buffer, const DISubrangeType *SR) { + addType(Buffer, SR->getBaseType()); + StringRef Name = SR->getName(); + addString(Buffer, dwarf::DW_AT_name, Name); + + int64_t LowerBound = 0; + int64_t Count = 0; + + if (auto *CI = SR->getLowerBound().dyn_cast()) { + LowerBound = CI->getSExtValue(); + addUInt(Buffer, dwarf::DW_AT_lower_bound, None, LowerBound); + } else if (auto *Expr = SR->getLowerBound().dyn_cast()) { + addDieExpr(Buffer, Expr, dwarf::DW_AT_lower_bound); + } + + if (auto *CI = SR->getCount().dyn_cast()) { + Count = CI->getSExtValue(); + addUInt(Buffer, dwarf::DW_AT_count, None, Count); + } else if (auto *Expr = SR->getCount().dyn_cast()) { + addDieExpr(Buffer, Expr, dwarf::DW_AT_count); + } +} + +void DwarfUnit::addDieExpr(DIE &Buffer, DIExpression *Expr, + dwarf::Attribute attr) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DwarfCompileUnit *DCU = static_cast(this); + DIEDwarfExpression DwarfExpr(*Asm, *DCU, *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(Expr); + addBlock(Buffer, attr, DwarfExpr.finalize()); +} + void DwarfUnit::constructTemplateTypeParameterDIE( DIE &Buffer, const DITemplateTypeParameter *TP) { DIE &ParamDIE = @@ -1510,7 +1545,10 @@ DINodeArray Elements = CTy->getElements(); for (DINode *E : Elements) { // FIXME: Should this really be such a loose cast? - if (auto *Element = dyn_cast_or_null(E)) { + if (auto *SRTy = dyn_cast(E)) { + DIE &DW_Subrange = createAndAddDIE(dwarf::DW_TAG_subrange_type, Buffer); + constructTypeDIE(DW_Subrange, SRTy); + } else if (auto *Element = dyn_cast_or_null(E)) { if (Element->getTag() == dwarf::DW_TAG_subrange_type) constructSubrangeDIE(Buffer, cast(Element), IdxTy); else if (Element->getTag() == dwarf::DW_TAG_generic_subrange) Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -1975,6 +1975,36 @@ Out << ")"; } +static void writeDISubrangeType(raw_ostream &Out, const DISubrangeType *N, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!DISubrangeType("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + + Printer.printString("name", N->getName()); + Printer.printMetadata("scope", N->getRawScope()); + Printer.printMetadata("file", N->getRawFile()); + Printer.printInt("line", N->getLine()); + Printer.printMetadata("baseType", N->getRawBaseType(), + /* ShouldSkipNull */ false); + Printer.printInt("size", N->getSizeInBits()); + Printer.printInt("align", N->getAlignInBits()); + Printer.printInt("offset", N->getOffsetInBits()); + + if (auto *CE = N->getCount().dyn_cast()) + Printer.printInt("count", CE->getSExtValue(), false); + else + Printer.printMetadata("count", N->getCount().dyn_cast(), + false); + + if (auto *LB = N->getLowerBound().dyn_cast()) + Printer.printInt("lowerBound", LB->getSExtValue(), false); + else + Printer.printMetadata("lowerBound", + N->getLowerBound().dyn_cast(), false); + Out << ")"; +} + static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N, TypePrinting *, SlotTracker *, const Module *) { Out << "!DIEnumerator("; Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -693,6 +693,23 @@ ConvToMetadata(Stride)); } +DISubrangeType *DIBuilder::getSubrange(DIScope *Scope, StringRef Name, + DIFile *File, DIType *BaseTy, + int64_t LowerBound, int64_t Count) { + return DISubrangeType::get(VMContext, Name, File, + getNonCompileUnitScope(Scope), BaseTy, 0, 0, 0, + Count, LowerBound); +} + +DISubrangeType *DIBuilder::getSubrange(DIScope *Scope, StringRef Name, + DIFile *File, DIType *BaseTy, + DIExpression *LowerBound, + DIExpression *Count) { + return DISubrangeType::get(VMContext, Name, File, + getNonCompileUnitScope(Scope), BaseTy, 0, 0, 0, + Count, LowerBound); +} + static void checkGlobalVariableScope(DIScope *Context) { #ifndef NDEBUG if (auto *CT = Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -528,6 +528,53 @@ return BoundType(); } +DISubrangeType *DISubrangeType::getImpl(LLVMContext &Context, MDString *Name, + Metadata *File, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, + uint64_t OffsetInBits, int64_t Count, + int64_t LowerBound, StorageType Storage, + bool ShouldCreate) { + auto *Lower = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), LowerBound)); + auto *ValueCount = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), Count)); + + return getImpl(Context, Name, File, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, ValueCount, Lower, Storage, ShouldCreate); +} + +DISubrangeType *DISubrangeType::getImpl(LLVMContext &Context, StringRef Name, + DIFile *File, DIScope *Scope, + DIType *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, + uint64_t OffsetInBits, int64_t Count, + int64_t LowerBound, StorageType Storage, + bool ShouldCreate) { + + auto *Lower = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), LowerBound)); + auto *ValueCount = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), Count)); + + return getImpl(Context, Name, File, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, ValueCount, Lower, Storage, ShouldCreate); +} + +DISubrangeType *DISubrangeType::getImpl( + LLVMContext &Context, MDString *Name, Metadata *File, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, + uint64_t OffsetInBits, Metadata *Count, Metadata *LowerBound, + StorageType Storage, bool ShouldCreate) { + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DISubrangeType, + (Name, File, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Count, LowerBound)); + Metadata *Ops[] = {File, Scope, Name, BaseType, Count, LowerBound}; + DEFINE_GETIMPL_STORE(DISubrangeType, (SizeInBits, AlignInBits, OffsetInBits), + Ops); +} + DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, const APInt &Value, bool IsUnsigned, MDString *Name, StorageType Storage, bool ShouldCreate) { Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -376,6 +376,45 @@ } }; +template <> struct MDNodeKeyImpl { + MDString *Name; + Metadata *File; + Metadata *Scope; + Metadata *BaseType; + uint64_t SizeInBits; + uint64_t OffsetInBits; + uint32_t AlignInBits; + Metadata *CountNode; + Metadata *LowNode; + + MDNodeKeyImpl(MDString *Name, Metadata *File, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, + uint64_t OffsetInBits, Metadata *CountNode, Metadata *LowNode) + : Name(Name), File(File), Scope(Scope), BaseType(BaseType), + SizeInBits(SizeInBits), OffsetInBits(OffsetInBits), + AlignInBits(AlignInBits), CountNode(CountNode), LowNode(LowNode) {} + + MDNodeKeyImpl(const DISubrangeType *N) + : Name(N->getRawName()), File(N->getRawFile()), Scope(N->getRawScope()), + BaseType(N->getRawBaseType()), SizeInBits(N->getSizeInBits()), + OffsetInBits(N->getOffsetInBits()), AlignInBits(N->getAlignInBits()), + CountNode(N->getRawCountNode()), LowNode(N->getRawLowNode()) {} + + bool isKeyOf(const DISubrangeType *RHS) const { + return Name == RHS->getRawName() && File == RHS->getRawFile() && + Scope == RHS->getRawScope() && BaseType == RHS->getRawBaseType() && + SizeInBits == RHS->getSizeInBits() && + AlignInBits == RHS->getAlignInBits() && + OffsetInBits == RHS->getOffsetInBits() && + CountNode == RHS->getRawCountNode() && + LowNode == RHS->getRawLowNode(); + } + + unsigned getHashValue() const { + return hash_combine(Name, File, Scope, BaseType, CountNode, LowNode); + } +}; + template <> struct MDNodeKeyImpl { APInt Value; MDString *Name; Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -1000,6 +1000,34 @@ "Stride must be signed constant or DIVariable or DIExpression", &N); } +void Verifier::visitDISubrangeType(const DISubrangeType &N) { + AssertDI(N.getTag() == dwarf::DW_TAG_subrange_type, "Invalid tag", &N); + auto *RawCount = N.getRawCountNode(); + AssertDI(!RawCount || isa(RawCount) || + isa(RawCount), + "Count must either be a signed constant or a DIExpression", &N); + auto *RawLB = N.getRawLowNode(); + AssertDI(!RawLB || isa(RawLB) || isa(RawLB), + "LowerBound must either be a signed constant or a DIExpression", &N); + auto Count = N.getCount(); + + AssertDI(!Count || !Count.is() || + Count.get()->getSExtValue() >= -1, + "Invalid subrange count", &N); + if (auto *T = N.getRawBaseType()) { + auto *Enum = dyn_cast_or_null(T); + auto *Basic = dyn_cast_or_null(T); + AssertDI( + (Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type) || + (Basic && (Basic->getEncoding() == dwarf::DW_ATE_unsigned || + Basic->getEncoding() == dwarf::DW_ATE_signed || + Basic->getEncoding() == dwarf::DW_ATE_unsigned_char || + Basic->getEncoding() == dwarf::DW_ATE_signed_char || + Basic->getEncoding() == dwarf::DW_ATE_boolean)), + "Invalid subrange base type", &N, T); + } +} + void Verifier::visitDIEnumerator(const DIEnumerator &N) { AssertDI(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N); } @@ -1044,8 +1072,10 @@ if (auto *T = N.getRawBaseType()) { auto *Enum = dyn_cast_or_null(T); auto *Basic = dyn_cast_or_null(T); + auto *Subrange = dyn_cast_or_null(T); AssertDI( (Enum && Enum->getTag() == dwarf::DW_TAG_enumeration_type) || + (Subrange && Subrange->getTag() == dwarf::DW_TAG_subrange_type) || (Basic && (Basic->getEncoding() == dwarf::DW_ATE_unsigned || Basic->getEncoding() == dwarf::DW_ATE_signed || Basic->getEncoding() == dwarf::DW_ATE_unsigned_char || Index: llvm/test/DebugInfo/X86/subrange.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/subrange.ll @@ -0,0 +1,413 @@ +; Test subrange representation in DWARF debug info: + +; RUN: llc -debugger-tune=gdb -dwarf-version=4 -filetype=obj -o %t.o < %s +; RUN: llvm-dwarfdump -debug-info %t.o | FileCheck %s --check-prefix=CHECK + +; ModuleID = 'Main.mb' +source_filename = "../src/Main.m3" +target datalayout = "e-m:e-p:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-linux-gnu" + +%M_Const_struct = type { [7 x i8], [1 x i8], [4 x i8], [4 x i8], i8* (i64)*, i8*, void ()*, i8*, [8 x i8], [14 x i8], [1 x i8], i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, [7 x i8], [1 x i8], i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, [7 x i8], [4 x i8] } +%M_Main_struct = type { i8*, i8*, i8*, [16 x i8], i8*, [24 x i8], i8*, [8 x i8], i8* (i64)*, i64, [8 x i8], i64, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, [1 x i8], i8, [4 x i8], i64, i8*, [8 x i8], i8*, void (i8*)*, [8 x i8], i8*, i8*, i64, i64, [8 x i8], i64, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, [1 x i8], i8, [4 x i8], i64, i8*, [8 x i8], i8*, void (i8*)*, [8 x i8], i8*, [8 x i8], i64, i64, [8 x i8], i8* ()*, i8*, [8 x i8], i8* ()*, [8 x i8], i8*, i64, [8 x i8], i64 } +%struct.0 = type { [24 x i8] } +%struct.1 = type { [32 x i8] } + +@M_Const = internal constant %M_Const_struct { [7 x i8] c"Main_M3", [1 x i8] zeroinitializer, [4 x i8] c"Test", [4 x i8] zeroinitializer, i8* (i64)* @Main_M3, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), void ()* @Main__Test, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 8), [8 x i8] zeroinitializer, [14 x i8] c"../src/Main.m3", [1 x i8] zeroinitializer, i8 24, i8 2, i8 16, i8 0, i8 0, i8 2, i8 13, i8 2, i8 21, i8 3, i8 55, [7 x i8] c"Main.BR", [1 x i8] zeroinitializer, i8 24, i8 1, i8 16, i8 0, i8 0, i8 2, i8 13, i8 1, i8 21, i8 3, i8 55, [7 x i8] c"Main.AR", [4 x i8] zeroinitializer }, align 8 +@M_Main = internal global %M_Main_struct { i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 56), i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 104), i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 376), [16 x i8] zeroinitializer, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 16), [24 x i8] zeroinitializer, i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 328), [8 x i8] zeroinitializer, i8* (i64)* @Main_M3, i64 3, [8 x i8] zeroinitializer, i64 1942303576, i8 47, i8 -118, i8 77, i8 115, i8 119, i8 -71, i8 -120, i8 0, i8 1, i8 3, [1 x i8] zeroinitializer, i8 8, [4 x i8] zeroinitializer, i64 16, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 90), [8 x i8] zeroinitializer, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 95), void (i8*)* @Main_M3_t73c53358_INIT, [8 x i8] zeroinitializer, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 101), i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 216), i64 1, i64 1, [8 x i8] zeroinitializer, i64 -166887669, i8 -123, i8 7, i8 70, i8 -12, i8 -114, i8 120, i8 75, i8 2, i8 1, i8 3, [1 x i8] zeroinitializer, i8 8, [4 x i8] zeroinitializer, i64 24, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 71), [8 x i8] zeroinitializer, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 76), void (i8*)* @Main_M3_tf60d7f0b_INIT, [8 x i8] zeroinitializer, i8* getelementptr inbounds (i8, i8* getelementptr inbounds (%M_Const_struct, %M_Const_struct* @M_Const, i32 0, i32 0, i32 0), i64 82), [8 x i8] zeroinitializer, i64 2, i64 1, [8 x i8] zeroinitializer, i8* ()* @Main_I3, i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 352), [8 x i8] zeroinitializer, i8* ()* @RTHooks_I3, [8 x i8] zeroinitializer, i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 392), i64 1942303576, [8 x i8] zeroinitializer, i64 -166887669 }, align 8 +@m3_jmpbuf_size = external global i64, align 8 + +declare i8* @Main_I3() + +declare i8* @RTHooks_I3() + +; Function Attrs: uwtable +define void @Main__Test() #0 !dbg !17 { +entry: + %x = alloca i8, align 1 + %y = alloca i8, align 1 + %z = alloca i8, align 1 + %l = alloca i32, align 4 + %ch = alloca i8, align 1 + %ar = alloca i8*, align 8 + %br = alloca i8*, align 8 + %tmp.15 = alloca %struct.0, align 8 + %tmp.18 = alloca i8*, align 8 + %tmp.19 = alloca %struct.1, align 8 + br label %second, !dbg !21 + +second: ; preds = %entry + call void @llvm.dbg.declare(metadata i8* %x, metadata !22, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i8* %y, metadata !26, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i8* %z, metadata !28, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i32* %l, metadata !31, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i8* %ch, metadata !34, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i8** %ar, metadata !37, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i8** %br, metadata !43, metadata !DIExpression()), !dbg !25 + store i8* null, i8** %ar, align 8, !dbg !51 + store i8* null, i8** %br, align 8, !dbg !52 + store i8 35, i8* %x, align 1, !dbg !53 + store i8 3, i8* %y, align 1, !dbg !54 + store i8 -1, i8* %z, align 1, !dbg !55 + store i32 9999, i32* %l, align 4, !dbg !56 + store i8 70, i8* %ch, align 1, !dbg !57 + %gep_cast = bitcast %struct.0* %tmp.15 to i8*, !dbg !58 + %0 = getelementptr inbounds i8, i8* %gep_cast, i64 16, !dbg !58 + %store_destptr = bitcast %struct.0* %tmp.15 to i8**, !dbg !58 + store i8* %0, i8** %store_destptr, align 8, !dbg !58 + %store_base.i8p = bitcast %struct.0* %tmp.15 to i8*, !dbg !58 + %store_dest.i8p = getelementptr inbounds i8, i8* %store_base.i8p, i64 8, !dbg !58 + %store_dest = bitcast i8* %store_dest.i8p to i64*, !dbg !58 + store i64 1, i64* %store_dest, align 8, !dbg !58 + %store_base.i8p1 = bitcast %struct.0* %tmp.15 to i8*, !dbg !58 + %store_dest.i8p2 = getelementptr inbounds i8, i8* %store_base.i8p1, i64 16, !dbg !58 + %store_dest3 = bitcast i8* %store_dest.i8p2 to i64*, !dbg !58 + store i64 50, i64* %store_dest3, align 8, !dbg !58 + %v.2 = load i8*, i8** bitcast (i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 376) to i8**), align 8, !dbg !58 + %pop_toadr = bitcast %struct.0* %tmp.15 to i8*, !dbg !58 + %result = call i8* @RTHooks__AllocateOpenArray(i8* %v.2, i8* %pop_toadr), !dbg !58 + store i8* %result, i8** %tmp.18, align 8, !dbg !58 + %v.18 = load i8*, i8** %tmp.18, align 8, !dbg !58 + store i8* %v.18, i8** %ar, align 8, !dbg !58 + %gep_cast4 = bitcast %struct.1* %tmp.19 to i8*, !dbg !59 + %1 = getelementptr inbounds i8, i8* %gep_cast4, i64 16, !dbg !59 + %store_destptr5 = bitcast %struct.1* %tmp.19 to i8**, !dbg !59 + store i8* %1, i8** %store_destptr5, align 8, !dbg !59 + %store_base.i8p6 = bitcast %struct.1* %tmp.19 to i8*, !dbg !59 + %store_dest.i8p7 = getelementptr inbounds i8, i8* %store_base.i8p6, i64 8, !dbg !59 + %store_dest8 = bitcast i8* %store_dest.i8p7 to i64*, !dbg !59 + store i64 2, i64* %store_dest8, align 8, !dbg !59 + %store_base.i8p9 = bitcast %struct.1* %tmp.19 to i8*, !dbg !59 + %store_dest.i8p10 = getelementptr inbounds i8, i8* %store_base.i8p9, i64 16, !dbg !59 + %store_dest11 = bitcast i8* %store_dest.i8p10 to i64*, !dbg !59 + store i64 50, i64* %store_dest11, align 8, !dbg !59 + %store_base.i8p12 = bitcast %struct.1* %tmp.19 to i8*, !dbg !59 + %store_dest.i8p13 = getelementptr inbounds i8, i8* %store_base.i8p12, i64 24, !dbg !59 + %store_dest14 = bitcast i8* %store_dest.i8p13 to i64*, !dbg !59 + store i64 50, i64* %store_dest14, align 8, !dbg !59 + %v.215 = load i8*, i8** bitcast (i8* getelementptr inbounds (i8, i8* bitcast (%M_Main_struct* @M_Main to i8*), i64 392) to i8**), align 8, !dbg !59 + %pop_toadr16 = bitcast %struct.1* %tmp.19 to i8*, !dbg !59 + %result17 = call i8* @RTHooks__AllocateOpenArray(i8* %v.215, i8* %pop_toadr16), !dbg !59 + store i8* %result17, i8** %tmp.18, align 8, !dbg !59 + %v.1818 = load i8*, i8** %tmp.18, align 8, !dbg !59 + store i8* %v.1818, i8** %br, align 8, !dbg !59 + ret void, !dbg !21 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +declare i8* @alloca() + +; Function Attrs: uwtable +declare i8* @RTHooks__AllocateOpenArray(i8*, i8*) #0 + +; Function Attrs: uwtable +define i8* @Main_M3(i64 %mode) #0 !dbg !60 { +entry: + %mode1 = alloca i64, align 8 + store i64 %mode, i64* %mode1, align 8 + br label %second, !dbg !65 + +second: ; preds = %entry + call void @llvm.dbg.declare(metadata i64* %mode1, metadata !66, metadata !DIExpression()), !dbg !67 + %v.3 = load i64, i64* %mode1, align 8, !dbg !67 + %icmp = icmp eq i64 %v.3, 0, !dbg !67 + br i1 %icmp, label %if_1, label %else_1, !dbg !67 + +else_1: ; preds = %second + call void @Main__Test(), !dbg !65 + br label %if_1, !dbg !65 + +if_1: ; preds = %else_1, %second + ret i8* bitcast (%M_Main_struct* @M_Main to i8*), !dbg !65 +} + +; Function Attrs: uwtable +define void @Main_M3_tf60d7f0b_INIT(i8* %Main_M3_tf60d7f0b_INIT__AnonFormal_0) #0 !dbg !68 { +entry: + %Main_M3_tf60d7f0b_INIT__AnonFormal_01 = alloca i8*, align 8 + store i8* %Main_M3_tf60d7f0b_INIT__AnonFormal_0, i8** %Main_M3_tf60d7f0b_INIT__AnonFormal_01, align 8 + %tmp.23 = alloca i64, align 8 + %tmp.24 = alloca i8*, align 8 + %tmp.25 = alloca i64, align 8 + %tmp.26 = alloca i64, align 8 + %tmp.27 = alloca i8*, align 8 + br label %second, !dbg !71 + +second: ; preds = %entry + call void @llvm.dbg.declare(metadata i8** %Main_M3_tf60d7f0b_INIT__AnonFormal_01, metadata !72, metadata !DIExpression()), !dbg !71 + %v.21 = load i8*, i8** %Main_M3_tf60d7f0b_INIT__AnonFormal_01, align 8, !dbg !71 + %0 = getelementptr inbounds i8, i8* %v.21, i64 8, !dbg !71 + %loadind_ptr = bitcast i8* %0 to i64*, !dbg !71 + %loadind = load i64, i64* %loadind_ptr, align 8, !dbg !71 + %v.212 = load i8*, i8** %Main_M3_tf60d7f0b_INIT__AnonFormal_01, align 8, !dbg !71 + %1 = getelementptr inbounds i8, i8* %v.212, i64 16, !dbg !71 + %loadind_ptr3 = bitcast i8* %1 to i64*, !dbg !71 + %loadind4 = load i64, i64* %loadind_ptr3, align 8, !dbg !71 + %umul = mul nuw i64 %loadind, %loadind4, !dbg !71 + store i64 %umul, i64* %tmp.23, align 8, !dbg !71 + %v.215 = load i8*, i8** %Main_M3_tf60d7f0b_INIT__AnonFormal_01, align 8, !dbg !71 + %loadind_ptr6 = bitcast i8* %v.215 to i8**, !dbg !71 + %loadind7 = load i8*, i8** %loadind_ptr6, align 8, !dbg !71 + store i8* %loadind7, i8** %tmp.24, align 8, !dbg !71 + store i64 0, i64* %tmp.25, align 8, !dbg !71 + br label %label_2, !dbg !71 + +label_3: ; preds = %label_2 + %v.25 = load i64, i64* %tmp.25, align 8, !dbg !71 + store i64 %v.25, i64* %tmp.26, align 8, !dbg !71 + %v.24 = load i8*, i8** %tmp.24, align 8, !dbg !71 + %v.26 = load i64, i64* %tmp.26, align 8, !dbg !71 + %idxadr_mul = mul nsw i64 %v.26, 1, !dbg !71 + %gep = getelementptr inbounds i8, i8* %v.24, i64 %idxadr_mul, !dbg !71 + store i8* %gep, i8** %tmp.27, align 8, !dbg !71 + %v.27 = load i8*, i8** %tmp.27, align 8, !dbg !71 + store i8 3, i8* %v.27, align 8, !dbg !71 + %v.258 = load i64, i64* %tmp.25, align 8, !dbg !71 + %add = add nsw i64 1, %v.258, !dbg !71 + store i64 %add, i64* %tmp.25, align 8, !dbg !71 + br label %label_2, !dbg !71 + +label_2: ; preds = %label_3, %second + %v.23 = load i64, i64* %tmp.23, align 8, !dbg !71 + %v.259 = load i64, i64* %tmp.25, align 8, !dbg !71 + %icmp = icmp sgt i64 %v.23, %v.259, !dbg !71 + br i1 %icmp, label %label_3, label %else_3, !dbg !71 + +else_3: ; preds = %label_2 + ret void, !dbg !71 +} + +; Function Attrs: uwtable +define void @Main_M3_t73c53358_INIT(i8* %Main_M3_t73c53358_INIT__AnonFormal_0) #0 !dbg !73 { +entry: + %Main_M3_t73c53358_INIT__AnonFormal_01 = alloca i8*, align 8 + store i8* %Main_M3_t73c53358_INIT__AnonFormal_0, i8** %Main_M3_t73c53358_INIT__AnonFormal_01, align 8 + %tmp.30 = alloca i64, align 8 + %tmp.31 = alloca i8*, align 8 + %tmp.32 = alloca i64, align 8 + %tmp.33 = alloca i64, align 8 + %tmp.34 = alloca i8*, align 8 + br label %second, !dbg !76 + +second: ; preds = %entry + call void @llvm.dbg.declare(metadata i8** %Main_M3_t73c53358_INIT__AnonFormal_01, metadata !77, metadata !DIExpression()), !dbg !76 + %v.28 = load i8*, i8** %Main_M3_t73c53358_INIT__AnonFormal_01, align 8, !dbg !76 + %0 = getelementptr inbounds i8, i8* %v.28, i64 8, !dbg !76 + %loadind_ptr = bitcast i8* %0 to i64*, !dbg !76 + %loadind = load i64, i64* %loadind_ptr, align 8, !dbg !76 + store i64 %loadind, i64* %tmp.30, align 8, !dbg !76 + %v.282 = load i8*, i8** %Main_M3_t73c53358_INIT__AnonFormal_01, align 8, !dbg !76 + %loadind_ptr3 = bitcast i8* %v.282 to i8**, !dbg !76 + %loadind4 = load i8*, i8** %loadind_ptr3, align 8, !dbg !76 + store i8* %loadind4, i8** %tmp.31, align 8, !dbg !76 + store i64 0, i64* %tmp.32, align 8, !dbg !76 + br label %label_4, !dbg !76 + +label_5: ; preds = %label_4 + %v.32 = load i64, i64* %tmp.32, align 8, !dbg !76 + store i64 %v.32, i64* %tmp.33, align 8, !dbg !76 + %v.31 = load i8*, i8** %tmp.31, align 8, !dbg !76 + %v.33 = load i64, i64* %tmp.33, align 8, !dbg !76 + %idxadr_mul = mul nsw i64 %v.33, 1, !dbg !76 + %gep = getelementptr inbounds i8, i8* %v.31, i64 %idxadr_mul, !dbg !76 + store i8* %gep, i8** %tmp.34, align 8, !dbg !76 + %v.34 = load i8*, i8** %tmp.34, align 8, !dbg !76 + store i8 3, i8* %v.34, align 8, !dbg !76 + %v.325 = load i64, i64* %tmp.32, align 8, !dbg !76 + %add = add nsw i64 1, %v.325, !dbg !76 + store i64 %add, i64* %tmp.32, align 8, !dbg !76 + br label %label_4, !dbg !76 + +label_4: ; preds = %label_5, %second + %v.30 = load i64, i64* %tmp.30, align 8, !dbg !76 + %v.326 = load i64, i64* %tmp.32, align 8, !dbg !76 + %icmp = icmp sgt i64 %v.30, %v.326, !dbg !76 + br i1 %icmp, label %label_5, label %else_5, !dbg !76 + +else_5: ; preds = %label_4 + ret void, !dbg !76 +} + +attributes #0 = { uwtable "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.ident = !{!0} +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!14, !15, !16} + +!0 = !{!"versions- cm3: d5.11.3 llvm: 14.0"} +!1 = distinct !DICompileUnit(language: DW_LANG_Modula3, file: !2, producer: "cm3", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3) +!2 = !DIFile(filename: "Main.m3", directory: "/home/cm3/subrangetest/src") +!3 = !{!4} +!4 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum", scope: !2, file: !2, line: 13, size: 8, align: 8, elements: !5) +!5 = !{!6, !7, !8, !9, !10, !11, !12, !13} +!6 = !DIEnumerator(name: "alpha", value: 0) +!7 = !DIEnumerator(name: "beta", value: 1) +!8 = !DIEnumerator(name: "gamma", value: 2) +!9 = !DIEnumerator(name: "delta", value: 3) +!10 = !DIEnumerator(name: "epsilon", value: 4) +!11 = !DIEnumerator(name: "theta", value: 5) +!12 = !DIEnumerator(name: "psi", value: 6) +!13 = !DIEnumerator(name: "zeta", value: 7) +!14 = !{i64 2, !"Dwarf Version", i64 4} +!15 = !{i64 2, !"Debug Info Version", i64 3} +!16 = !{i64 2, !"wchar_size", i64 2} +!17 = distinct !DISubprogram(name: "Test", linkageName: "Main__Test", scope: !2, file: !2, line: 13, type: !18, scopeLine: 13, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20) +!18 = !DISubroutineType(types: !19) +!19 = !{null} +!20 = !{} +!21 = !DILocation(line: 25, scope: !17) +!22 = !DILocalVariable(name: "x", scope: !17, file: !2, line: 13, type: !23) +!23 = !DISubrangeType(name: "Range355", scope: !2, file: !2, baseType: !24, count: 53, lowerBound: 3) +!24 = !DIBasicType(name: "Range355_BASE", size: 8, encoding: DW_ATE_signed) +!25 = !DILocation(line: 13, scope: !17) +!26 = !DILocalVariable(name: "y", scope: !17, file: !2, line: 13, type: !27) +!27 = !DISubrangeType(name: "RangeEnum", scope: !2, file: !2, baseType: !4, count: 4, lowerBound: 2) +!28 = !DILocalVariable(name: "z", scope: !17, file: !2, line: 13, type: !29) +!29 = !DISubrangeType(name: "Rangeneg", scope: !2, file: !2, baseType: !30, count: 12, lowerBound: -4) +!30 = !DIBasicType(name: "Rangeneg_BASE", size: 8, encoding: DW_ATE_signed) +!31 = !DILocalVariable(name: "l", scope: !17, file: !2, line: 13, type: !32) +!32 = !DISubrangeType(name: "BigRange", scope: !2, file: !2, baseType: !33, count: 128001, lowerBound: 0) +!33 = !DIBasicType(name: "BigRange_BASE", size: 32, encoding: DW_ATE_signed) +!34 = !DILocalVariable(name: "ch", scope: !17, file: !2, line: 13, type: !35) +!35 = !DISubrangeType(name: "CharRange", scope: !2, file: !2, baseType: !36, count: 10, lowerBound: 68) +!36 = !DIBasicType(name: "CharRange_BASE", size: 8, encoding: DW_ATE_unsigned_char) +!37 = !DILocalVariable(name: "ar", scope: !17, file: !2, line: 13, type: !38) +!38 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "AR", baseType: !39, size: 64, align: 64) +!39 = !DICompositeType(tag: DW_TAG_array_type, baseType: !23, align: 64, elements: !40, dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref)) +!40 = !{!41} +!41 = !DISubrangeType(name: "EJERzT_rng", scope: !2, file: !2, baseType: !42, count: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref), lowerBound: !DIExpression(DW_OP_lit0)) +!42 = !DIBasicType(name: "INTEGER", size: 64, encoding: DW_ATE_signed) +!43 = !DILocalVariable(name: "br", scope: !17, file: !2, line: 13, type: !44) +!44 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "BR", baseType: !45, size: 64, align: 64) +!45 = !DICompositeType(tag: DW_TAG_array_type, baseType: !46, align: 64, elements: !49, dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref)) +!46 = !DICompositeType(tag: DW_TAG_array_type, baseType: !23, align: 64, elements: !47) +!47 = !{!48} +!48 = !DISubrangeType(name: "EJERzT_rng", scope: !2, file: !2, baseType: !42, count: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 16, DW_OP_deref), lowerBound: !DIExpression(DW_OP_lit0)) +!49 = !{!50} +!50 = !DISubrangeType(name: "D6HOe1_rng", scope: !2, file: !2, baseType: !42, count: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref), lowerBound: !DIExpression(DW_OP_lit0)) +!51 = !DILocation(line: 20, scope: !17) +!52 = !DILocation(line: 21, scope: !17) +!53 = !DILocation(line: 15, scope: !17) +!54 = !DILocation(line: 16, scope: !17) +!55 = !DILocation(line: 17, scope: !17) +!56 = !DILocation(line: 18, scope: !17) +!57 = !DILocation(line: 19, scope: !17) +!58 = !DILocation(line: 23, scope: !17) +!59 = !DILocation(line: 24, scope: !17) +!60 = distinct !DISubprogram(name: "Main_M3", linkageName: "Main_M3", scope: !2, file: !2, line: 27, type: !61, scopeLine: 27, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20) +!61 = !DISubroutineType(types: !62) +!62 = !{!63, !42} +!63 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ADDR", baseType: !64, size: 64, align: 64) +!64 = !DICompositeType(tag: DW_TAG_class_type, name: "ADDR__HeapObject", scope: !2, file: !2, line: 27, size: 64, align: 64, elements: !19, identifier: "AJWxb1") +!65 = !DILocation(line: 28, scope: !60) +!66 = !DILocalVariable(name: "mode", arg: 1, scope: !60, file: !2, line: 27, type: !42) +!67 = !DILocation(line: 27, scope: !60) +!68 = distinct !DISubprogram(name: "3_tf60d7f0b_INIT", linkageName: "Main_M3_tf60d7f0b_INIT", scope: !2, file: !2, line: 11, type: !69, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20) +!69 = !DISubroutineType(types: !70) +!70 = !{null, !44} +!71 = !DILocation(line: 11, scope: !68) +!72 = !DILocalVariable(name: "Main_M3_tf60d7f0b_INIT__AnonFormal_0", arg: 1, scope: !68, file: !2, line: 11, type: !44) +!73 = distinct !DISubprogram(name: "3_t73c53358_INIT", linkageName: "Main_M3_t73c53358_INIT", scope: !2, file: !2, line: 10, type: !74, scopeLine: 10, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20) +!74 = !DISubroutineType(types: !75) +!75 = !{null, !38} +!76 = !DILocation(line: 10, scope: !73) +!77 = !DILocalVariable(name: "Main_M3_t73c53358_INIT__AnonFormal_0", arg: 1, scope: !73, file: !2, line: 10, type: !38) +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("x") +; CHECK: DW_AT_type{{.*}}"Range355" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("y") +; CHECK: DW_AT_type{{.*}}"RangeEnum" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("z") +; CHECK: DW_AT_type{{.*}}"Rangeneg" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("l") +; CHECK: DW_AT_type{{.*}}"BigRange" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("ar") +; CHECK: DW_AT_type{{.*}}"AR" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("br") +; CHECK: DW_AT_type{{.*}}"BR" +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"Range355_BASE" +; CHECK: DW_AT_name ("Range355") +; CHECK: DW_AT_lower_bound (0x03) +; CHECK: DW_AT_count (0x35) +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("Range355_BASE") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x01) +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"Enum" +; CHECK: DW_AT_name ("RangeEnum") +; CHECK: DW_AT_lower_bound (0x02) +; CHECK: DW_AT_count (0x04) +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"Rangeneg_BASE" +; CHECK: DW_AT_name ("Rangeneg") +; CHECK: DW_AT_lower_bound (0xfffffffffffffffc) +; CHECK: DW_AT_count (0x0c) +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("Rangeneg_BASE") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x01) +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"BigRange_BASE" +; CHECK: DW_AT_name ("BigRange") +; CHECK: DW_AT_lower_bound (0x00) +; CHECK: DW_AT_count (0x0001f401) +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("BigRange_BASE") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x04) +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"CharRange_BASE" +; CHECK: DW_AT_name ("CharRange") +; CHECK: DW_AT_lower_bound (0x44) +; CHECK: DW_AT_count (0x0a) +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("CharRange_BASE") +; CHECK: DW_AT_encoding (DW_ATE_unsigned_char) +; CHECK: DW_AT_byte_size (0x01) +; CHECK: DW_TAG_pointer_type +; CHECK: DW_AT_type{{.*}}"Range355 []" +; CHECK: DW_AT_name ("AR") +; CHECK: DW_TAG_array_type +; CHECK: DW_AT_data_location (DW_OP_push_object_address, DW_OP_deref) +; CHECK: DW_AT_type{{.*}}"Range355" +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"INTEGER" +; CHECK: DW_AT_name ("EJERzT_rng") +; CHECK: DW_AT_lower_bound (DW_OP_lit0) +; CHECK: DW_AT_count (DW_OP_push_object_address, DW_OP_plus_uconst 0x8, DW_OP_deref) +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("__ARRAY_SIZE_TYPE__") +; CHECK: DW_AT_byte_size (0x08) +; CHECK: DW_AT_encoding (DW_ATE_unsigned) +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("INTEGER") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x08) +; CHECK: DW_TAG_pointer_type +; CHECK: DW_AT_type{{.*}}"Range355 []" +; CHECK: DW_AT_name ("BR") +; CHECK: DW_TAG_array_type +; CHECK: DW_AT_data_location (DW_OP_push_object_address, DW_OP_deref) +; CHECK: DW_AT_type{{.*}}"Range355 []" +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"INTEGER" +; CHECK: DW_AT_name ("D6HOe1_rng") +; CHECK: DW_AT_lower_bound (DW_OP_lit0) +; CHECK: DW_AT_count (DW_OP_push_object_address, DW_OP_plus_uconst 0x8, DW_OP_deref) +; CHECK: DW_TAG_array_type +; CHECK: DW_AT_type{{.*}}"Range355" +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_type{{.*}}"INTEGER" +; CHECK: DW_AT_name ("EJERzT_rng") +; CHECK: DW_AT_lower_bound (DW_OP_lit0) +; CHECK: DW_AT_count (DW_OP_push_object_address, DW_OP_plus_uconst 0x10, DW_OP_deref) Index: llvm/test/Verifier/subrange.ll =================================================================== --- /dev/null +++ llvm/test/Verifier/subrange.ll @@ -0,0 +1,115 @@ +; RUN: llvm-as -disable-output <%s 2>&1 | FileCheck %s + +%struct.0 = type { [5 x i8] } + +; Function Attrs: uwtable +define void @Main__Test() #0 !dbg !17 { +entry: + %x = alloca i8, align 1 + %y = alloca i8, align 1 + %z = alloca i8, align 1 + %l = alloca i32, align 4 + %ar = alloca %struct.0, align 1 + %tmp.9 = alloca i64, align 8 + %tmp.10 = alloca i64, align 8 + %tmp.11 = alloca i8*, align 8 + br label %second, !dbg !21 + +second: ; preds = %entry + call void @llvm.dbg.declare(metadata i8* %x, metadata !22, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i8* %y, metadata !26, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i8* %z, metadata !28, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata i32* %l, metadata !31, metadata !DIExpression()), !dbg !25 + call void @llvm.dbg.declare(metadata %struct.0* %ar, metadata !34, metadata !DIExpression()), !dbg !25 + store i64 0, i64* %tmp.9, align 8, !dbg !38 + br label %label_1, !dbg !38 + +label_1: ; preds = %label_1, %second + %v.9 = load i64, i64* %tmp.9, align 8, !dbg !38 + store i64 %v.9, i64* %tmp.10, align 8, !dbg !38 + %v.10 = load i64, i64* %tmp.10, align 8, !dbg !38 + %idxadr_mul = mul nsw i64 %v.10, 1, !dbg !38 + %idxadr_cast = bitcast %struct.0* %ar to i8*, !dbg !38 + %gep = getelementptr inbounds i8, i8* %idxadr_cast, i64 %idxadr_mul, !dbg !38 + store i8* %gep, i8** %tmp.11, align 8, !dbg !38 + %v.11 = load i8*, i8** %tmp.11, align 8, !dbg !38 + store i8 3, i8* %v.11, align 8, !dbg !38 + %v.91 = load i64, i64* %tmp.9, align 8, !dbg !38 + %add = add nsw i64 1, %v.91, !dbg !38 + store i64 %add, i64* %tmp.9, align 8, !dbg !38 + %v.92 = load i64, i64* %tmp.9, align 8, !dbg !38 + %icmp = icmp sgt i64 5, %v.92, !dbg !38 + br i1 %icmp, label %label_1, label %else_1, !dbg !38 + +else_1: ; preds = %label_1 + store i8 35, i8* %x, align 1, !dbg !39 + store i8 3, i8* %y, align 1, !dbg !40 + store i8 -1, i8* %z, align 1, !dbg !41 + store i32 9999, i32* %l, align 4, !dbg !42 + ret void, !dbg !21 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { uwtable "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.ident = !{!0} +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!14, !15, !16} + +!0 = !{!"versions- cm3: d5.11.0 llvm: 13.0"} +!1 = distinct !DICompileUnit(language: DW_LANG_Modula3, file: !2, producer: "cm3", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3) +!2 = !DIFile(filename: "Main.m3", directory: "/home/peter/cm3/subrangetest/src/llvm/src") +!3 = !{!4} +!4 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum", scope: !2, file: !2, line: 11, size: 8, align: 8, elements: !5) +!5 = !{!6, !7, !8, !9, !10, !11, !12, !13} +!6 = !DIEnumerator(name: "alpha", value: 0) +!7 = !DIEnumerator(name: "beta", value: 1) +!8 = !DIEnumerator(name: "gamma", value: 2) +!9 = !DIEnumerator(name: "delta", value: 3) +!10 = !DIEnumerator(name: "epsilon", value: 4) +!11 = !DIEnumerator(name: "theta", value: 5) +!12 = !DIEnumerator(name: "psi", value: 6) +!13 = !DIEnumerator(name: "zeta", value: 7) +!14 = !{i64 2, !"Dwarf Version", i64 4} +!15 = !{i64 2, !"Debug Info Version", i64 3} +!16 = !{i64 2, !"wchar_size", i64 2} +!17 = distinct !DISubprogram(name: "Test", linkageName: "Main__Test", scope: !2, file: !2, line: 11, type: !18, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20) +!18 = !DISubroutineType(types: !19) +!19 = !{null} +!20 = !{} +!21 = !DILocation(line: 19, scope: !17) +!22 = !DILocalVariable(name: "x", scope: !17, file: !2, line: 11, type: !23) +; CHECK: Invalid subrange base type +!23 = !DISubrangeType(name: "Range355", scope: !2, file: !2, baseType: !27, count: 53, lowerBound: 3) +!24 = !DIBasicType(name: "Range355_SR", size: 8, encoding: DW_ATE_signed) +!25 = !DILocation(line: 11, scope: !17) +!26 = !DILocalVariable(name: "y", scope: !17, file: !2, line: 11, type: !27) +!27 = !DISubrangeType(name: "RangeEnum", scope: !2, file: !2, baseType: !4, count: 4, lowerBound: 2) +!28 = !DILocalVariable(name: "z", scope: !17, file: !2, line: 11, type: !29) +; CHECK: Invalid subrange base type +!29 = !DISubrangeType(name: "Rangeneg", scope: !2, file: !2, baseType: !27, count: 12, lowerBound: -4) +!30 = !DIBasicType(name: "Rangeneg_SR", size: 8, encoding: DW_ATE_signed) +!31 = !DILocalVariable(name: "l", scope: !17, file: !2, line: 11, type: !32) +!32 = !DISubrangeType(name: "BigRange", scope: !2, file: !2, baseType: !33, count: 128001, lowerBound: 0) +!33 = !DIBasicType(name: "BigRange_SR", size: 32, encoding: DW_ATE_signed) +!34 = !DILocalVariable(name: "ar", scope: !17, file: !2, line: 11, type: !35) +!35 = !DICompositeType(tag: DW_TAG_array_type, baseType: !23, size: 40, align: 64, elements: !36) +!36 = !{!37} +!37 = !DISubrange(count: 5, lowerBound: 0) +!38 = !DILocation(line: 17, scope: !17) +!39 = !DILocation(line: 13, scope: !17) +!40 = !DILocation(line: 14, scope: !17) +!41 = !DILocation(line: 15, scope: !17) +!42 = !DILocation(line: 16, scope: !17) +!43 = distinct !DISubprogram(name: "Main_M3", linkageName: "Main_M3", scope: !2, file: !2, line: 21, type: !44, scopeLine: 21, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !20) +!44 = !DISubroutineType(types: !45) +!45 = !{!46, !48} +!46 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ADDR", baseType: !47, size: 64, align: 64) +!47 = !DICompositeType(tag: DW_TAG_class_type, name: "ADDR__HeapObject", scope: !2, file: !2, line: 21, size: 64, align: 64, elements: !19, identifier: "AJWxb1") +!48 = !DIBasicType(name: "INTEGER", size: 64, encoding: DW_ATE_signed) +!49 = !DILocation(line: 22, scope: !43) +!50 = !DILocalVariable(name: "mode", arg: 1, scope: !43, file: !2, line: 21, type: !48) +!51 = !DILocation(line: 21, scope: !43) Index: llvm/unittests/IR/DebugInfoTest.cpp =================================================================== --- llvm/unittests/IR/DebugInfoTest.cpp +++ llvm/unittests/IR/DebugInfoTest.cpp @@ -244,4 +244,32 @@ EXPECT_TRUE(isa_and_nonnull(SetType)); } +TEST(DIBuilder, CreateSubrangeType) { + LLVMContext Ctx; + std::unique_ptr M(new Module("MyModule", Ctx)); + DIBuilder DIB(*M); + DIScope *Scope = DISubprogram::getDistinct( + Ctx, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0, + DINode::FlagZero, DISubprogram::SPFlagZero, nullptr); + DIType *Type = DIB.createBasicType("Int", 64, dwarf::DW_ATE_signed); + DIFile *F = DIB.createFile("main.c", "/"); + + auto getDIExpression = [&DIB](int offset) { + SmallVector ops; + ops.push_back(llvm::dwarf::DW_OP_push_object_address); + DIExpression::appendOffset(ops, offset); + ops.push_back(llvm::dwarf::DW_OP_deref); + + return DIB.createExpression(ops); + }; + + DISubrangeType *SRType1 = DIB.getSubrange(Scope, "sr1", F, Type, 2, 4); + EXPECT_TRUE(isa_and_nonnull(SRType1)); + + DIExpression *exp1 = getDIExpression(1); + DIExpression *exp2 = getDIExpression(2); + DISubrangeType *SRType2 = DIB.getSubrange(Scope, "sr2", F, Type, exp1, exp2); + EXPECT_TRUE(isa_and_nonnull(SRType2)); +} + } // end namespace