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 @@ -573,6 +573,8 @@ /// 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 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -287,12 +287,8 @@ 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 @@ 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,17 +317,30 @@ 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 (!getRawCountNode()) + return CountType(); + if (auto *MD = dyn_cast(getRawCountNode())) return CountType(cast(MD->getValue())); @@ -335,6 +350,54 @@ return CountType(); } + BoundType getLowerBound() const { + if (!getRawLowerBound()) + return BoundType(); + + if (auto *MD = dyn_cast(getRawLowerBound())) + return BoundType(cast(MD->getValue())); + + if (auto *MD = dyn_cast(getRawLowerBound())) + return BoundType(MD); + + if (auto *MD = dyn_cast(getRawLowerBound())) + return BoundType(MD); + + return BoundType(); + } + + BoundType getUpperBound() const { + if (!getRawUpperBound()) + return BoundType(); + + if (auto *MD = dyn_cast(getRawUpperBound())) + return BoundType(cast(MD->getValue())); + + if (auto *MD = dyn_cast(getRawUpperBound())) + return BoundType(MD); + + if (auto *MD = dyn_cast(getRawUpperBound())) + return BoundType(MD); + + return BoundType(); + } + + BoundType getStride() const { + if (!getRawStride()) + return BoundType(); + + if (auto *MD = dyn_cast(getRawStride())) + return BoundType(cast(MD->getValue())); + + if (auto *MD = dyn_cast(getRawStride())) + return BoundType(MD); + + if (auto *MD = dyn_cast(getRawStride())) + return BoundType(MD); + + return BoundType(); + } + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DISubrangeKind; } 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 @@ -4500,21 +4500,46 @@ /// 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(); + + if (lowerBound.isMDSignedField()) + LowerBound = ConstantAsMetadata::get(ConstantInt::getSigned( + Type::getInt64Ty(Context), lowerBound.getMDSignedValue())); + else if (lowerBound.isMDField()) + LowerBound = lowerBound.getMDFieldValue(); + + if (upperBound.isMDSignedField()) + UpperBound = ConstantAsMetadata::get(ConstantInt::getSigned( + Type::getInt64Ty(Context), upperBound.getMDSignedValue())); + else if (upperBound.isMDField()) + UpperBound = upperBound.getMDFieldValue(); + + if (stride.isMDSignedField()) + Stride = ConstantAsMetadata::get(ConstantInt::getSigned( + Type::getInt64Ty(Context), stride.getMDSignedValue())); + else if (stride.isMDField()) + Stride = stride.getMDFieldValue(); + + 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 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1261,11 +1261,16 @@ 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 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1527,10 +1527,12 @@ void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N, SmallVectorImpl &Record, unsigned Abbrev) { - const uint64_t Version = 1 << 1; + const uint64_t Version = 1 << 2; 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 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1592,7 +1592,7 @@ 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 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -768,9 +768,18 @@ 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 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1349,20 +1349,56 @@ // 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); + if (auto *LV = SR->getLowerBound().dyn_cast()) { + if (auto *VarDIE = getDIE(LV)) + addDIEEntry(DW_Subrange, dwarf::DW_AT_lower_bound, *VarDIE); + } else if (auto *LE = SR->getLowerBound().dyn_cast()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(LE); + addBlock(DW_Subrange, dwarf::DW_AT_lower_bound, DwarfExpr.finalize()); + } else if (auto *LI = SR->getLowerBound().dyn_cast()) { + if (DefaultLowerBound == -1 || LI->getSExtValue() != DefaultLowerBound) + addSInt(DW_Subrange, dwarf::DW_AT_lower_bound, dwarf::DW_FORM_sdata, LI->getSExtValue()); + } 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); + + if (auto *UV = SR->getUpperBound().dyn_cast()) { + if (auto *VarDIE = getDIE(UV)) + addDIEEntry(DW_Subrange, dwarf::DW_AT_upper_bound, *VarDIE); + } else if (auto *UE = SR->getUpperBound().dyn_cast()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(UE); + addBlock(DW_Subrange, dwarf::DW_AT_upper_bound, DwarfExpr.finalize()); + } else if (auto *UI = SR->getUpperBound().dyn_cast()) { + addSInt(DW_Subrange, dwarf::DW_AT_upper_bound, dwarf::DW_FORM_sdata, UI->getSExtValue()); + } + + if (auto *SV = SR->getStride().dyn_cast()) { + if (auto *VarDIE = getDIE(SV)) + addDIEEntry(DW_Subrange, dwarf::DW_AT_byte_stride, *VarDIE); + } else if (auto *SE = SR->getStride().dyn_cast()) { + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(SE); + addBlock(DW_Subrange, dwarf::DW_AT_byte_stride, DwarfExpr.finalize()); + } else if (auto *SI = SR->getStride().dyn_cast()) { + addSInt(DW_Subrange, dwarf::DW_AT_byte_stride, dwarf::DW_FORM_sdata, SI->getSExtValue()); + } } DIE *DwarfUnit::getIndexTyDie() { 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 @@ -1858,9 +1858,40 @@ 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); + + // lowerBound: 0 should not be skipped, as absence of lowerBound should + // not be assumed as 0, as it depends on other factors like language, and + // it can also be calcualted as (upperBound - count + 1) + if (auto *LE = N->getLowerBound().dyn_cast()) + Printer.printInt("lowerBound", LE->getSExtValue(), + /* ShouldSkipZero */ false); + else if (auto *LV = N->getLowerBound().dyn_cast()) + Printer.printMetadata("lowerBound", LV, /*ShouldSkipNull */ true); + else + Printer.printMetadata("lowerBound", + N->getLowerBound().dyn_cast(), + /*ShouldSkipNull */ true); + + if (auto *UE = N->getUpperBound().dyn_cast()) + Printer.printInt("upperBound", UE->getSExtValue(), + /* ShouldSkipZero */ false); + else if (auto *UV = N->getUpperBound().dyn_cast()) + Printer.printMetadata("upperBound", UV, /*ShouldSkipNull */ true); + else + Printer.printMetadata("upperBound", + N->getUpperBound().dyn_cast(), + /*ShouldSkipNull */ true); + + if (auto *SE = N->getStride().dyn_cast()) + Printer.printInt("stride", SE->getSExtValue(), /* ShouldSkipZero */ false); + else if (auto *SV = N->getStride().dyn_cast()) + Printer.printMetadata("stride", SV, /*ShouldSkipNull */ true); + else + Printer.printMetadata("stride", N->getStride().dyn_cast(), + /*ShouldSkipNull */ true); + Out << ")"; } 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 @@ -625,11 +625,22 @@ } 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 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -336,15 +336,27 @@ 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); } DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, APInt Value, 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 @@ -323,32 +323,61 @@ template <> struct MDNodeKeyImpl { Metadata *CountNode; - int64_t LowerBound; - - MDNodeKeyImpl(Metadata *CountNode, int64_t LowerBound) - : CountNode(CountNode), LowerBound(LowerBound) {} + 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 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; - if (auto *RHSCount = RHS->getCount().dyn_cast()) + if (auto *RHSCount = RHS->getCount().dyn_cast()) { if (auto *MD = dyn_cast(CountNode)) - if (RHSCount->getSExtValue() == + if (RHSCount->getSExtValue() != cast(MD->getValue())->getSExtValue()) - return true; + return false; + } else if (CountNode != RHS->getRawCountNode()) + return false; - return CountNode == RHS->getRawCountNode(); + if (auto *RHSLower = RHS->getLowerBound().dyn_cast()) { + if (auto *MD = dyn_cast(LowerBound)) + if (RHSLower->getSExtValue() != + cast(MD->getValue())->getSExtValue()) + return false; + } else if (LowerBound != RHS->getRawLowerBound()) + return false; + + if (auto *RHSUpper = RHS->getUpperBound().dyn_cast()) { + if (auto *MD = dyn_cast(UpperBound)) + if (RHSUpper->getSExtValue() != + cast(MD->getValue())->getSExtValue()) + return false; + } else if (UpperBound != RHS->getRawUpperBound()) + return false; + + if (auto *RHSStride = RHS->getStride().dyn_cast()) { + if (auto *MD = dyn_cast(Stride)) + if (RHSStride->getSExtValue() != + cast(MD->getValue())->getSExtValue()) + return false; + } else if (Stride != RHS->getRawStride()) + return false; + + return true; } 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 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -893,12 +893,22 @@ 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.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); + AssertDI(!N.getRawLowerBound() || N.getLowerBound(), + "LowerBound must be signed constant or DIVariable or DIExpression", + &N); + AssertDI(!N.getRawUpperBound() || N.getUpperBound(), + "UpperBound must be signed constant or DIVariable or DIExpression", + &N); + AssertDI(!N.getRawStride() || N.getStride(), + "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 --- 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 --- 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 --- 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 --- 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 --- /dev/null +++ b/llvm/test/Bitcode/fortranSubrange.ll @@ -0,0 +1,45 @@ +;; 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: !{{[0-9]+}}, stride: !DIExpression(DW_OP_constu, 4)) + + +; ModuleID = 'fortsubrange.ll' +source_filename = "fortsubrange.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +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 --- /dev/null +++ b/llvm/test/Bitcode/fortranSubrangeBackward.ll @@ -0,0 +1,50 @@ +;; This test checks Backward compatibility of DISubrange bounds + +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +;; Test whether bounds are generated correctly. +; CHECK: !DISubrange(count: 15, lowerBound: 3) +; CHECK: !DISubrange(count: !{{[0-9]+}}, lowerBound: 3) + + +; ModuleID = 'fortsubrange.ll' +source_filename = "fortsubrange.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +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..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ {[[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/fortranSubrangeExpr.ll b/llvm/test/DebugInfo/fortranSubrangeExpr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/fortranSubrangeExpr.ll @@ -0,0 +1,45 @@ +;; This test checks DISubrange bounds for DIExpression + +; RUN: %llc_dwarf -mtriple=x86_64-unknown-linux-gnu %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" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +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 --- /dev/null +++ b/llvm/test/DebugInfo/fortranSubrangeInt.ll @@ -0,0 +1,44 @@ +;; This test checks DISubrange bounds for constants + +; RUN: %llc_dwarf -mtriple=x86_64-unknown-linux-gnu %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" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +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 --- /dev/null +++ b/llvm/test/DebugInfo/fortranSubrangeVar.ll @@ -0,0 +1,64 @@ +;; This test checks DISubrange bounds for DIVariable + +; RUN: %llc_dwarf -mtriple=x86_64-unknown-linux-gnu %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" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +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-missing-upperBound.ll b/llvm/test/Verifier/disubrange-missing-upperBound.ll new file mode 100644 --- /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 --- /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 --- /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 --- /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 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1139,11 +1139,12 @@ 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, 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,104 @@ 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) { + 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 *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)); +} + +TEST_F(DISubrangeTest, fortranAllocatableVar) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + DIType *Type = getDerivedType(); + DINode::DIFlags Flags = static_cast(7); + auto *LE = DILocalVariable::get(Context, Scope, "lb", File, 8, + Type, 2, Flags, 8); + auto *UE = DILocalVariable::get(Context, Scope, "ub", File, 8, + Type, 2, Flags, 8); + auto *SE = DILocalVariable::get(Context, Scope, "st", 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)); +} + +TEST_F(DISubrangeTest, fortranAllocatableExpr) { + auto *LE = DIExpression::get(Context, {1, 2}); + auto *UE = DIExpression::get(Context, {2, 3}); + auto *SE = DIExpression::get(Context, {3, 4}); + + 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)); +} + typedef MetadataTest DIEnumeratorTest; TEST_F(DIEnumeratorTest, get) {