From d20bf5a7258d4b6a7f017a81b125275dac1aa166 Mon Sep 17 00:00:00 2001 From: Alok Kumar Sharma Date: Thu, 28 May 2020 13:31:22 +0530 Subject: [PATCH] [DebugInfo] Upgrade DISubrange to support Fortran dynamic arrays This patch upgrades DISubrange to support fortran requirements. Summary: Below are the updates/addition of fields. lowerBound - Now accepts signed integer or DIVariable or DIExpression, earlier it accepted only signed integer. upperBound - This field is now added and accepts signed interger or DIVariable or DIExpression. stride - This field is now added and accepts signed interger or DIVariable or DIExpression. This is required to describe bounds of array which are known at runtime. Testing: unit test cases added (hand-written) check clang check llvm check debug-info Reviewed By: aprantl Differential Revision: https://reviews.llvm.org/D80197 --- clang/lib/CodeGen/CGDebugInfo.cpp | 43 ++++-- llvm/include/llvm/IR/DIBuilder.h | 2 + llvm/include/llvm/IR/DebugInfoMetadata.h | 42 ++++-- llvm/lib/AsmParser/LLParser.cpp | 36 ++++- llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 14 +- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 6 +- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 2 +- .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 15 +- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 26 +++- llvm/lib/IR/AsmWriter.cpp | 31 +++- llvm/lib/IR/DIBuilder.cpp | 15 +- llvm/lib/IR/DebugInfoMetadata.cpp | 96 +++++++++++- llvm/lib/IR/LLVMContextImpl.h | 46 ++++-- llvm/lib/IR/Verifier.cpp | 26 +++- llvm/test/Assembler/debug-info.ll | 4 +- llvm/test/Assembler/disubrange-empty-array.ll | 4 +- .../invalid-disubrange-count-missing.ll | 3 +- llvm/test/Bindings/llvm-c/debug_info.ll | 2 +- llvm/test/Bitcode/fortranSubrange.ll | 44 ++++++ llvm/test/Bitcode/fortranSubrangeBackward.ll | 50 +++++++ .../Bitcode/fortranSubrangeBackward.ll.bc | Bin 0 -> 2064 bytes .../DebugInfo/X86/default-subrange-array.ll | 2 +- .../X86/nondefault-subrange-array.ll | 2 +- llvm/test/DebugInfo/cDefaultLower.ll | 35 +++++ llvm/test/DebugInfo/fortranDefaultLower.ll | 35 +++++ llvm/test/DebugInfo/fortranSubrangeExpr.ll | 44 ++++++ llvm/test/DebugInfo/fortranSubrangeInt.ll | 43 ++++++ llvm/test/DebugInfo/fortranSubrangeVar.ll | 62 ++++++++ .../Verifier/disubrange-count-upperBound.ll | 5 + .../Verifier/disubrange-missing-upperBound.ll | 5 + .../Verifier/invalid-disubrange-lowerBound.ll | 6 + .../Verifier/invalid-disubrange-stride.ll | 6 + .../Verifier/invalid-disubrange-upperBound.ll | 6 + llvm/unittests/IR/MetadataTest.cpp | 139 +++++++++++++++++- 34 files changed, 813 insertions(+), 84 deletions(-) create mode 100644 llvm/test/Bitcode/fortranSubrange.ll create mode 100644 llvm/test/Bitcode/fortranSubrangeBackward.ll create mode 100644 llvm/test/Bitcode/fortranSubrangeBackward.ll.bc create mode 100644 llvm/test/DebugInfo/cDefaultLower.ll create mode 100644 llvm/test/DebugInfo/fortranDefaultLower.ll create mode 100644 llvm/test/DebugInfo/fortranSubrangeExpr.ll create mode 100644 llvm/test/DebugInfo/fortranSubrangeInt.ll create mode 100644 llvm/test/DebugInfo/fortranSubrangeVar.ll create mode 100644 llvm/test/Verifier/disubrange-count-upperBound.ll create mode 100644 llvm/test/Verifier/disubrange-missing-upperBound.ll create mode 100644 llvm/test/Verifier/invalid-disubrange-lowerBound.ll create mode 100644 llvm/test/Verifier/invalid-disubrange-stride.ll create mode 100644 llvm/test/Verifier/invalid-disubrange-upperBound.ll diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 7ec792ca0e1f..4e0b6aa0dca6 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2732,9 +2732,17 @@ llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty, QualType QTy(Ty, 0); auto SizeExpr = SizeExprCache.find(QTy); if (SizeExpr != SizeExprCache.end()) - Subscript = DBuilder.getOrCreateSubrange(0, SizeExpr->getSecond()); - else - Subscript = DBuilder.getOrCreateSubrange(0, Count ? Count : -1); + Subscript = DBuilder.getOrCreateSubrange( + SizeExpr->getSecond() /*count*/, nullptr /*lowerBound*/, + nullptr /*upperBound*/, nullptr /*stride*/); + else { + auto *CountNode = + llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( + llvm::Type::getInt64Ty(CGM.getLLVMContext()), Count ? Count : -1)); + Subscript = DBuilder.getOrCreateSubrange( + CountNode /*count*/, nullptr /*lowerBound*/, nullptr /*upperBound*/, + nullptr /*stride*/); + } llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); uint64_t Size = CGM.getContext().getTypeSize(Ty); @@ -2754,8 +2762,18 @@ llvm::DIType *CGDebugInfo::CreateType(const ConstantMatrixType *Ty, // Create ranges for both dimensions. llvm::SmallVector Subscripts; - Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Ty->getNumColumns())); - Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Ty->getNumRows())); + auto *ColumnCountNode = + llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( + llvm::Type::getInt64Ty(CGM.getLLVMContext()), Ty->getNumColumns())); + auto *RowCountNode = + llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( + llvm::Type::getInt64Ty(CGM.getLLVMContext()), Ty->getNumRows())); + Subscripts.push_back(DBuilder.getOrCreateSubrange( + ColumnCountNode /*count*/, nullptr /*lowerBound*/, nullptr /*upperBound*/, + nullptr /*stride*/)); + Subscripts.push_back(DBuilder.getOrCreateSubrange( + RowCountNode /*count*/, nullptr /*lowerBound*/, nullptr /*upperBound*/, + nullptr /*stride*/)); llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts); return DBuilder.createArrayType(Size, Align, ElementTy, SubscriptArray); } @@ -2810,10 +2828,17 @@ llvm::DIType *CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIFile *Unit) { auto SizeNode = SizeExprCache.find(EltTy); if (SizeNode != SizeExprCache.end()) - Subscripts.push_back( - DBuilder.getOrCreateSubrange(0, SizeNode->getSecond())); - else - Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count)); + Subscripts.push_back(DBuilder.getOrCreateSubrange( + SizeNode->getSecond() /*count*/, nullptr /*lowerBound*/, + nullptr /*upperBound*/, nullptr /*stride*/)); + else { + auto *CountNode = + llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( + llvm::Type::getInt64Ty(CGM.getLLVMContext()), Count)); + Subscripts.push_back(DBuilder.getOrCreateSubrange( + CountNode /*count*/, nullptr /*lowerBound*/, nullptr /*upperBound*/, + nullptr /*stride*/)); + } EltTy = Ty->getElementType(); } diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index d63ca34c573b..d1c7d126b5a9 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -573,6 +573,8 @@ namespace llvm { /// implicitly uniques the values returned. DISubrange *getOrCreateSubrange(int64_t Lo, int64_t Count); DISubrange *getOrCreateSubrange(int64_t Lo, Metadata *CountNode); + DISubrange *getOrCreateSubrange(Metadata *Count, Metadata *LowerBound, + Metadata *UpperBound, Metadata *Stride); /// Create a new descriptor for the specified variable. /// \param Context Variable scope. diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 7dca44247c04..900a4b561cda 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -287,12 +287,8 @@ class DISubrange : public DINode { friend class LLVMContextImpl; friend class MDNode; - int64_t LowerBound; - - DISubrange(LLVMContext &C, StorageType Storage, Metadata *Node, - int64_t LowerBound, ArrayRef Ops) - : DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, Ops), - LowerBound(LowerBound) {} + DISubrange(LLVMContext &C, StorageType Storage, ArrayRef Ops) + : DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, Ops) {} ~DISubrange() = default; @@ -304,8 +300,14 @@ class DISubrange : public DINode { int64_t LowerBound, StorageType Storage, bool ShouldCreate = true); + static DISubrange *getImpl(LLVMContext &Context, Metadata *CountNode, + Metadata *LowerBound, Metadata *UpperBound, + Metadata *Stride, StorageType Storage, + bool ShouldCreate = true); + TempDISubrange cloneImpl() const { - return getTemporary(getContext(), getRawCountNode(), getLowerBound()); + return getTemporary(getContext(), getRawCountNode(), getRawLowerBound(), + getRawUpperBound(), getRawStride()); } public: @@ -315,25 +317,33 @@ public: DEFINE_MDNODE_GET(DISubrange, (Metadata *CountNode, int64_t LowerBound = 0), (CountNode, LowerBound)) - TempDISubrange clone() const { return cloneImpl(); } + DEFINE_MDNODE_GET(DISubrange, + (Metadata * CountNode, Metadata *LowerBound, + Metadata *UpperBound, Metadata *Stride), + (CountNode, LowerBound, UpperBound, Stride)) - int64_t getLowerBound() const { return LowerBound; } + TempDISubrange 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(); } + typedef PointerUnion CountType; + typedef PointerUnion BoundType; - CountType getCount() const { - if (auto *MD = dyn_cast(getRawCountNode())) - return CountType(cast(MD->getValue())); + CountType getCount() const; - if (auto *DV = dyn_cast(getRawCountNode())) - return CountType(DV); + BoundType getLowerBound() const; - return CountType(); - } + BoundType getUpperBound() const; + + BoundType getStride() const; static bool classof(const Metadata *MD) { return MD->getMetadataID() == DISubrangeKind; diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 9e8fe96ac3a8..a2c1b3f632af 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4500,21 +4500,41 @@ bool LLParser::ParseGenericDINode(MDNode *&Result, bool IsDistinct) { /// ParseDISubrange: /// ::= !DISubrange(count: 30, lowerBound: 2) /// ::= !DISubrange(count: !node, lowerBound: 2) +/// ::= !DISubrange(lowerBound: !node1, upperBound: !node2, stride: !node3) bool LLParser::ParseDISubrange(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ - REQUIRED(count, MDSignedOrMDField, (-1, -1, INT64_MAX, false)); \ - OPTIONAL(lowerBound, MDSignedField, ); + 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; if (count.isMDSignedField()) - Result = GET_OR_DISTINCT( - DISubrange, (Context, count.getMDSignedValue(), lowerBound.Val)); + Count = ConstantAsMetadata::get(ConstantInt::getSigned( + Type::getInt64Ty(Context), count.getMDSignedValue())); else if (count.isMDField()) - Result = GET_OR_DISTINCT( - DISubrange, (Context, count.getMDFieldValue(), lowerBound.Val)); - else - return true; + Count = count.getMDFieldValue(); + + 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; + }; + + LowerBound = convToMetadata(lowerBound); + UpperBound = convToMetadata(upperBound); + Stride = convToMetadata(stride); + + Result = GET_OR_DISTINCT(DISubrange, + (Context, Count, LowerBound, UpperBound, Stride)); return false; } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 7338d170cb48..34c93beebb01 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1258,14 +1258,24 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( // Operand 'count' is interpreted as: // - Signed integer (version 0) // - Metadata node (version 1) + // Operand 'lowerBound' is interpreted as: + // - Signed integer (version 0 and 1) + // - Metadata node (version 2) + // Operands 'upperBound' and 'stride' are interpreted as: + // - Metadata node (version 2) switch (Record[0] >> 1) { case 0: Val = GET_OR_DISTINCT(DISubrange, - (Context, Record[1], unrotateSign(Record.back()))); + (Context, Record[1], unrotateSign(Record[2]))); break; case 1: Val = GET_OR_DISTINCT(DISubrange, (Context, getMDOrNull(Record[1]), - unrotateSign(Record.back()))); + unrotateSign(Record[2]))); + break; + case 2: + Val = GET_OR_DISTINCT( + DISubrange, (Context, getMDOrNull(Record[1]), getMDOrNull(Record[2]), + getMDOrNull(Record[3]), getMDOrNull(Record[4]))); break; default: return error("Invalid record: Unsupported version of DISubrange"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index fd4275f7d569..9da1437b56b2 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1527,10 +1527,12 @@ static uint64_t rotateSign(int64_t I) { void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N, SmallVectorImpl &Record, unsigned Abbrev) { - const uint64_t Version = 1 << 1; + const uint64_t Version = 2 << 1; Record.push_back((uint64_t)N->isDistinct() | Version); Record.push_back(VE.getMetadataOrNullID(N->getRawCountNode())); - Record.push_back(rotateSign(N->getLowerBound())); + 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_SUBRANGE, Record, Abbrev); Record.clear(); diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index de2b9bcc58c7..f7041c0cc926 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1592,7 +1592,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { assert(Element->getTag() == dwarf::DW_TAG_subrange_type); const DISubrange *Subrange = cast(Element); - assert(Subrange->getLowerBound() == 0 && + assert(!Subrange->getRawLowerBound() && "codeview doesn't support subranges with lower bounds"); int64_t Count = -1; if (auto *CI = Subrange->getCount().dyn_cast()) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index dce90b3c17c0..8d6849b4e1e3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -768,9 +768,18 @@ static SmallVector dependencies(DbgVariable *Var) { Result.push_back(DLVar); for (auto *El : Array->getElements()) { if (auto *Subrange = dyn_cast(El)) { - auto Count = Subrange->getCount(); - if (auto *Dependency = Count.dyn_cast()) - Result.push_back(Dependency); + if (auto Count = Subrange->getCount()) + if (auto *Dependency = Count.dyn_cast()) + Result.push_back(Dependency); + if (auto LB = Subrange->getLowerBound()) + if (auto *Dependency = LB.dyn_cast()) + Result.push_back(Dependency); + if (auto UB = Subrange->getUpperBound()) + if (auto *Dependency = UB.dyn_cast()) + Result.push_back(Dependency); + if (auto ST = Subrange->getStride()) + if (auto *Dependency = ST.dyn_cast()) + Result.push_back(Dependency); } } return Result; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 62bf51d42206..e958f38e486b 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1349,20 +1349,40 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, // C/C++. The Count value is the number of elements. Values are 64 bit. If // Count == -1 then the array is unbounded and we do not emit // DW_AT_lower_bound and DW_AT_count attributes. - int64_t LowerBound = SR->getLowerBound(); int64_t DefaultLowerBound = getDefaultLowerBound(); int64_t Count = -1; if (auto *CI = SR->getCount().dyn_cast()) Count = CI->getSExtValue(); - if (DefaultLowerBound == -1 || LowerBound != DefaultLowerBound) - addUInt(DW_Subrange, dwarf::DW_AT_lower_bound, None, LowerBound); + auto addBoundTypeEntry = [&](dwarf::Attribute Attr, + DISubrange::BoundType Bound) -> void { + if (auto *BV = Bound.dyn_cast()) { + if (auto *VarDIE = getDIE(BV)) + addDIEEntry(DW_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_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_Subrange, Attr, dwarf::DW_FORM_sdata, BI->getSExtValue()); + } + }; + + addBoundTypeEntry(dwarf::DW_AT_lower_bound, SR->getLowerBound()); if (auto *CV = SR->getCount().dyn_cast()) { if (auto *CountVarDIE = getDIE(CV)) addDIEEntry(DW_Subrange, dwarf::DW_AT_count, *CountVarDIE); } else if (Count != -1) addUInt(DW_Subrange, dwarf::DW_AT_count, None, Count); + + addBoundTypeEntry(dwarf::DW_AT_upper_bound, SR->getUpperBound()); + + addBoundTypeEntry(dwarf::DW_AT_byte_stride, SR->getStride()); } DIE *DwarfUnit::getIndexTyDie() { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 72da461ddcb8..68edb6bad939 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1858,9 +1858,34 @@ static void writeDISubrange(raw_ostream &Out, const DISubrange *N, if (auto *CE = N->getCount().dyn_cast()) Printer.printInt("count", CE->getSExtValue(), /* ShouldSkipZero */ false); else - Printer.printMetadata("count", N->getCount().dyn_cast(), - /*ShouldSkipNull */ false); - Printer.printInt("lowerBound", N->getLowerBound()); + Printer.printMetadata("count", N->getCount().dyn_cast(), + /*ShouldSkipNull */ true); + + // A lowerBound of constant 0 should not be skipped, since it is different + // from an unspecified lower bound (= nullptr). + 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 << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 95841be53477..45cbbb3a6037 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -625,11 +625,22 @@ DITypeRefArray DIBuilder::getOrCreateTypeArray(ArrayRef Elements) { } DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, int64_t Count) { - return DISubrange::get(VMContext, Count, Lo); + auto *LB = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(VMContext), Lo)); + auto *CountNode = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(VMContext), Count)); + return DISubrange::get(VMContext, CountNode, LB, nullptr, nullptr); } DISubrange *DIBuilder::getOrCreateSubrange(int64_t Lo, Metadata *CountNode) { - return DISubrange::get(VMContext, CountNode, Lo); + auto *LB = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(VMContext), Lo)); + return DISubrange::get(VMContext, CountNode, LB, nullptr, nullptr); +} + +DISubrange *DIBuilder::getOrCreateSubrange(Metadata *CountNode, Metadata *LB, + Metadata *UB, Metadata *Stride) { + return DISubrange::get(VMContext, CountNode, LB, UB, Stride); } static void checkGlobalVariableScope(DIScope *Context) { diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index f1e946c1902e..ea90d6842c31 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -336,15 +336,103 @@ DISubrange *DISubrange::getImpl(LLVMContext &Context, int64_t Count, int64_t Lo, StorageType Storage, bool ShouldCreate) { auto *CountNode = ConstantAsMetadata::get( ConstantInt::getSigned(Type::getInt64Ty(Context), Count)); - return getImpl(Context, CountNode, Lo, Storage, ShouldCreate); + auto *LB = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), Lo)); + return getImpl(Context, CountNode, LB, nullptr, nullptr, Storage, + ShouldCreate); } DISubrange *DISubrange::getImpl(LLVMContext &Context, Metadata *CountNode, int64_t Lo, StorageType Storage, bool ShouldCreate) { - DEFINE_GETIMPL_LOOKUP(DISubrange, (CountNode, Lo)); - Metadata *Ops[] = { CountNode }; - DEFINE_GETIMPL_STORE(DISubrange, (CountNode, Lo), Ops); + auto *LB = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), Lo)); + return getImpl(Context, CountNode, LB, nullptr, nullptr, Storage, + ShouldCreate); +} + +DISubrange *DISubrange::getImpl(LLVMContext &Context, Metadata *CountNode, + Metadata *LB, Metadata *UB, Metadata *Stride, + StorageType Storage, bool ShouldCreate) { + DEFINE_GETIMPL_LOOKUP(DISubrange, (CountNode, LB, UB, Stride)); + Metadata *Ops[] = {CountNode, LB, UB, Stride}; + DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DISubrange, Ops); +} + +DISubrange::CountType DISubrange::getCount() const { + if (!getRawCountNode()) + return CountType(); + + if (auto *MD = dyn_cast(getRawCountNode())) + return CountType(cast(MD->getValue())); + + if (auto *DV = dyn_cast(getRawCountNode())) + return CountType(DV); + + return CountType(); +} + +DISubrange::BoundType DISubrange::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(); +} + +DISubrange::BoundType DISubrange::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(); +} + +DISubrange::BoundType DISubrange::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, APInt Value, diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 9912808c53c2..1c7d8746d242 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -323,32 +323,46 @@ template <> struct MDNodeKeyImpl : MDNodeOpsKey { template <> struct MDNodeKeyImpl { Metadata *CountNode; - int64_t LowerBound; + Metadata *LowerBound; + Metadata *UpperBound; + Metadata *Stride; - MDNodeKeyImpl(Metadata *CountNode, int64_t LowerBound) - : CountNode(CountNode), LowerBound(LowerBound) {} + MDNodeKeyImpl(Metadata *CountNode, Metadata *LowerBound, Metadata *UpperBound, + Metadata *Stride) + : CountNode(CountNode), LowerBound(LowerBound), UpperBound(UpperBound), + Stride(Stride) {} MDNodeKeyImpl(const DISubrange *N) - : CountNode(N->getRawCountNode()), - LowerBound(N->getLowerBound()) {} + : CountNode(N->getRawCountNode()), LowerBound(N->getRawLowerBound()), + UpperBound(N->getRawUpperBound()), Stride(N->getRawStride()) {} bool isKeyOf(const DISubrange *RHS) const { - if (LowerBound != RHS->getLowerBound()) - return false; + auto BoundsEqual = [=](Metadata *Node1, Metadata *Node2) -> bool { + if (Node1 == Node2) + return true; - if (auto *RHSCount = RHS->getCount().dyn_cast()) - if (auto *MD = dyn_cast(CountNode)) - if (RHSCount->getSExtValue() == - cast(MD->getValue())->getSExtValue()) + 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 CountNode == RHS->getRawCountNode(); + return BoundsEqual(CountNode, RHS->getRawCountNode()) && + BoundsEqual(LowerBound, RHS->getRawLowerBound()) && + BoundsEqual(UpperBound, RHS->getRawUpperBound()) && + BoundsEqual(Stride, RHS->getRawStride()); } unsigned getHashValue() const { - if (auto *MD = dyn_cast(CountNode)) - return hash_combine(cast(MD->getValue())->getSExtValue(), - LowerBound); - return hash_combine(CountNode, LowerBound); + 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); } }; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index c39fb0edc714..388fc72417ad 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -893,12 +893,30 @@ void Verifier::visitDIScope(const DIScope &N) { void Verifier::visitDISubrange(const DISubrange &N) { AssertDI(N.getTag() == dwarf::DW_TAG_subrange_type, "invalid tag", &N); + AssertDI(N.getRawCountNode() || N.getRawUpperBound(), + "Subrange must contain count or upperBound", &N); + AssertDI(!N.getRawCountNode() || !N.getRawUpperBound(), + "Subrange can have any one of count or upperBound", &N); + AssertDI(!N.getRawCountNode() || N.getCount(), + "Count must either be a signed constant or a DIVariable", &N); auto Count = N.getCount(); - AssertDI(Count, "Count must either be a signed constant or a DIVariable", - &N); - AssertDI(!Count.is() || - Count.get()->getSExtValue() >= -1, + AssertDI(!Count || !Count.is() || + Count.get()->getSExtValue() >= -1, "invalid subrange count", &N); + auto *LBound = N.getRawLowerBound(); + AssertDI(!LBound || 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 || isa(Stride) || + isa(Stride) || isa(Stride), + "Stride must be signed constant or DIVariable or DIExpression", &N); } void Verifier::visitDIEnumerator(const DIEnumerator &N) { diff --git a/llvm/test/Assembler/debug-info.ll b/llvm/test/Assembler/debug-info.ll index d54dba07ac1e..419623a2cb7d 100644 --- a/llvm/test/Assembler/debug-info.ll +++ b/llvm/test/Assembler/debug-info.ll @@ -4,10 +4,10 @@ ; CHECK: !named = !{!0, !0, !1, !2, !3, !4, !5, !6, !7, !8, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39} !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34, !35, !36, !37, !38, !39, !40, !41, !42} -; CHECK: !0 = !DISubrange(count: 3) +; CHECK: !0 = !DISubrange(count: 3, lowerBound: 0) ; CHECK-NEXT: !1 = !DISubrange(count: 3, lowerBound: 4) ; CHECK-NEXT: !2 = !DISubrange(count: 3, lowerBound: -5) -!0 = !DISubrange(count: 3) +!0 = !DISubrange(count: 3, lowerBound: 0) !1 = !DISubrange(count: 3, lowerBound: 0) !2 = !DISubrange(count: 3, lowerBound: 4) diff --git a/llvm/test/Assembler/disubrange-empty-array.ll b/llvm/test/Assembler/disubrange-empty-array.ll index 7b5279e3d3c2..ef0ca0e81a27 100644 --- a/llvm/test/Assembler/disubrange-empty-array.ll +++ b/llvm/test/Assembler/disubrange-empty-array.ll @@ -4,10 +4,10 @@ ; CHECK: !named = !{!0, !0, !1, !2} !named = !{!0, !1, !2, !3} -; CHECK: !0 = !DISubrange(count: -1) +; CHECK: !0 = !DISubrange(count: -1, lowerBound: 0) ; CHECK-NEXT: !1 = !DISubrange(count: -1, lowerBound: 4) ; CHECK-NEXT: !2 = !DISubrange(count: -1, lowerBound: -5) -!0 = !DISubrange(count: -1) +!0 = !DISubrange(count: -1, lowerBound: 0) !1 = !DISubrange(count: -1, lowerBound: 0) !2 = !DISubrange(count: -1, lowerBound: 4) diff --git a/llvm/test/Assembler/invalid-disubrange-count-missing.ll b/llvm/test/Assembler/invalid-disubrange-count-missing.ll index 8fc4487117f6..8b7bf713a8e9 100644 --- a/llvm/test/Assembler/invalid-disubrange-count-missing.ll +++ b/llvm/test/Assembler/invalid-disubrange-count-missing.ll @@ -1,4 +1,5 @@ ; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s -; CHECK: [[@LINE+1]]:32: error: missing required field 'count' +!named = !{!0} +; CHECK: Subrange must contain count or upperBound !0 = !DISubrange(lowerBound: -3) diff --git a/llvm/test/Bindings/llvm-c/debug_info.ll b/llvm/test/Bindings/llvm-c/debug_info.ll index 59d9628ff009..d56873f1cb25 100644 --- a/llvm/test/Bindings/llvm-c/debug_info.ll +++ b/llvm/test/Bindings/llvm-c/debug_info.ll @@ -60,7 +60,7 @@ ; CHECK-NEXT: !33 = !{!6, !6, !34} ; CHECK-NEXT: !34 = !DICompositeType(tag: DW_TAG_array_type, baseType: !6, size: 640, flags: DIFlagVector, elements: !35) ; CHECK-NEXT: !35 = !{!36} -; CHECK-NEXT: !36 = !DISubrange(count: 10) +; CHECK-NEXT: !36 = !DISubrange(count: 10, lowerBound: 0) ; CHECK-NEXT: !37 = !{!38, !39, !40, !41} ; CHECK-NEXT: !38 = !DILocalVariable(name: "a", arg: 1, scope: !31, file: !1, line: 42, type: !6) ; CHECK-NEXT: !39 = !DILocalVariable(name: "b", arg: 2, scope: !31, file: !1, line: 42, type: !6) diff --git a/llvm/test/Bitcode/fortranSubrange.ll b/llvm/test/Bitcode/fortranSubrange.ll new file mode 100644 index 000000000000..7b97be5b352d --- /dev/null +++ b/llvm/test/Bitcode/fortranSubrange.ll @@ -0,0 +1,44 @@ +;; This test checks DISubrange bounds + +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +;; Test whether bounds are generated correctly. +; CHECK: !{{[0-9]+}} = !DISubrange(lowerBound: 3, upperBound: ![[NODE:[0-9]+]], stride: !DIExpression(DW_OP_constu, 4)) +; CHECK: ![[NODE]] = distinct !DILocalVariable + + +; ModuleID = 'fortsubrange.ll' +source_filename = "fortsubrange.ll" + +define void @MAIN_() !dbg !5 { +L.entry: + %.Z0640_333 = alloca i32*, align 8 + %"arr$sd1_349" = alloca [16 x i64], align 8 + call void @llvm.dbg.declare(metadata i32** %.Z0640_333, metadata !8, metadata !DIExpression(DW_OP_deref)), !dbg !15 + call void @llvm.dbg.declare(metadata [16 x i64]* %"arr$sd1_349", metadata !13, metadata !DIExpression(DW_OP_plus_uconst, 120)), !dbg !15 + ret void, !dbg !16 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(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: "fortsubrange.f90", directory: "/dir") +!4 = !{} +!5 = distinct !DISubprogram(name: "main", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2) +!6 = !DISubroutineType(cc: DW_CC_program, types: !7) +!7 = !{null} +!8 = !DILocalVariable(name: "arr", scope: !5, file: !3, type: !9) +!9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 32, align: 32, elements: !11) +!10 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DISubrange(lowerBound: 3, upperBound: !13, stride: !DIExpression(DW_OP_constu, 4)) +!13 = distinct !DILocalVariable(scope: !5, file: !3, type: !14, flags: DIFlagArtificial) +!14 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) +!15 = !DILocation(line: 0, scope: !5) +!16 = !DILocation(line: 6, column: 1, scope: !5) diff --git a/llvm/test/Bitcode/fortranSubrangeBackward.ll b/llvm/test/Bitcode/fortranSubrangeBackward.ll new file mode 100644 index 000000000000..ffa987e2f01e --- /dev/null +++ b/llvm/test/Bitcode/fortranSubrangeBackward.ll @@ -0,0 +1,50 @@ +;; This test checks Backward compatibility of DISubrange bounds +; REQUIRES: x86_64-linux + +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +;; Test whether bounds are generated correctly. +; CHECK: !DISubrange(count: 15, lowerBound: 3) +; CHECK: !DISubrange(count: ![[NODE:[0-9]+]], lowerBound: 3) +; CHECK: ![[NODE]] = distinct !DILocalVariable + + +; ModuleID = 'fortsubrange.ll' +source_filename = "fortsubrange.ll" + +define void @MAIN_() !dbg !10 { +L.entry: + %.Z0640_333 = alloca i32*, align 8 + %"arr$sd1_349" = alloca [16 x i64], align 8 + call void @llvm.dbg.declare(metadata i32** %.Z0640_333, metadata !13, metadata !DIExpression(DW_OP_deref)), !dbg !19 + call void @llvm.dbg.declare(metadata [16 x i64]* %"arr$sd1_349", metadata !17, metadata !DIExpression(DW_OP_plus_uconst, 120)), !dbg !19 + ret void, !dbg !20 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(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: !5, globals: !4, imports: !4) +!3 = !DIFile(filename: "fortsubrange.f90", directory: "/dir") +!4 = !{} +!5 = !{!6} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !8) +!7 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{!9} +!9 = !DISubrange(count: 15, lowerBound: 3) +!10 = distinct !DISubprogram(name: "main", scope: !2, file: !3, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2) +!11 = !DISubroutineType(cc: DW_CC_program, types: !12) +!12 = !{null} +!13 = !DILocalVariable(name: "arr", scope: !10, file: !3, type: !14) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !15) +!15 = !{!16} +!16 = !DISubrange(count: !17, lowerBound: 3) +!17 = distinct !DILocalVariable(scope: !10, file: !3, type: !18, flags: DIFlagArtificial) +!18 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) +!19 = !DILocation(line: 0, scope: !10) +!20 = !DILocation(line: 6, column: 1, scope: !10) diff --git a/llvm/test/Bitcode/fortranSubrangeBackward.ll.bc b/llvm/test/Bitcode/fortranSubrangeBackward.ll.bc new file mode 100644 index 0000000000000000000000000000000000000000..00e427b1cdaa2a65525d6002c20b53b41cdf6e63 GIT binary patch literal 2064 zcmY*aeN0=|6~F#`PH>)|2~CW!y=Nean+5W02gk;y!+w;2N>-z771dJ3&tLblh*l)90Z(Wt6e8X*`TO)8qwHJh>~T6dn4 zRN9fwIrpA(-?_hY?>YCm>D+Ql4MH-6kWWc99)JEXffw#ydA6?9*da2@kU@#iyCQ_D z#0DgWHG6=u>4sTXN!l$Z%=Yu5xN@INQLC4};)@bbi{0m|+;PHOV^e6J*=cqsy4ZO` zLq|2ABwXjk10}`f8j|izke`Um?zrZl@nFhyHhW^0oG(G#mq>(g(B^u@4szg}ba(xw zIEc0QT&kwJCy}g*$9o8>0qsLCPeYv4kOJC015BOGNgVfNj!ew@HWu!~!V&%q%Uiwt7|T!Pc&iNyzs>J@%Y%FxSeyOgLTP%*ZP zx`Kr9#X5viGBJ{a&8$x=Yt=oeS+-BD~Zf}Ku}DmRhpYXZL;#Vty=zL3{lo6`m;S!G$Qt}JOQ(QQddTRD;(W3e*| zY_f}IS!{}xOhkB=E6r)w=d|UDyvb;<8npA%x~q)*^Av3_(e`vjzE`weplu0><3jN;Z2Dlv z@tMStEh;}A=Gi`;V`F1OSOo4{!;fY7+H1d1-9f57z>qW&tQy=BlX z=XJjo=>@;T&sWwQ}zdd+}z}F}orr)i|Z?E9%9{e6fuih}|Hs`e4q6%`R z^RvGfZE#uH;^8H_wM@4r=vK&jk$wtIk_fq=rZ{~UNhg%GJ2-O}*)W})o&B^ULl_5~ zCbRpsl;ICU(C~)erC2)!xJ3a2>n9!iV zIbf#_4-9i;r=21@gJ2??NKd%lU!Qbx^d#ha_Ot3t0&4!g=?Fg>OK4STCIPw?loVwym9&cUNJnF??8VE z?_t$W&IomjP4%&9x(&)NOWPNVGn?9lxm~whLR)PbbPwxc&yh7R{-p=XOtmf)o9ass zem5JP#wLxGE{O1OgF+1mXg(!SrN6PV^HR)l5eiz;mWer`xKl*|H$x)yH0a$@*CAM1 z$$4NOLf=vd>0w@ftd#1-rLy@HLLD z@nb3DLKby`NfmnHKFuY{$0AZ8mvaAw2f6q?2-R&6KPzi$P*jvl {[[BASE2:0x[0-9a-f]*]]} -; CHECK-NEXT: DW_AT_lower_bound [DW_FORM_data8] (0xfffffffffffffffd) +; CHECK-NEXT: DW_AT_lower_bound [DW_FORM_sdata] (-3) ; CHECK-NEXT: DW_AT_count [DW_FORM_data1] (0x2a) ; CHECK: [[BASE]]: DW_TAG_base_type diff --git a/llvm/test/DebugInfo/cDefaultLower.ll b/llvm/test/DebugInfo/cDefaultLower.ll new file mode 100644 index 000000000000..7cd37fe845b3 --- /dev/null +++ b/llvm/test/DebugInfo/cDefaultLower.ll @@ -0,0 +1,35 @@ +;; This test checks whether c default lowerBound is removed. +; REQUIRES: x86_64-linux + +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +;; c default DW_AT_lower_bound(0) is not dumped. +; CHECK-LABEL: DW_TAG_subrange_type +; CHECK-NEXT: DW_AT_type +; CHECK-NEXT: DW_AT_upper_bound (4) + +;; c non-default lowerBound=1 is dumped. +; CHECK-LABEL: DW_TAG_subrange_type +; CHECK-NEXT: DW_AT_type +; CHECK-NEXT: DW_AT_lower_bound (1) +; CHECK-NEXT: DW_AT_upper_bound (5) + +; ModuleID = 'cDefaultLower.c' +source_filename = "cDefaultLower.c" + +!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_C99, file: !3, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4) +!3 = !DIFile(filename: "cDefaultLower.c", directory: "dir") +!4 = !{} +!5 = !{!6, !10} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 160, align: 32, elements: !8) +!7 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{!9} +!9 = !DISubrange(lowerBound: 0, upperBound: 4) +!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 160, align: 32, elements: !11) +!11 = !{!12} +!12 = !DISubrange(lowerBound: 1, upperBound: 5) diff --git a/llvm/test/DebugInfo/fortranDefaultLower.ll b/llvm/test/DebugInfo/fortranDefaultLower.ll new file mode 100644 index 000000000000..face5d12fc4f --- /dev/null +++ b/llvm/test/DebugInfo/fortranDefaultLower.ll @@ -0,0 +1,35 @@ +;; This test checks whether fortran default lowerBound is removed. +; REQUIRES: x86_64-linux + +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +;; fortran default DW_AT_lower_bound(1) is not dumped. +; CHECK-LABEL: DW_TAG_subrange_type +; CHECK-NEXT: DW_AT_type +; CHECK-NEXT: DW_AT_upper_bound (5) + +;; fortran non-default lowerBound=2 is dumped. +; CHECK-LABEL: DW_TAG_subrange_type +; CHECK-NEXT: DW_AT_type +; CHECK-NEXT: DW_AT_lower_bound (2) +; CHECK-NEXT: DW_AT_upper_bound (6) + +; ModuleID = 'fortranDefaultLower.ll' +source_filename = "fortranDefaultLower.f90" + +!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: "fortranDefaultLower.f90", directory: "dir") +!4 = !{} +!5 = !{!6, !10} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 160, align: 32, elements: !8) +!7 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!8 = !{!9} +!9 = !DISubrange(lowerBound: 1, upperBound: 5) +!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 160, align: 32, elements: !11) +!11 = !{!12} +!12 = !DISubrange(lowerBound: 2, upperBound: 6) diff --git a/llvm/test/DebugInfo/fortranSubrangeExpr.ll b/llvm/test/DebugInfo/fortranSubrangeExpr.ll new file mode 100644 index 000000000000..5ad5635cc6dc --- /dev/null +++ b/llvm/test/DebugInfo/fortranSubrangeExpr.ll @@ -0,0 +1,44 @@ +;; This test checks DISubrange bounds for DIExpression +; REQUIRES: x86_64-linux + +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +;; Test whether bounds are generated correctly. +; CHECK-LABEL: DW_TAG_array_type +; CHECK: DW_TAG_subrange_type +; DW_AT_lower_bound (DW_OP_push_object_address, DW_OP_plus_uconst 0x50, DW_OP_deref) +; CHECK: DW_AT_lower_bound (DW_OP_push_object_address, DW_OP_plus_uconst 0x50, DW_OP_deref) +; CHECK-NEXT: DW_AT_upper_bound (DW_OP_push_object_address, DW_OP_plus_uconst 0x78, DW_OP_deref) +; CHECK-NEXT: DW_AT_byte_stride (DW_OP_push_object_address, DW_OP_plus_uconst 0x70, DW_OP_deref, DW_OP_plus_uconst 0x4, DW_OP_mul) + +; ModuleID = 'fortsubrange.modified.strategy3check-in.ll' +source_filename = "fortsubrange.ll" + +define void @MAIN_() !dbg !5 { +L.entry: + %"arr$sd1_349" = alloca [16 x i64], align 8 + call void @llvm.dbg.declare(metadata [16 x i64]* %"arr$sd1_349", metadata !8, metadata !DIExpression()), !dbg !13 + ret void, !dbg !14 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(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: "fortsubrange.f90", directory: "/dir") +!4 = !{} +!5 = distinct !DISubprogram(name: "main", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2) +!6 = !DISubroutineType(cc: DW_CC_program, types: !7) +!7 = !{null} +!8 = !DILocalVariable(name: "arr", scope: !5, file: !3, type: !9) +!9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 32, align: 32, elements: !11) +!10 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 80, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 120, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 112, DW_OP_deref, DW_OP_plus_uconst, 4, DW_OP_mul)) +!13 = !DILocation(line: 0, scope: !5) +!14 = !DILocation(line: 6, column: 1, scope: !5) diff --git a/llvm/test/DebugInfo/fortranSubrangeInt.ll b/llvm/test/DebugInfo/fortranSubrangeInt.ll new file mode 100644 index 000000000000..34290b929cdb --- /dev/null +++ b/llvm/test/DebugInfo/fortranSubrangeInt.ll @@ -0,0 +1,43 @@ +;; This test checks DISubrange bounds for constants +; REQUIRES: x86_64-linux + +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +;; Test whether bounds are generated correctly. +; CHECK-LABEL: DW_TAG_array_type +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_lower_bound (-10) +; CHECK-NEXT: DW_AT_upper_bound (10) +; CHECK-NEXT: DW_AT_byte_stride (4) + +; ModuleID = 'fortsubrange.ll' +source_filename = "fortsubrange.ll" + +define void @MAIN_() !dbg !5 { +L.entry: + %"arr$sd1_349" = alloca [16 x i64], align 8 + call void @llvm.dbg.declare(metadata [16 x i64]* %"arr$sd1_349", metadata !8, metadata !DIExpression()), !dbg !13 + ret void, !dbg !14 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(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: "fortsubrange.f90", directory: "/dir") +!4 = !{} +!5 = distinct !DISubprogram(name: "main", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2) +!6 = !DISubroutineType(cc: DW_CC_program, types: !7) +!7 = !{null} +!8 = !DILocalVariable(name: "arr", scope: !5, file: !3, type: !9) +!9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 32, align: 32, elements: !11) +!10 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DISubrange(lowerBound: -10, upperBound: 10, stride: 4) +!13 = !DILocation(line: 0, scope: !5) +!14 = !DILocation(line: 6, column: 1, scope: !5) diff --git a/llvm/test/DebugInfo/fortranSubrangeVar.ll b/llvm/test/DebugInfo/fortranSubrangeVar.ll new file mode 100644 index 000000000000..5ee283e4b21e --- /dev/null +++ b/llvm/test/DebugInfo/fortranSubrangeVar.ll @@ -0,0 +1,62 @@ +;; This test checks DISubrange bounds for DIVariable + +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +;; Test whether bounds are generated correctly. +; CHECK: [[DIE1:0x.+]]: DW_TAG_variable +; CHECK: DW_AT_location +; CHECK-SAME: DW_OP_plus_uconst 0x70, DW_OP_deref, DW_OP_lit4, DW_OP_mul +; CHECK: [[DIE2:0x.+]]: DW_TAG_variable +; CHECK: DW_AT_location +; CHECK-SAME: DW_OP_plus_uconst 0x78 +; CHECK: [[DIE3:0x.+]]: DW_TAG_variable +; CHECK: DW_AT_location +; CHECK-SAME: DW_OP_plus_uconst 0x50 +; CHECK: DW_TAG_subrange_type +; CHECK: DW_AT_lower_bound ([[DIE3]]) +; CHEK-NEXT: DW_AT_upper_bound ([[DIE2]]) +; CHECK-NEXT DW_AT_byte_stride ([[DIE1]]) + + +; ModuleID = 'fortsubrange.ll' +source_filename = "fortsubrange.ll" + +define void @MAIN_() !dbg !5 { +L.entry: + %.Z0640_333 = alloca i32*, align 8 + %"arr$sd1_349" = alloca [16 x i64], align 8 + call void @llvm.dbg.declare(metadata i32** %.Z0640_333, metadata !8, metadata !DIExpression(DW_OP_deref)), !dbg !17 + call void @llvm.dbg.declare(metadata [16 x i64]* %"arr$sd1_349", metadata !13, metadata !DIExpression(DW_OP_plus_uconst, 80)), !dbg !17 + call void @llvm.dbg.value(metadata [16 x i64]* %"arr$sd1_349", metadata !16, metadata !DIExpression(DW_OP_plus_uconst, 112, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul)), !dbg !17 + call void @llvm.dbg.declare(metadata [16 x i64]* %"arr$sd1_349", metadata !15, metadata !DIExpression(DW_OP_plus_uconst, 120)), !dbg !17 + 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: "fortsubrange.f90", directory: "/dir") +!4 = !{} +!5 = distinct !DISubprogram(name: "main", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2) +!6 = !DISubroutineType(cc: DW_CC_program, types: !7) +!7 = !{null} +!8 = !DILocalVariable(name: "arr", scope: !5, file: !3, type: !9) +!9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 32, align: 32, elements: !11) +!10 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DISubrange(lowerBound: !13, upperBound: !15, stride: !16) +!13 = distinct !DILocalVariable(scope: !5, file: !3, type: !14, flags: DIFlagArtificial) +!14 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) +!15 = distinct !DILocalVariable(scope: !5, file: !3, type: !14, flags: DIFlagArtificial) +!16 = distinct !DILocalVariable(scope: !5, file: !3, type: !14, flags: DIFlagArtificial) +!17 = !DILocation(line: 0, scope: !5) +!18 = !DILocation(line: 6, column: 1, scope: !5) diff --git a/llvm/test/Verifier/disubrange-count-upperBound.ll b/llvm/test/Verifier/disubrange-count-upperBound.ll new file mode 100644 index 000000000000..3dbc79004f02 --- /dev/null +++ b/llvm/test/Verifier/disubrange-count-upperBound.ll @@ -0,0 +1,5 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0} +; CHECK: Subrange can have any one of count or upperBound +!0 = !DISubrange(count: 20, lowerBound: 1, upperBound: 10) diff --git a/llvm/test/Verifier/disubrange-missing-upperBound.ll b/llvm/test/Verifier/disubrange-missing-upperBound.ll new file mode 100644 index 000000000000..26b707caa609 --- /dev/null +++ b/llvm/test/Verifier/disubrange-missing-upperBound.ll @@ -0,0 +1,5 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0} +; CHECK: Subrange must contain count or upperBound +!0 = !DISubrange(lowerBound: 1, stride: 4) diff --git a/llvm/test/Verifier/invalid-disubrange-lowerBound.ll b/llvm/test/Verifier/invalid-disubrange-lowerBound.ll new file mode 100644 index 000000000000..37a449a83290 --- /dev/null +++ b/llvm/test/Verifier/invalid-disubrange-lowerBound.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0, !1} +; CHECK: LowerBound must be signed constant or DIVariable or DIExpression +!0 = !DISubrange(lowerBound: !1, upperBound: 1) +!1 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) diff --git a/llvm/test/Verifier/invalid-disubrange-stride.ll b/llvm/test/Verifier/invalid-disubrange-stride.ll new file mode 100644 index 000000000000..eae6b625911e --- /dev/null +++ b/llvm/test/Verifier/invalid-disubrange-stride.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0, !1} +; CHECK: Stride must be signed constant or DIVariable or DIExpression +!0 = !DISubrange(upperBound: 1, stride: !1) +!1 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) diff --git a/llvm/test/Verifier/invalid-disubrange-upperBound.ll b/llvm/test/Verifier/invalid-disubrange-upperBound.ll new file mode 100644 index 000000000000..d4daa6ba7e1e --- /dev/null +++ b/llvm/test/Verifier/invalid-disubrange-upperBound.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +!named = !{!0, !1} +; CHECK: UpperBound must be signed constant or DIVariable or DIExpression +!0 = !DISubrange(lowerBound: 1, upperBound: !1) +!1 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed) diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index d785e469e728..038899ada964 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1139,11 +1139,12 @@ typedef MetadataTest DISubrangeTest; TEST_F(DISubrangeTest, get) { auto *N = DISubrange::get(Context, 5, 7); auto Count = N->getCount(); + auto Lower = N->getLowerBound(); EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); ASSERT_TRUE(Count); ASSERT_TRUE(Count.is()); EXPECT_EQ(5, Count.get()->getSExtValue()); - EXPECT_EQ(7, N->getLowerBound()); + EXPECT_EQ(7, Lower.get()->getSExtValue()); EXPECT_EQ(N, DISubrange::get(Context, 5, 7)); EXPECT_EQ(DISubrange::get(Context, 5, 0), DISubrange::get(Context, 5)); @@ -1154,11 +1155,12 @@ TEST_F(DISubrangeTest, get) { TEST_F(DISubrangeTest, getEmptyArray) { auto *N = DISubrange::get(Context, -1, 0); auto Count = N->getCount(); + auto Lower = N->getLowerBound(); EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); ASSERT_TRUE(Count); ASSERT_TRUE(Count.is()); EXPECT_EQ(-1, Count.get()->getSExtValue()); - EXPECT_EQ(0, N->getLowerBound()); + EXPECT_EQ(0, Lower.get()->getSExtValue()); EXPECT_EQ(N, DISubrange::get(Context, -1, 0)); } @@ -1172,15 +1174,146 @@ TEST_F(DISubrangeTest, getVariableCount) { auto *N = DISubrange::get(Context, VlaExpr, 0); auto Count = N->getCount(); + auto Lower = N->getLowerBound(); ASSERT_TRUE(Count); ASSERT_TRUE(Count.is()); EXPECT_EQ(VlaExpr, Count.get()); ASSERT_TRUE(isa(N->getRawCountNode())); - EXPECT_EQ(0, N->getLowerBound()); + EXPECT_EQ(0, Lower.get()->getSExtValue()); EXPECT_EQ("vla_expr", Count.get()->getName()); EXPECT_EQ(N, DISubrange::get(Context, VlaExpr, 0)); } +TEST_F(DISubrangeTest, fortranAllocatableInt) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + DIType *Type = getDerivedType(); + DINode::DIFlags Flags = static_cast(7); + auto *LI = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), -10)); + auto *UI = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), 10)); + auto *SI = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), 4)); + auto *UIother = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), 20)); + auto *UVother = DILocalVariable::get(Context, Scope, "ubother", File, 8, Type, + 2, Flags, 8); + auto *UEother = DIExpression::get(Context, {5, 6}); + auto *LIZero = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), 0)); + auto *UIZero = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), 0)); + + auto *N = DISubrange::get(Context, nullptr, LI, UI, SI); + + auto Lower = N->getLowerBound(); + ASSERT_TRUE(Lower); + ASSERT_TRUE(Lower.is()); + EXPECT_EQ(cast(LI->getValue()), Lower.get()); + + auto Upper = N->getUpperBound(); + ASSERT_TRUE(Upper); + ASSERT_TRUE(Upper.is()); + EXPECT_EQ(cast(UI->getValue()), Upper.get()); + + auto Stride = N->getStride(); + ASSERT_TRUE(Stride); + ASSERT_TRUE(Stride.is()); + EXPECT_EQ(cast(SI->getValue()), Stride.get()); + + EXPECT_EQ(N, DISubrange::get(Context, nullptr, LI, UI, SI)); + + EXPECT_NE(N, DISubrange::get(Context, nullptr, LI, UIother, SI)); + EXPECT_NE(N, DISubrange::get(Context, nullptr, LI, UEother, SI)); + EXPECT_NE(N, DISubrange::get(Context, nullptr, LI, UVother, SI)); + + auto *NZeroLower = DISubrange::get(Context, nullptr, LIZero, UI, SI); + EXPECT_NE(NZeroLower, DISubrange::get(Context, nullptr, nullptr, UI, SI)); + + auto *NZeroUpper = DISubrange::get(Context, nullptr, LI, UIZero, SI); + EXPECT_NE(NZeroUpper, DISubrange::get(Context, nullptr, LI, nullptr, SI)); +} + +TEST_F(DISubrangeTest, fortranAllocatableVar) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + DIType *Type = getDerivedType(); + DINode::DIFlags Flags = static_cast(7); + auto *LV = + DILocalVariable::get(Context, Scope, "lb", File, 8, Type, 2, Flags, 8); + auto *UV = + DILocalVariable::get(Context, Scope, "ub", File, 8, Type, 2, Flags, 8); + auto *SV = + DILocalVariable::get(Context, Scope, "st", File, 8, Type, 2, Flags, 8); + auto *SVother = DILocalVariable::get(Context, Scope, "stother", File, 8, Type, + 2, Flags, 8); + auto *SIother = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), 20)); + auto *SEother = DIExpression::get(Context, {5, 6}); + + auto *N = DISubrange::get(Context, nullptr, LV, UV, SV); + + auto Lower = N->getLowerBound(); + ASSERT_TRUE(Lower); + ASSERT_TRUE(Lower.is()); + EXPECT_EQ(LV, Lower.get()); + + auto Upper = N->getUpperBound(); + ASSERT_TRUE(Upper); + ASSERT_TRUE(Upper.is()); + EXPECT_EQ(UV, Upper.get()); + + auto Stride = N->getStride(); + ASSERT_TRUE(Stride); + ASSERT_TRUE(Stride.is()); + EXPECT_EQ(SV, Stride.get()); + + EXPECT_EQ(N, DISubrange::get(Context, nullptr, LV, UV, SV)); + + EXPECT_NE(N, DISubrange::get(Context, nullptr, LV, UV, SVother)); + EXPECT_NE(N, DISubrange::get(Context, nullptr, LV, UV, SEother)); + EXPECT_NE(N, DISubrange::get(Context, nullptr, LV, UV, SIother)); +} + +TEST_F(DISubrangeTest, fortranAllocatableExpr) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + DIType *Type = getDerivedType(); + DINode::DIFlags Flags = static_cast(7); + auto *LE = DIExpression::get(Context, {1, 2}); + auto *UE = DIExpression::get(Context, {2, 3}); + auto *SE = DIExpression::get(Context, {3, 4}); + auto *LEother = DIExpression::get(Context, {5, 6}); + auto *LIother = ConstantAsMetadata::get( + ConstantInt::getSigned(Type::getInt64Ty(Context), 20)); + auto *LVother = DILocalVariable::get(Context, Scope, "lbother", File, 8, Type, + 2, Flags, 8); + + auto *N = DISubrange::get(Context, nullptr, LE, UE, SE); + + auto Lower = N->getLowerBound(); + ASSERT_TRUE(Lower); + ASSERT_TRUE(Lower.is()); + EXPECT_EQ(LE, Lower.get()); + + auto Upper = N->getUpperBound(); + ASSERT_TRUE(Upper); + ASSERT_TRUE(Upper.is()); + EXPECT_EQ(UE, Upper.get()); + + auto Stride = N->getStride(); + ASSERT_TRUE(Stride); + ASSERT_TRUE(Stride.is()); + EXPECT_EQ(SE, Stride.get()); + + EXPECT_EQ(N, DISubrange::get(Context, nullptr, LE, UE, SE)); + + EXPECT_NE(N, DISubrange::get(Context, nullptr, LEother, UE, SE)); + EXPECT_NE(N, DISubrange::get(Context, nullptr, LIother, UE, SE)); + EXPECT_NE(N, DISubrange::get(Context, nullptr, LVother, UE, SE)); +} + typedef MetadataTest DIEnumeratorTest; TEST_F(DIEnumeratorTest, get) {