You've already forked llvm-project
mirror of
https://github.com/encounter/llvm-project.git
synced 2026-03-30 11:27:19 -07:00
[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
This commit is contained in:
committed by
Sourabh Singh Tomar
parent
213c6cdf2e
commit
d20bf5a725
@@ -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<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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<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;
|
||||
|
||||
@@ -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<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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -1527,10 +1527,12 @@ static uint64_t rotateSign(int64_t I) {
|
||||
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();
|
||||
|
||||
@@ -1592,7 +1592,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
|
||||
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*>())
|
||||
|
||||
@@ -768,9 +768,18 @@ static SmallVector<const DIVariable *, 2> dependencies(DbgVariable *Var) {
|
||||
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;
|
||||
|
||||
@@ -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<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() {
|
||||
|
||||
@@ -1858,9 +1858,34 @@ static void writeDISubrange(raw_ostream &Out, const DISubrange *N,
|
||||
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 << ")";
|
||||
}
|
||||
|
||||
|
||||
@@ -625,11 +625,22 @@ DITypeRefArray DIBuilder::getOrCreateTypeArray(ArrayRef<Metadata *> 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) {
|
||||
|
||||
@@ -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<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,
|
||||
|
||||
@@ -323,32 +323,46 @@ template <> struct MDNodeKeyImpl<GenericDINode> : MDNodeOpsKey {
|
||||
|
||||
template <> struct MDNodeKeyImpl<DISubrange> {
|
||||
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<ConstantInt*>())
|
||||
if (auto *MD = dyn_cast<ConstantAsMetadata>(CountNode))
|
||||
if (RHSCount->getSExtValue() ==
|
||||
cast<ConstantInt>(MD->getValue())->getSExtValue())
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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<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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user