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
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);
// Create ranges for both dimensions.
llvm::SmallVector<llvm::Metadata *, 2> 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);
}
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();
}
/// 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.
friend class LLVMContextImpl;
friend class MDNode;
- int64_t LowerBound;
-
- DISubrange(LLVMContext &C, StorageType Storage, Metadata *Node,
- int64_t LowerBound, ArrayRef<Metadata *> Ops)
- : DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, Ops),
- LowerBound(LowerBound) {}
+ DISubrange(LLVMContext &C, StorageType Storage, ArrayRef<Metadata *> Ops)
+ : DINode(C, DISubrangeKind, Storage, dwarf::DW_TAG_subrange_type, Ops) {}
~DISubrange() = default;
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:
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<ConstantInt*, DIVariable*> CountType;
+ typedef PointerUnion<ConstantInt *, DIVariable *, DIExpression *> BoundType;
- CountType getCount() const {
- if (auto *MD = dyn_cast<ConstantAsMetadata>(getRawCountNode()))
- return CountType(cast<ConstantInt>(MD->getValue()));
+ CountType getCount() const;
- if (auto *DV = dyn_cast<DIVariable>(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;
/// 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;
}
// 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");
void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N,
SmallVectorImpl<uint64_t> &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();
assert(Element->getTag() == dwarf::DW_TAG_subrange_type);
const DISubrange *Subrange = cast<DISubrange>(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<ConstantInt*>())
Result.push_back(DLVar);
for (auto *El : Array->getElements()) {
if (auto *Subrange = dyn_cast<DISubrange>(El)) {
- auto Count = Subrange->getCount();
- if (auto *Dependency = Count.dyn_cast<DIVariable *>())
- Result.push_back(Dependency);
+ if (auto Count = Subrange->getCount())
+ if (auto *Dependency = Count.dyn_cast<DIVariable *>())
+ Result.push_back(Dependency);
+ if (auto LB = Subrange->getLowerBound())
+ if (auto *Dependency = LB.dyn_cast<DIVariable *>())
+ Result.push_back(Dependency);
+ if (auto UB = Subrange->getUpperBound())
+ if (auto *Dependency = UB.dyn_cast<DIVariable *>())
+ Result.push_back(Dependency);
+ if (auto ST = Subrange->getStride())
+ if (auto *Dependency = ST.dyn_cast<DIVariable *>())
+ Result.push_back(Dependency);
}
}
return Result;
// 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<ConstantInt*>())
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<DIVariable *>()) {
+ if (auto *VarDIE = getDIE(BV))
+ addDIEEntry(DW_Subrange, Attr, *VarDIE);
+ } else if (auto *BE = Bound.dyn_cast<DIExpression *>()) {
+ 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<ConstantInt *>()) {
+ 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<DIVariable*>()) {
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() {
if (auto *CE = N->getCount().dyn_cast<ConstantInt*>())
Printer.printInt("count", CE->getSExtValue(), /* ShouldSkipZero */ false);
else
- Printer.printMetadata("count", N->getCount().dyn_cast<DIVariable*>(),
- /*ShouldSkipNull */ false);
- Printer.printInt("lowerBound", N->getLowerBound());
+ Printer.printMetadata("count", N->getCount().dyn_cast<DIVariable *>(),
+ /*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<ConstantAsMetadata>(LBound)) {
+ auto *LV = cast<ConstantInt>(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<ConstantAsMetadata>(UBound)) {
+ auto *UV = cast<ConstantInt>(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<ConstantAsMetadata>(Stride)) {
+ auto *SV = cast<ConstantInt>(SE->getValue());
+ Printer.printInt("stride", SV->getSExtValue(), /* ShouldSkipZero */ false);
+ } else
+ Printer.printMetadata("stride", Stride, /*ShouldSkipNull */ true);
+
Out << ")";
}
}
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) {
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<ConstantAsMetadata>(getRawCountNode()))
+ return CountType(cast<ConstantInt>(MD->getValue()));
+
+ if (auto *DV = dyn_cast<DIVariable>(getRawCountNode()))
+ return CountType(DV);
+
+ return CountType();
+}
+
+DISubrange::BoundType DISubrange::getLowerBound() const {
+ Metadata *LB = getRawLowerBound();
+ if (!LB)
+ return BoundType();
+
+ assert((isa<ConstantAsMetadata>(LB) || isa<DIVariable>(LB) ||
+ isa<DIExpression>(LB)) &&
+ "LowerBound must be signed constant or DIVariable or DIExpression");
+
+ if (auto *MD = dyn_cast<ConstantAsMetadata>(LB))
+ return BoundType(cast<ConstantInt>(MD->getValue()));
+
+ if (auto *MD = dyn_cast<DIVariable>(LB))
+ return BoundType(MD);
+
+ if (auto *MD = dyn_cast<DIExpression>(LB))
+ return BoundType(MD);
+
+ return BoundType();
+}
+
+DISubrange::BoundType DISubrange::getUpperBound() const {
+ Metadata *UB = getRawUpperBound();
+ if (!UB)
+ return BoundType();
+
+ assert((isa<ConstantAsMetadata>(UB) || isa<DIVariable>(UB) ||
+ isa<DIExpression>(UB)) &&
+ "UpperBound must be signed constant or DIVariable or DIExpression");
+
+ if (auto *MD = dyn_cast<ConstantAsMetadata>(UB))
+ return BoundType(cast<ConstantInt>(MD->getValue()));
+
+ if (auto *MD = dyn_cast<DIVariable>(UB))
+ return BoundType(MD);
+
+ if (auto *MD = dyn_cast<DIExpression>(UB))
+ return BoundType(MD);
+
+ return BoundType();
+}
+
+DISubrange::BoundType DISubrange::getStride() const {
+ Metadata *ST = getRawStride();
+ if (!ST)
+ return BoundType();
+
+ assert((isa<ConstantAsMetadata>(ST) || isa<DIVariable>(ST) ||
+ isa<DIExpression>(ST)) &&
+ "Stride must be signed constant or DIVariable or DIExpression");
+
+ if (auto *MD = dyn_cast<ConstantAsMetadata>(ST))
+ return BoundType(cast<ConstantInt>(MD->getValue()));
+
+ if (auto *MD = dyn_cast<DIVariable>(ST))
+ return BoundType(MD);
+
+ if (auto *MD = dyn_cast<DIExpression>(ST))
+ return BoundType(MD);
+
+ return BoundType();
}
DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, APInt Value,
template <> struct MDNodeKeyImpl<DISubrange> {
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<ConstantInt*>())
- if (auto *MD = dyn_cast<ConstantAsMetadata>(CountNode))
- if (RHSCount->getSExtValue() ==
- cast<ConstantInt>(MD->getValue())->getSExtValue())
+ auto BoundsEqual = [=](Metadata *Node1, Metadata *Node2) -> bool {
+ if (Node1 == Node2)
+ return true;
+
+ ConstantAsMetadata *MD1 = dyn_cast_or_null<ConstantAsMetadata>(Node1);
+ ConstantAsMetadata *MD2 = dyn_cast_or_null<ConstantAsMetadata>(Node2);
+ if (MD1 && MD2) {
+ ConstantInt *CV1 = cast<ConstantInt>(MD1->getValue());
+ ConstantInt *CV2 = cast<ConstantInt>(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<ConstantAsMetadata>(CountNode))
- return hash_combine(cast<ConstantInt>(MD->getValue())->getSExtValue(),
- LowerBound);
- return hash_combine(CountNode, LowerBound);
+ if (CountNode)
+ if (auto *MD = dyn_cast<ConstantAsMetadata>(CountNode))
+ return hash_combine(cast<ConstantInt>(MD->getValue())->getSExtValue(),
+ LowerBound, UpperBound, Stride);
+ return hash_combine(CountNode, LowerBound, UpperBound, Stride);
}
};
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<ConstantInt*>() ||
- Count.get<ConstantInt*>()->getSExtValue() >= -1,
+ AssertDI(!Count || !Count.is<ConstantInt *>() ||
+ Count.get<ConstantInt *>()->getSExtValue() >= -1,
"invalid subrange count", &N);
+ auto *LBound = N.getRawLowerBound();
+ AssertDI(!LBound || isa<ConstantAsMetadata>(LBound) ||
+ isa<DIVariable>(LBound) || isa<DIExpression>(LBound),
+ "LowerBound must be signed constant or DIVariable or DIExpression",
+ &N);
+ auto *UBound = N.getRawUpperBound();
+ AssertDI(!UBound || isa<ConstantAsMetadata>(UBound) ||
+ isa<DIVariable>(UBound) || isa<DIExpression>(UBound),
+ "UpperBound must be signed constant or DIVariable or DIExpression",
+ &N);
+ auto *Stride = N.getRawStride();
+ AssertDI(!Stride || isa<ConstantAsMetadata>(Stride) ||
+ isa<DIVariable>(Stride) || isa<DIExpression>(Stride),
+ "Stride must be signed constant or DIVariable or DIExpression", &N);
}
void Verifier::visitDIEnumerator(const DIEnumerator &N) {
; 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)
; 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)
; 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)
; 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)
--- /dev/null
+;; 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)
--- /dev/null
+;; 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)
; CHECK-NEXT: DW_AT_type
; CHECK: DW_TAG_subrange_type
; CHECK-NEXT: DW_AT_type
-; DWARF4-NEXT: DW_AT_lower_bound [DW_FORM_data1] (0x00)
+; DWARF4-NEXT: DW_AT_lower_bound [DW_FORM_sdata] (0)
; CHECK-NEXT: DW_AT_count [DW_FORM_data1] (0x2a)
; DWARF5-NOT: DW_AT_lower_bound
; CHECK: DW_TAG_subrange_type
; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + 0x{{[0-9a-f]*}} => {[[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
--- /dev/null
+;; 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)
--- /dev/null
+;; 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)
--- /dev/null
+;; 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)
--- /dev/null
+;; 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)
--- /dev/null
+;; 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)
--- /dev/null
+; 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)
--- /dev/null
+; 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)
--- /dev/null
+; 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)
--- /dev/null
+; 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)
--- /dev/null
+; 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)
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<ConstantInt*>());
EXPECT_EQ(5, Count.get<ConstantInt*>()->getSExtValue());
- EXPECT_EQ(7, N->getLowerBound());
+ EXPECT_EQ(7, Lower.get<ConstantInt *>()->getSExtValue());
EXPECT_EQ(N, DISubrange::get(Context, 5, 7));
EXPECT_EQ(DISubrange::get(Context, 5, 0), DISubrange::get(Context, 5));
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<ConstantInt*>());
EXPECT_EQ(-1, Count.get<ConstantInt*>()->getSExtValue());
- EXPECT_EQ(0, N->getLowerBound());
+ EXPECT_EQ(0, Lower.get<ConstantInt *>()->getSExtValue());
EXPECT_EQ(N, DISubrange::get(Context, -1, 0));
}
auto *N = DISubrange::get(Context, VlaExpr, 0);
auto Count = N->getCount();
+ auto Lower = N->getLowerBound();
ASSERT_TRUE(Count);
ASSERT_TRUE(Count.is<DIVariable*>());
EXPECT_EQ(VlaExpr, Count.get<DIVariable*>());
ASSERT_TRUE(isa<DIVariable>(N->getRawCountNode()));
- EXPECT_EQ(0, N->getLowerBound());
+ EXPECT_EQ(0, Lower.get<ConstantInt *>()->getSExtValue());
EXPECT_EQ("vla_expr", Count.get<DIVariable*>()->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<DINode::DIFlags>(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<ConstantInt *>());
+ EXPECT_EQ(cast<ConstantInt>(LI->getValue()), Lower.get<ConstantInt *>());
+
+ auto Upper = N->getUpperBound();
+ ASSERT_TRUE(Upper);
+ ASSERT_TRUE(Upper.is<ConstantInt *>());
+ EXPECT_EQ(cast<ConstantInt>(UI->getValue()), Upper.get<ConstantInt *>());
+
+ auto Stride = N->getStride();
+ ASSERT_TRUE(Stride);
+ ASSERT_TRUE(Stride.is<ConstantInt *>());
+ EXPECT_EQ(cast<ConstantInt>(SI->getValue()), Stride.get<ConstantInt *>());
+
+ 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<DINode::DIFlags>(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<DIVariable *>());
+ EXPECT_EQ(LV, Lower.get<DIVariable *>());
+
+ auto Upper = N->getUpperBound();
+ ASSERT_TRUE(Upper);
+ ASSERT_TRUE(Upper.is<DIVariable *>());
+ EXPECT_EQ(UV, Upper.get<DIVariable *>());
+
+ auto Stride = N->getStride();
+ ASSERT_TRUE(Stride);
+ ASSERT_TRUE(Stride.is<DIVariable *>());
+ EXPECT_EQ(SV, Stride.get<DIVariable *>());
+
+ 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<DINode::DIFlags>(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<DIExpression *>());
+ EXPECT_EQ(LE, Lower.get<DIExpression *>());
+
+ auto Upper = N->getUpperBound();
+ ASSERT_TRUE(Upper);
+ ASSERT_TRUE(Upper.is<DIExpression *>());
+ EXPECT_EQ(UE, Upper.get<DIExpression *>());
+
+ auto Stride = N->getStride();
+ ASSERT_TRUE(Stride);
+ ASSERT_TRUE(Stride.is<DIExpression *>());
+ EXPECT_EQ(SE, Stride.get<DIExpression *>());
+
+ 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) {