diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -160,7 +160,8 @@ LLVMDIMacroMetadataKind, LLVMDIMacroFileMetadataKind, LLVMDICommonBlockMetadataKind, - LLVMDIStringTypeMetadataKind + LLVMDIStringTypeMetadataKind, + LLVMDIGenericSubrangeMetadataKind }; typedef unsigned LLVMMetadataKind; diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -341,7 +341,8 @@ METADATA_STRING_TYPE = 41, // [distinct, name, size, align,...] // Codes 42 and 43 are reserved for support for Fortran array specific debug // info. - METADATA_COMMON_BLOCK = 44 // [distinct, scope, name, variable,...] + METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...] + METADATA_GENERIC_SUBRANGE = 45 // [distinct, count, lo, up, stride] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -582,6 +582,11 @@ DISubrange *getOrCreateSubrange(Metadata *Count, Metadata *LowerBound, Metadata *UpperBound, Metadata *Stride); + DIGenericSubrange *getOrCreateGenericSubrange(Metadata *Count, + Metadata *LowerBound, + Metadata *UpperBound, + Metadata *Stride); + /// Create a new descriptor for the specified variable. /// \param Context Variable scope. /// \param Name Name of the variable. diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -201,6 +201,7 @@ case DIObjCPropertyKind: case DIImportedEntityKind: case DIModuleKind: + case DIGenericSubrangeKind: return true; } } @@ -351,6 +352,58 @@ } }; +class DIGenericSubrange : public DINode { + friend class LLVMContextImpl; + friend class MDNode; + + DIGenericSubrange(LLVMContext &C, StorageType Storage, + ArrayRef Ops) + : DINode(C, DIGenericSubrangeKind, Storage, + dwarf::DW_TAG_generic_subrange, Ops) {} + + ~DIGenericSubrange() = default; + + static DIGenericSubrange *getImpl(LLVMContext &Context, Metadata *CountNode, + Metadata *LowerBound, Metadata *UpperBound, + Metadata *Stride, StorageType Storage, + bool ShouldCreate = true); + + TempDIGenericSubrange cloneImpl() const { + return getTemporary(getContext(), getRawCountNode(), getRawLowerBound(), + getRawUpperBound(), getRawStride()); + } + +public: + DEFINE_MDNODE_GET(DIGenericSubrange, + (Metadata * CountNode, Metadata *LowerBound, + Metadata *UpperBound, Metadata *Stride), + (CountNode, LowerBound, UpperBound, Stride)) + + TempDIGenericSubrange clone() const { return cloneImpl(); } + + Metadata *getRawCountNode() const { return getOperand(0).get(); } + + Metadata *getRawLowerBound() const { return getOperand(1).get(); } + + Metadata *getRawUpperBound() const { return getOperand(2).get(); } + + Metadata *getRawStride() const { return getOperand(3).get(); } + + using BoundType = PointerUnion; + + BoundType getCount() const; + + BoundType getLowerBound() const; + + BoundType getUpperBound() const; + + BoundType getStride() const; + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DIGenericSubrangeKind; + } +}; + /// Enumeration value. /// /// TODO: Add a pointer to the context (DW_TAG_enumeration_type) once that no diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def --- a/llvm/include/llvm/IR/Metadata.def +++ b/llvm/include/llvm/IR/Metadata.def @@ -115,6 +115,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType) +HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGenericSubrange) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4593,6 +4593,43 @@ return false; } +/// ParseDIGenericSubrange: +/// ::= !DIGenericSubrange(lowerBound: !node1, upperBound: !node2, stride: +/// !node3) +bool LLParser::ParseDIGenericSubrange(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + OPTIONAL(count, MDSignedOrMDField, (-1, -1, INT64_MAX, false)); \ + OPTIONAL(lowerBound, MDSignedOrMDField, ); \ + OPTIONAL(upperBound, MDSignedOrMDField, ); \ + OPTIONAL(stride, MDSignedOrMDField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Metadata *Count = nullptr; + Metadata *LowerBound = nullptr; + Metadata *UpperBound = nullptr; + Metadata *Stride = nullptr; + + auto convToMetadata = [&](MDSignedOrMDField Bound) -> Metadata * { + if (Bound.isMDSignedField()) + return ConstantAsMetadata::get(ConstantInt::getSigned( + Type::getInt64Ty(Context), Bound.getMDSignedValue())); + if (Bound.isMDField()) + return Bound.getMDFieldValue(); + return nullptr; + }; + + Count = convToMetadata(count); + LowerBound = convToMetadata(lowerBound); + UpperBound = convToMetadata(upperBound); + Stride = convToMetadata(stride); + + Result = GET_OR_DISTINCT(DIGenericSubrange, + (Context, Count, LowerBound, UpperBound, Stride)); + + return false; +} + /// ParseDIEnumerator: /// ::= !DIEnumerator(value: 30, isUnsigned: true, name: "SomeKind") bool LLParser::ParseDIEnumerator(MDNode *&Result, bool IsDistinct) { diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -873,6 +873,7 @@ case bitc::METADATA_OBJC_PROPERTY: case bitc::METADATA_IMPORTED_ENTITY: case bitc::METADATA_GLOBAL_VAR_EXPR: + case bitc::METADATA_GENERIC_SUBRANGE: // We don't expect to see any of these, if we see one, give up on // lazy-loading and fallback. MDStringRef.clear(); @@ -1284,6 +1285,18 @@ NextMetadataNo++; break; } + case bitc::METADATA_GENERIC_SUBRANGE: { + Metadata *Val = nullptr; + Val = GET_OR_DISTINCT(DIGenericSubrange, + (Context, getMDOrNull(Record[1]), + getMDOrNull(Record[2]), getMDOrNull(Record[3]), + getMDOrNull(Record[4]))); + + MetadataList.assignValue(Val, NextMetadataNo); + IsDistinct = Record[0] & 1; + NextMetadataNo++; + break; + } case bitc::METADATA_ENUMERATOR: { if (Record.size() < 3) return error("Invalid record"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -300,6 +300,9 @@ SmallVectorImpl &Record, unsigned &Abbrev); void writeDISubrange(const DISubrange *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDIGenericSubrange(const DIGenericSubrange *N, + SmallVectorImpl &Record, + unsigned Abbrev); void writeDIEnumerator(const DIEnumerator *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIBasicType(const DIBasicType *N, SmallVectorImpl &Record, @@ -1549,6 +1552,19 @@ Record.clear(); } +void ModuleBitcodeWriter::writeDIGenericSubrange( + const DIGenericSubrange *N, SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back((uint64_t)N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getRawCountNode())); + Record.push_back(VE.getMetadataOrNullID(N->getRawLowerBound())); + Record.push_back(VE.getMetadataOrNullID(N->getRawUpperBound())); + Record.push_back(VE.getMetadataOrNullID(N->getRawStride())); + + Stream.EmitRecord(bitc::METADATA_GENERIC_SUBRANGE, Record, Abbrev); + Record.clear(); +} + static void emitSignedInt64(SmallVectorImpl &Vals, uint64_t V) { if ((int64_t)V >= 0) Vals.push_back(V << 1); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -812,6 +812,19 @@ if (auto ST = Subrange->getStride()) if (auto *Dependency = ST.dyn_cast()) Result.push_back(Dependency); + } else if (auto *GenericSubrange = dyn_cast(El)) { + if (auto Count = GenericSubrange->getCount()) + if (auto *Dependency = Count.dyn_cast()) + Result.push_back(Dependency); + if (auto LB = GenericSubrange->getLowerBound()) + if (auto *Dependency = LB.dyn_cast()) + Result.push_back(Dependency); + if (auto UB = GenericSubrange->getUpperBound()) + if (auto *Dependency = UB.dyn_cast()) + Result.push_back(Dependency); + if (auto ST = GenericSubrange->getStride()) + if (auto *Dependency = ST.dyn_cast()) + Result.push_back(Dependency); } } return Result; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -300,6 +300,8 @@ void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy); void constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy); void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy); + void constructGenericSubrangeDIE(DIE &Buffer, const DIGenericSubrange *SR, + DIE *IndexTy); void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy); void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy); DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1388,6 +1388,43 @@ addBoundTypeEntry(dwarf::DW_AT_byte_stride, SR->getStride()); } +void DwarfUnit::constructGenericSubrangeDIE(DIE &Buffer, + const DIGenericSubrange *GSR, + DIE *IndexTy) { + DIE &DW_generic_Subrange = + createAndAddDIE(dwarf::DW_TAG_generic_subrange, Buffer); + addDIEEntry(DW_generic_Subrange, dwarf::DW_AT_type, *IndexTy); + + int64_t DefaultLowerBound = getDefaultLowerBound(); + + auto addBoundTypeEntry = [&](dwarf::Attribute Attr, + DISubrange::BoundType Bound) -> void { + if (auto *BV = Bound.dyn_cast()) { + if (auto *VarDIE = getDIE(BV)) + addDIEEntry(DW_generic_Subrange, Attr, *VarDIE); + } else if (auto *BE = Bound.dyn_cast()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(BE); + addBlock(DW_generic_Subrange, Attr, DwarfExpr.finalize()); + } else if (auto *BI = Bound.dyn_cast()) { + if (Attr != dwarf::DW_AT_lower_bound || DefaultLowerBound == -1 || + BI->getSExtValue() != DefaultLowerBound) + addSInt(DW_generic_Subrange, Attr, dwarf::DW_FORM_sdata, + BI->getSExtValue()); + } + }; + + addBoundTypeEntry(dwarf::DW_AT_lower_bound, GSR->getLowerBound()); + + addBoundTypeEntry(dwarf::DW_AT_count, GSR->getCount()); + + addBoundTypeEntry(dwarf::DW_AT_upper_bound, GSR->getUpperBound()); + + addBoundTypeEntry(dwarf::DW_AT_byte_stride, GSR->getStride()); +} + DIE *DwarfUnit::getIndexTyDie() { if (IndexTyDie) return IndexTyDie; @@ -1495,9 +1532,13 @@ DINodeArray Elements = CTy->getElements(); for (unsigned i = 0, N = Elements.size(); i < N; ++i) { // FIXME: Should this really be such a loose cast? - if (auto *Element = dyn_cast_or_null(Elements[i])) + if (auto *Element = dyn_cast_or_null(Elements[i])) { if (Element->getTag() == dwarf::DW_TAG_subrange_type) constructSubrangeDIE(Buffer, cast(Element), IdxTy); + else if (Element->getTag() == dwarf::DW_TAG_generic_subrange) + constructGenericSubrangeDIE(Buffer, cast(Element), + IdxTy); + } } } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1899,6 +1899,47 @@ Out << ")"; } +static void writeDIGenericSubrange(raw_ostream &Out, const DIGenericSubrange *N, + TypePrinting *TypePrinter, + SlotTracker *Machine, + const Module *Context) { + Out << "!DIGenericSubrange("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + + auto *Count = N->getRawCountNode(); + if (auto *CE = dyn_cast_or_null(Count)) { + auto *CV = cast(CE->getValue()); + Printer.printInt("count", CV->getSExtValue(), + /* ShouldSkipZero */ false); + } else + Printer.printMetadata("count", Count, /*ShouldSkipNull */ true); + + auto *LBound = N->getRawLowerBound(); + if (auto *LE = dyn_cast_or_null(LBound)) { + auto *LV = cast(LE->getValue()); + Printer.printInt("lowerBound", LV->getSExtValue(), + /* ShouldSkipZero */ false); + } else + Printer.printMetadata("lowerBound", LBound, /*ShouldSkipNull */ true); + + auto *UBound = N->getRawUpperBound(); + if (auto *UE = dyn_cast_or_null(UBound)) { + auto *UV = cast(UE->getValue()); + Printer.printInt("upperBound", UV->getSExtValue(), + /* ShouldSkipZero */ false); + } else + Printer.printMetadata("upperBound", UBound, /*ShouldSkipNull */ true); + + auto *Stride = N->getRawStride(); + if (auto *SE = dyn_cast_or_null(Stride)) { + auto *SV = cast(SE->getValue()); + Printer.printInt("stride", SV->getSExtValue(), /* ShouldSkipZero */ false); + } else + Printer.printMetadata("stride", Stride, /*ShouldSkipNull */ true); + + Out << ")"; +} + static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N, TypePrinting *, SlotTracker *, const Module *) { Out << "!DIEnumerator("; diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -649,6 +649,13 @@ return DISubrange::get(VMContext, CountNode, LB, UB, Stride); } +DIGenericSubrange *DIBuilder::getOrCreateGenericSubrange(Metadata *CountNode, + Metadata *LB, + Metadata *UB, + Metadata *Stride) { + return DIGenericSubrange::get(VMContext, CountNode, LB, UB, Stride); +} + static void checkGlobalVariableScope(DIScope *Context) { #ifndef NDEBUG if (auto *CT = diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -435,6 +435,100 @@ return BoundType(); } +DIGenericSubrange *DIGenericSubrange::getImpl(LLVMContext &Context, + Metadata *CountNode, Metadata *LB, + Metadata *UB, Metadata *Stride, + StorageType Storage, + bool ShouldCreate) { + DEFINE_GETIMPL_LOOKUP(DIGenericSubrange, (CountNode, LB, UB, Stride)); + Metadata *Ops[] = {CountNode, LB, UB, Stride}; + DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIGenericSubrange, Ops); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getCount() const { + Metadata *CB = getRawCountNode(); + if (!CB) + return BoundType(); + + assert((isa(CB) || isa(CB) || + isa(CB)) && + "Count must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast(CB)) + return BoundType(cast(MD->getValue())); + + if (auto *MD = dyn_cast(CB)) + return BoundType(MD); + + if (auto *MD = dyn_cast(CB)) + return BoundType(MD); + + return BoundType(); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getLowerBound() const { + Metadata *LB = getRawLowerBound(); + if (!LB) + return BoundType(); + + assert((isa(LB) || isa(LB) || + isa(LB)) && + "LowerBound must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast(LB)) + return BoundType(cast(MD->getValue())); + + if (auto *MD = dyn_cast(LB)) + return BoundType(MD); + + if (auto *MD = dyn_cast(LB)) + return BoundType(MD); + + return BoundType(); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getUpperBound() const { + Metadata *UB = getRawUpperBound(); + if (!UB) + return BoundType(); + + assert((isa(UB) || isa(UB) || + isa(UB)) && + "UpperBound must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast(UB)) + return BoundType(cast(MD->getValue())); + + if (auto *MD = dyn_cast(UB)) + return BoundType(MD); + + if (auto *MD = dyn_cast(UB)) + return BoundType(MD); + + return BoundType(); +} + +DIGenericSubrange::BoundType DIGenericSubrange::getStride() const { + Metadata *ST = getRawStride(); + if (!ST) + return BoundType(); + + assert((isa(ST) || isa(ST) || + isa(ST)) && + "Stride must be signed constant or DIVariable or DIExpression"); + + if (auto *MD = dyn_cast(ST)) + return BoundType(cast(MD->getValue())); + + if (auto *MD = dyn_cast(ST)) + return BoundType(MD); + + if (auto *MD = dyn_cast(ST)) + return BoundType(MD); + + return BoundType(); +} + DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, const APInt &Value, bool IsUnsigned, MDString *Name, StorageType Storage, bool ShouldCreate) { diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -346,6 +346,51 @@ } }; +template <> struct MDNodeKeyImpl { + Metadata *CountNode; + Metadata *LowerBound; + Metadata *UpperBound; + Metadata *Stride; + + MDNodeKeyImpl(Metadata *CountNode, Metadata *LowerBound, Metadata *UpperBound, + Metadata *Stride) + : CountNode(CountNode), LowerBound(LowerBound), UpperBound(UpperBound), + Stride(Stride) {} + MDNodeKeyImpl(const DIGenericSubrange *N) + : CountNode(N->getRawCountNode()), LowerBound(N->getRawLowerBound()), + UpperBound(N->getRawUpperBound()), Stride(N->getRawStride()) {} + + bool isKeyOf(const DIGenericSubrange *RHS) const { + auto BoundsEqual = [=](Metadata *Node1, Metadata *Node2) -> bool { + if (Node1 == Node2) + return true; + + ConstantAsMetadata *MD1 = dyn_cast_or_null(Node1); + ConstantAsMetadata *MD2 = dyn_cast_or_null(Node2); + if (MD1 && MD2) { + ConstantInt *CV1 = cast(MD1->getValue()); + ConstantInt *CV2 = cast(MD2->getValue()); + if (CV1->getSExtValue() == CV2->getSExtValue()) + return true; + } + return false; + }; + + return BoundsEqual(CountNode, RHS->getRawCountNode()) && + BoundsEqual(LowerBound, RHS->getRawLowerBound()) && + BoundsEqual(UpperBound, RHS->getRawUpperBound()) && + BoundsEqual(Stride, RHS->getRawStride()); + } + + unsigned getHashValue() const { + if (CountNode) + if (auto *MD = dyn_cast(CountNode)) + return hash_combine(cast(MD->getValue())->getSExtValue(), + LowerBound, UpperBound, Stride); + return hash_combine(CountNode, LowerBound, UpperBound, Stride); + } +}; + template <> struct MDNodeKeyImpl { APInt Value; MDString *Name; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -926,6 +926,35 @@ "Stride must be signed constant or DIVariable or DIExpression", &N); } +void Verifier::visitDIGenericSubrange(const DIGenericSubrange &N) { + AssertDI(N.getTag() == dwarf::DW_TAG_generic_subrange, "invalid tag", &N); + AssertDI(N.getRawCountNode() || + N.getRawUpperBound(), + "GenericSubrange must contain count or upperBound", &N); + AssertDI(!N.getRawCountNode() || !N.getRawUpperBound(), + "GenericSubrange can have any one of count or upperBound", &N); + auto *CBound = N.getRawCountNode(); + AssertDI(!CBound || isa(CBound) || + isa(CBound) || isa(CBound), + "Count must be signed constant or DIVariable or DIExpression", &N); + auto *LBound = N.getRawLowerBound(); + AssertDI(LBound, "GenericSubrange must contain lowerBound", &N); + AssertDI(isa(LBound) || + isa(LBound) || isa(LBound), + "LowerBound must be signed constant or DIVariable or DIExpression", + &N); + auto *UBound = N.getRawUpperBound(); + AssertDI(!UBound || isa(UBound) || + isa(UBound) || isa(UBound), + "UpperBound must be signed constant or DIVariable or DIExpression", + &N); + auto *Stride = N.getRawStride(); + AssertDI(Stride, "GenericSubrange must contain stride", &N); + AssertDI(isa(Stride) || + isa(Stride) || isa(Stride), + "Stride must be signed constant or DIVariable or DIExpression", &N); +} + void Verifier::visitDIEnumerator(const DIEnumerator &N) { AssertDI(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N); } diff --git a/llvm/test/Bitcode/generic_subrange.ll b/llvm/test/Bitcode/generic_subrange.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Bitcode/generic_subrange.ll @@ -0,0 +1,35 @@ +;; This test checks generation of DIGenericSubrange. + +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +;; Test whether DIGenericSubrange is generated. +; CHECK: !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)) + +; ModuleID = 'generic_subrange.f90' +source_filename = "/dir/generic_subrange.ll" + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 2, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4) +!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir") +!4 = !{} +!5 = !{!6} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !8, dataLocation: !10, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref)) +!7 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float) +!8 = !{!9} +!9 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)) +!10 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial) +!11 = distinct !DISubprogram(name: "sub1", scope: !2, file: !3, line: 1, type: !12, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2) +!12 = !DISubroutineType(types: !13) +!13 = !{null, !14, !19} +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !15) +!15 = !{!16} +!16 = !DISubrange(lowerBound: 1, upperBound: !17) +!17 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial) +!18 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) +!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 1024, align: 64, elements: !20) +!20 = !{!21} +!21 = !DISubrange(lowerBound: 1, upperBound: 16) diff --git a/llvm/test/Bitcode/generic_subrange_count.ll b/llvm/test/Bitcode/generic_subrange_count.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Bitcode/generic_subrange_count.ll @@ -0,0 +1,35 @@ +;; This test checks generation of DIGenericSubrange. + +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +;; Test whether DIGenericSubrange is generated. +; CHECK: !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)) + +; ModuleID = 'generic_subrange.f90' +source_filename = "/dir/generic_subrange.ll" + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 2, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4) +!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir") +!4 = !{} +!5 = !{!6} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !8, dataLocation: !10, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref)) +!7 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float) +!8 = !{!9} +!9 = !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)) +!10 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial) +!11 = distinct !DISubprogram(name: "sub1", scope: !2, file: !3, line: 1, type: !12, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2) +!12 = !DISubroutineType(types: !13) +!13 = !{null, !14, !19} +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !15) +!15 = !{!16} +!16 = !DISubrange(lowerBound: 1, upperBound: !17) +!17 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial) +!18 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) +!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 1024, align: 64, elements: !20) +!20 = !{!21} +!21 = !DISubrange(lowerBound: 1, upperBound: 16) diff --git a/llvm/test/DebugInfo/X86/dwarfdump-generic_subrange.ll b/llvm/test/DebugInfo/X86/dwarfdump-generic_subrange.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/dwarfdump-generic_subrange.ll @@ -0,0 +1,66 @@ +;; This test checks whether DW_AT_rank attribute accepts DIExpression. + +; RUN: llc %s -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +;; Test whether DW_AT_data_location is generated. +; CHECK-LABEL: DW_TAG_array_type + +; CHECK: DW_AT_rank (DW_OP_push_object_address, DW_OP_plus_uconst 0x8, DW_OP_deref) +; CHECK: DW_TAG_generic_subrange +; CHECK: DW_AT_lower_bound (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x50, DW_OP_plus, DW_OP_deref) +; CHECK: DW_AT_upper_bound (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x78, DW_OP_plus, DW_OP_deref) +; CHECK: DW_AT_byte_stride (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x70, DW_OP_plus, DW_OP_deref, DW_OP_lit4, DW_OP_mul) + +;; Test case is hand written with the help of below testcase +;;------------------------------ +;;subroutine sub(arank) +;; real :: arank(..) +;; print *, RANK(arank) +;;end +;;------------------------------ + +; ModuleID = 'dwarfdump-rank.ll' +source_filename = "dwarfdump-rank.ll" + +define void @sub_(i64* noalias %arank, i64* noalias %"arank$sd") !dbg !5 { +L.entry: + call void @llvm.dbg.value(metadata i64* %arank, metadata !17, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !19, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !29, metadata !DIExpression()), !dbg !18 + ret void, !dbg !18 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 2, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !4, imports: !4) +!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir") +!4 = !{} +!5 = distinct !DISubprogram(name: "sub", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2) +!6 = !DISubroutineType(types: !7) +!7 = !{null, !8, !14} +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !10) +!9 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float) +!10 = !{!11} +!11 = !DISubrange(lowerBound: 1, upperBound: !12) +!12 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial) +!13 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 1024, align: 64, elements: !15) +!15 = !{!16} +!16 = !DISubrange(lowerBound: 1, upperBound: 16) +!17 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial) +!18 = !DILocation(line: 0, scope: !5) +!19 = !DILocalVariable(name: "arank", arg: 1, scope: !5, file: !3, line: 1, type: !20) +!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !21, dataLocation: !17, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref)) +!21 = !{!22} +!22 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)) +!29 = !DILocalVariable(arg: 2, scope: !5, file: !3, line: 1, type: !14, flags: DIFlagArtificial) diff --git a/llvm/test/DebugInfo/X86/dwarfdump-generic_subrange_count.ll b/llvm/test/DebugInfo/X86/dwarfdump-generic_subrange_count.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/dwarfdump-generic_subrange_count.ll @@ -0,0 +1,66 @@ +;; This test checks whether DW_AT_rank attribute accepts DIExpression. + +; RUN: llc %s -filetype=obj -o %t.o +; RUN: llvm-dwarfdump %t.o | FileCheck %s + +;; Test whether DW_AT_data_location is generated. +; CHECK-LABEL: DW_TAG_array_type + +; CHECK: DW_AT_rank (DW_OP_push_object_address, DW_OP_plus_uconst 0x8, DW_OP_deref) +; CHECK: DW_TAG_generic_subrange +; CHECK: DW_AT_lower_bound (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x50, DW_OP_plus, DW_OP_deref) +; CHECK: DW_AT_count (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x58, DW_OP_plus, DW_OP_deref) +; CHECK: DW_AT_byte_stride (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x70, DW_OP_plus, DW_OP_deref, DW_OP_lit4, DW_OP_mul) + +;; Test case is hand written with the help of below testcase +;;------------------------------ +;;subroutine sub(arank) +;; real :: arank(..) +;; print *, RANK(arank) +;;end +;;------------------------------ + +; ModuleID = 'dwarfdump-rank.ll' +source_filename = "dwarfdump-rank.ll" + +define void @sub_(i64* noalias %arank, i64* noalias %"arank$sd") !dbg !5 { +L.entry: + call void @llvm.dbg.value(metadata i64* %arank, metadata !17, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !19, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !29, metadata !DIExpression()), !dbg !18 + ret void, !dbg !18 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 2, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !4, imports: !4) +!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir") +!4 = !{} +!5 = distinct !DISubprogram(name: "sub", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2) +!6 = !DISubroutineType(types: !7) +!7 = !{null, !8, !14} +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !10) +!9 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float) +!10 = !{!11} +!11 = !DISubrange(lowerBound: 1, upperBound: !12) +!12 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial) +!13 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 1024, align: 64, elements: !15) +!15 = !{!16} +!16 = !DISubrange(lowerBound: 1, upperBound: 16) +!17 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial) +!18 = !DILocation(line: 0, scope: !5) +!19 = !DILocalVariable(name: "arank", arg: 1, scope: !5, file: !3, line: 1, type: !20) +!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !21, dataLocation: !17, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref)) +!21 = !{!22} +!22 = !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)) +!29 = !DILocalVariable(arg: 2, scope: !5, file: !3, line: 1, type: !14, flags: DIFlagArtificial) diff --git a/llvm/test/Verifier/digenericsubrange-count-upperBound.ll b/llvm/test/Verifier/digenericsubrange-count-upperBound.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/digenericsubrange-count-upperBound.ll @@ -0,0 +1,5 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0} +; CHECK: GenericSubrange can have any one of count or upperBound +!0 = !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)) diff --git a/llvm/test/Verifier/digenericsubrange-missing-stride.ll b/llvm/test/Verifier/digenericsubrange-missing-stride.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/digenericsubrange-missing-stride.ll @@ -0,0 +1,5 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0} +; CHECK: GenericSubrange must contain stride +!0 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref)) diff --git a/llvm/test/Verifier/digenericsubrange-missing-upperBound.ll b/llvm/test/Verifier/digenericsubrange-missing-upperBound.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/digenericsubrange-missing-upperBound.ll @@ -0,0 +1,5 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0} +; CHECK: GenericSubrange must contain count or upperBound +!0 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))