mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[DebugInfo] Support for DW_TAG_generic_subrange
This is needed to support fortran assumed rank arrays which have runtime rank. Summary: Fortran assumed rank arrays have dynamic rank. DWARF TAG DW_TAG_generic_subrange is needed to support that. Testing: unit test cases added (hand-written) check llvm check debug-info Reviewed By: aprantl Differential Revision: https://reviews.llvm.org/D89218
This commit is contained in:
parent
e89fe0ad6a
commit
0d9afcbbba
@ -160,7 +160,8 @@ enum {
|
||||
LLVMDIMacroMetadataKind,
|
||||
LLVMDIMacroFileMetadataKind,
|
||||
LLVMDICommonBlockMetadataKind,
|
||||
LLVMDIStringTypeMetadataKind
|
||||
LLVMDIStringTypeMetadataKind,
|
||||
LLVMDIGenericSubrangeMetadataKind
|
||||
};
|
||||
typedef unsigned LLVMMetadataKind;
|
||||
|
||||
|
@ -341,7 +341,8 @@ enum MetadataCodes {
|
||||
METADATA_STRING_TYPE = 41, // [distinct, name, size, align,...]
|
||||
// Codes 42 and 43 are reserved for support for Fortran array specific debug
|
||||
// info.
|
||||
METADATA_COMMON_BLOCK = 44 // [distinct, scope, name, variable,...]
|
||||
METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...]
|
||||
METADATA_GENERIC_SUBRANGE = 45 // [distinct, count, lo, up, stride]
|
||||
};
|
||||
|
||||
// The constants block (CONSTANTS_BLOCK_ID) describes emission for each
|
||||
|
@ -582,6 +582,12 @@ namespace llvm {
|
||||
DISubrange *getOrCreateSubrange(Metadata *Count, Metadata *LowerBound,
|
||||
Metadata *UpperBound, Metadata *Stride);
|
||||
|
||||
DIGenericSubrange *
|
||||
getOrCreateGenericSubrange(DIGenericSubrange::BoundType Count,
|
||||
DIGenericSubrange::BoundType LowerBound,
|
||||
DIGenericSubrange::BoundType UpperBound,
|
||||
DIGenericSubrange::BoundType Stride);
|
||||
|
||||
/// Create a new descriptor for the specified variable.
|
||||
/// \param Context Variable scope.
|
||||
/// \param Name Name of the variable.
|
||||
|
@ -201,6 +201,7 @@ public:
|
||||
case DIObjCPropertyKind:
|
||||
case DIImportedEntityKind:
|
||||
case DIModuleKind:
|
||||
case DIGenericSubrangeKind:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -351,6 +352,52 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DIGenericSubrange : public DINode {
|
||||
friend class LLVMContextImpl;
|
||||
friend class MDNode;
|
||||
|
||||
DIGenericSubrange(LLVMContext &C, StorageType Storage,
|
||||
ArrayRef<Metadata *> Ops)
|
||||
: DINode(C, DIGenericSubrangeKind, Storage,
|
||||
dwarf::DW_TAG_generic_subrange, Ops) {}
|
||||
|
||||
~DIGenericSubrange() = default;
|
||||
|
||||
static DIGenericSubrange *getImpl(LLVMContext &Context, Metadata *CountNode,
|
||||
Metadata *LowerBound, Metadata *UpperBound,
|
||||
Metadata *Stride, StorageType Storage,
|
||||
bool ShouldCreate = true);
|
||||
|
||||
TempDIGenericSubrange cloneImpl() const {
|
||||
return getTemporary(getContext(), getRawCountNode(), getRawLowerBound(),
|
||||
getRawUpperBound(), getRawStride());
|
||||
}
|
||||
|
||||
public:
|
||||
DEFINE_MDNODE_GET(DIGenericSubrange,
|
||||
(Metadata * CountNode, Metadata *LowerBound,
|
||||
Metadata *UpperBound, Metadata *Stride),
|
||||
(CountNode, LowerBound, UpperBound, Stride))
|
||||
|
||||
TempDIGenericSubrange clone() const { return cloneImpl(); }
|
||||
|
||||
Metadata *getRawCountNode() const { return getOperand(0).get(); }
|
||||
Metadata *getRawLowerBound() const { return getOperand(1).get(); }
|
||||
Metadata *getRawUpperBound() const { return getOperand(2).get(); }
|
||||
Metadata *getRawStride() const { return getOperand(3).get(); }
|
||||
|
||||
using BoundType = PointerUnion<DIVariable *, DIExpression *>;
|
||||
|
||||
BoundType getCount() const;
|
||||
BoundType getLowerBound() const;
|
||||
BoundType getUpperBound() const;
|
||||
BoundType getStride() const;
|
||||
|
||||
static bool classof(const Metadata *MD) {
|
||||
return MD->getMetadataID() == DIGenericSubrangeKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// Enumeration value.
|
||||
///
|
||||
/// TODO: Add a pointer to the context (DW_TAG_enumeration_type) once that no
|
||||
@ -2524,6 +2571,9 @@ public:
|
||||
/// Determine whether this represents a standalone constant value.
|
||||
bool isConstant() const;
|
||||
|
||||
/// Determine whether this represents a standalone signed constant value.
|
||||
bool isSignedConstant() const;
|
||||
|
||||
using element_iterator = ArrayRef<uint64_t>::iterator;
|
||||
|
||||
element_iterator elements_begin() const { return getElements().begin(); }
|
||||
|
@ -115,6 +115,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGenericSubrange)
|
||||
|
||||
#undef HANDLE_METADATA
|
||||
#undef HANDLE_METADATA_LEAF
|
||||
|
@ -4670,6 +4670,39 @@ bool LLParser::parseDISubrange(MDNode *&Result, bool IsDistinct) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDIGenericSubrange:
|
||||
/// ::= !DIGenericSubrange(lowerBound: !node1, upperBound: !node2, stride:
|
||||
/// !node3)
|
||||
bool LLParser::parseDIGenericSubrange(MDNode *&Result, bool IsDistinct) {
|
||||
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
||||
OPTIONAL(count, MDSignedOrMDField, ); \
|
||||
OPTIONAL(lowerBound, MDSignedOrMDField, ); \
|
||||
OPTIONAL(upperBound, MDSignedOrMDField, ); \
|
||||
OPTIONAL(stride, MDSignedOrMDField, );
|
||||
PARSE_MD_FIELDS();
|
||||
#undef VISIT_MD_FIELDS
|
||||
|
||||
auto ConvToMetadata = [&](MDSignedOrMDField Bound) -> Metadata * {
|
||||
if (Bound.isMDSignedField())
|
||||
return DIExpression::get(
|
||||
Context, {dwarf::DW_OP_consts,
|
||||
static_cast<uint64_t>(Bound.getMDSignedValue())});
|
||||
if (Bound.isMDField())
|
||||
return Bound.getMDFieldValue();
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
Metadata *Count = ConvToMetadata(count);
|
||||
Metadata *LowerBound = ConvToMetadata(lowerBound);
|
||||
Metadata *UpperBound = ConvToMetadata(upperBound);
|
||||
Metadata *Stride = ConvToMetadata(stride);
|
||||
|
||||
Result = GET_OR_DISTINCT(DIGenericSubrange,
|
||||
(Context, Count, LowerBound, UpperBound, Stride));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// parseDIEnumerator:
|
||||
/// ::= !DIEnumerator(value: 30, isUnsigned: true, name: "SomeKind")
|
||||
bool LLParser::parseDIEnumerator(MDNode *&Result, bool IsDistinct) {
|
||||
|
@ -875,6 +875,7 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
|
||||
case bitc::METADATA_OBJC_PROPERTY:
|
||||
case bitc::METADATA_IMPORTED_ENTITY:
|
||||
case bitc::METADATA_GLOBAL_VAR_EXPR:
|
||||
case bitc::METADATA_GENERIC_SUBRANGE:
|
||||
// We don't expect to see any of these, if we see one, give up on
|
||||
// lazy-loading and fallback.
|
||||
MDStringRef.clear();
|
||||
@ -1371,6 +1372,18 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||
NextMetadataNo++;
|
||||
break;
|
||||
}
|
||||
case bitc::METADATA_GENERIC_SUBRANGE: {
|
||||
Metadata *Val = nullptr;
|
||||
Val = GET_OR_DISTINCT(DIGenericSubrange,
|
||||
(Context, getMDOrNull(Record[1]),
|
||||
getMDOrNull(Record[2]), getMDOrNull(Record[3]),
|
||||
getMDOrNull(Record[4])));
|
||||
|
||||
MetadataList.assignValue(Val, NextMetadataNo);
|
||||
IsDistinct = Record[0] & 1;
|
||||
NextMetadataNo++;
|
||||
break;
|
||||
}
|
||||
case bitc::METADATA_ENUMERATOR: {
|
||||
if (Record.size() < 3)
|
||||
return error("Invalid record");
|
||||
|
@ -300,6 +300,9 @@ private:
|
||||
SmallVectorImpl<uint64_t> &Record, unsigned &Abbrev);
|
||||
void writeDISubrange(const DISubrange *N, SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned Abbrev);
|
||||
void writeDIGenericSubrange(const DIGenericSubrange *N,
|
||||
SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned Abbrev);
|
||||
void writeDIEnumerator(const DIEnumerator *N,
|
||||
SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
|
||||
void writeDIBasicType(const DIBasicType *N, SmallVectorImpl<uint64_t> &Record,
|
||||
@ -1553,6 +1556,19 @@ void ModuleBitcodeWriter::writeDISubrange(const DISubrange *N,
|
||||
Record.clear();
|
||||
}
|
||||
|
||||
void ModuleBitcodeWriter::writeDIGenericSubrange(
|
||||
const DIGenericSubrange *N, SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned Abbrev) {
|
||||
Record.push_back((uint64_t)N->isDistinct());
|
||||
Record.push_back(VE.getMetadataOrNullID(N->getRawCountNode()));
|
||||
Record.push_back(VE.getMetadataOrNullID(N->getRawLowerBound()));
|
||||
Record.push_back(VE.getMetadataOrNullID(N->getRawUpperBound()));
|
||||
Record.push_back(VE.getMetadataOrNullID(N->getRawStride()));
|
||||
|
||||
Stream.EmitRecord(bitc::METADATA_GENERIC_SUBRANGE, Record, Abbrev);
|
||||
Record.clear();
|
||||
}
|
||||
|
||||
static void emitSignedInt64(SmallVectorImpl<uint64_t> &Vals, uint64_t V) {
|
||||
if ((int64_t)V >= 0)
|
||||
Vals.push_back(V << 1);
|
||||
|
@ -812,6 +812,19 @@ static SmallVector<const DIVariable *, 2> dependencies(DbgVariable *Var) {
|
||||
if (auto ST = Subrange->getStride())
|
||||
if (auto *Dependency = ST.dyn_cast<DIVariable *>())
|
||||
Result.push_back(Dependency);
|
||||
} else if (auto *GenericSubrange = dyn_cast<DIGenericSubrange>(El)) {
|
||||
if (auto Count = GenericSubrange->getCount())
|
||||
if (auto *Dependency = Count.dyn_cast<DIVariable *>())
|
||||
Result.push_back(Dependency);
|
||||
if (auto LB = GenericSubrange->getLowerBound())
|
||||
if (auto *Dependency = LB.dyn_cast<DIVariable *>())
|
||||
Result.push_back(Dependency);
|
||||
if (auto UB = GenericSubrange->getUpperBound())
|
||||
if (auto *Dependency = UB.dyn_cast<DIVariable *>())
|
||||
Result.push_back(Dependency);
|
||||
if (auto ST = GenericSubrange->getStride())
|
||||
if (auto *Dependency = ST.dyn_cast<DIVariable *>())
|
||||
Result.push_back(Dependency);
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
|
@ -541,6 +541,10 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
|
||||
assert(!isRegisterLocation());
|
||||
emitConstu(Op->getArg(0));
|
||||
break;
|
||||
case dwarf::DW_OP_consts:
|
||||
assert(!isRegisterLocation());
|
||||
emitSigned(Op->getArg(0));
|
||||
break;
|
||||
case dwarf::DW_OP_LLVM_convert: {
|
||||
unsigned BitSize = Op->getArg(0);
|
||||
dwarf::TypeKind Encoding = static_cast<dwarf::TypeKind>(Op->getArg(1));
|
||||
|
@ -1357,7 +1357,7 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR,
|
||||
if (auto *CI = SR->getCount().dyn_cast<ConstantInt*>())
|
||||
Count = CI->getSExtValue();
|
||||
|
||||
auto addBoundTypeEntry = [&](dwarf::Attribute Attr,
|
||||
auto AddBoundTypeEntry = [&](dwarf::Attribute Attr,
|
||||
DISubrange::BoundType Bound) -> void {
|
||||
if (auto *BV = Bound.dyn_cast<DIVariable *>()) {
|
||||
if (auto *VarDIE = getDIE(BV))
|
||||
@ -1375,7 +1375,7 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR,
|
||||
}
|
||||
};
|
||||
|
||||
addBoundTypeEntry(dwarf::DW_AT_lower_bound, SR->getLowerBound());
|
||||
AddBoundTypeEntry(dwarf::DW_AT_lower_bound, SR->getLowerBound());
|
||||
|
||||
if (auto *CV = SR->getCount().dyn_cast<DIVariable*>()) {
|
||||
if (auto *CountVarDIE = getDIE(CV))
|
||||
@ -1383,9 +1383,45 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR,
|
||||
} 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_upper_bound, SR->getUpperBound());
|
||||
|
||||
addBoundTypeEntry(dwarf::DW_AT_byte_stride, SR->getStride());
|
||||
AddBoundTypeEntry(dwarf::DW_AT_byte_stride, SR->getStride());
|
||||
}
|
||||
|
||||
void DwarfUnit::constructGenericSubrangeDIE(DIE &Buffer,
|
||||
const DIGenericSubrange *GSR,
|
||||
DIE *IndexTy) {
|
||||
DIE &DwGenericSubrange =
|
||||
createAndAddDIE(dwarf::DW_TAG_generic_subrange, Buffer);
|
||||
addDIEEntry(DwGenericSubrange, dwarf::DW_AT_type, *IndexTy);
|
||||
|
||||
int64_t DefaultLowerBound = getDefaultLowerBound();
|
||||
|
||||
auto AddBoundTypeEntry = [&](dwarf::Attribute Attr,
|
||||
DIGenericSubrange::BoundType Bound) -> void {
|
||||
if (auto *BV = Bound.dyn_cast<DIVariable *>()) {
|
||||
if (auto *VarDIE = getDIE(BV))
|
||||
addDIEEntry(DwGenericSubrange, Attr, *VarDIE);
|
||||
} else if (auto *BE = Bound.dyn_cast<DIExpression *>()) {
|
||||
if (BE->isSignedConstant()) {
|
||||
if (Attr != dwarf::DW_AT_lower_bound || DefaultLowerBound == -1 ||
|
||||
static_cast<int64_t>(BE->getElement(1)) != DefaultLowerBound)
|
||||
addSInt(DwGenericSubrange, Attr, dwarf::DW_FORM_sdata,
|
||||
BE->getElement(1));
|
||||
} else {
|
||||
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
|
||||
DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc);
|
||||
DwarfExpr.setMemoryLocationKind();
|
||||
DwarfExpr.addExpression(BE);
|
||||
addBlock(DwGenericSubrange, Attr, DwarfExpr.finalize());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AddBoundTypeEntry(dwarf::DW_AT_lower_bound, GSR->getLowerBound());
|
||||
AddBoundTypeEntry(dwarf::DW_AT_count, GSR->getCount());
|
||||
AddBoundTypeEntry(dwarf::DW_AT_upper_bound, GSR->getUpperBound());
|
||||
AddBoundTypeEntry(dwarf::DW_AT_byte_stride, GSR->getStride());
|
||||
}
|
||||
|
||||
DIE *DwarfUnit::getIndexTyDie() {
|
||||
@ -1495,9 +1531,13 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
|
||||
DINodeArray Elements = CTy->getElements();
|
||||
for (unsigned i = 0, N = Elements.size(); i < N; ++i) {
|
||||
// FIXME: Should this really be such a loose cast?
|
||||
if (auto *Element = dyn_cast_or_null<DINode>(Elements[i]))
|
||||
if (auto *Element = dyn_cast_or_null<DINode>(Elements[i])) {
|
||||
if (Element->getTag() == dwarf::DW_TAG_subrange_type)
|
||||
constructSubrangeDIE(Buffer, cast<DISubrange>(Element), IdxTy);
|
||||
else if (Element->getTag() == dwarf::DW_TAG_generic_subrange)
|
||||
constructGenericSubrangeDIE(Buffer, cast<DIGenericSubrange>(Element),
|
||||
IdxTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,6 +301,8 @@ private:
|
||||
void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy);
|
||||
void constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy);
|
||||
void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy);
|
||||
void constructGenericSubrangeDIE(DIE &Buffer, const DIGenericSubrange *SR,
|
||||
DIE *IndexTy);
|
||||
void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy);
|
||||
void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy);
|
||||
DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT);
|
||||
|
@ -1910,6 +1910,57 @@ static void writeDISubrange(raw_ostream &Out, const DISubrange *N,
|
||||
Out << ")";
|
||||
}
|
||||
|
||||
static void writeDIGenericSubrange(raw_ostream &Out, const DIGenericSubrange *N,
|
||||
TypePrinting *TypePrinter,
|
||||
SlotTracker *Machine,
|
||||
const Module *Context) {
|
||||
Out << "!DIGenericSubrange(";
|
||||
MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
|
||||
|
||||
auto IsConstant = [&](Metadata *Bound) -> bool {
|
||||
if (auto *BE = dyn_cast_or_null<DIExpression>(Bound)) {
|
||||
return BE->isSignedConstant();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto GetConstant = [&](Metadata *Bound) -> int64_t {
|
||||
assert(IsConstant(Bound) && "Expected constant");
|
||||
auto *BE = dyn_cast_or_null<DIExpression>(Bound);
|
||||
return static_cast<int64_t>(BE->getElement(1));
|
||||
};
|
||||
|
||||
auto *Count = N->getRawCountNode();
|
||||
if (IsConstant(Count))
|
||||
Printer.printInt("count", GetConstant(Count),
|
||||
/* ShouldSkipZero */ false);
|
||||
else
|
||||
Printer.printMetadata("count", Count, /*ShouldSkipNull */ true);
|
||||
|
||||
auto *LBound = N->getRawLowerBound();
|
||||
if (IsConstant(LBound))
|
||||
Printer.printInt("lowerBound", GetConstant(LBound),
|
||||
/* ShouldSkipZero */ false);
|
||||
else
|
||||
Printer.printMetadata("lowerBound", LBound, /*ShouldSkipNull */ true);
|
||||
|
||||
auto *UBound = N->getRawUpperBound();
|
||||
if (IsConstant(UBound))
|
||||
Printer.printInt("upperBound", GetConstant(UBound),
|
||||
/* ShouldSkipZero */ false);
|
||||
else
|
||||
Printer.printMetadata("upperBound", UBound, /*ShouldSkipNull */ true);
|
||||
|
||||
auto *Stride = N->getRawStride();
|
||||
if (IsConstant(Stride))
|
||||
Printer.printInt("stride", GetConstant(Stride),
|
||||
/* ShouldSkipZero */ false);
|
||||
else
|
||||
Printer.printMetadata("stride", Stride, /*ShouldSkipNull */ true);
|
||||
|
||||
Out << ")";
|
||||
}
|
||||
|
||||
static void writeDIEnumerator(raw_ostream &Out, const DIEnumerator *N,
|
||||
TypePrinting *, SlotTracker *, const Module *) {
|
||||
Out << "!DIEnumerator(";
|
||||
|
@ -649,6 +649,18 @@ DISubrange *DIBuilder::getOrCreateSubrange(Metadata *CountNode, Metadata *LB,
|
||||
return DISubrange::get(VMContext, CountNode, LB, UB, Stride);
|
||||
}
|
||||
|
||||
DIGenericSubrange *DIBuilder::getOrCreateGenericSubrange(
|
||||
DIGenericSubrange::BoundType CountNode, DIGenericSubrange::BoundType LB,
|
||||
DIGenericSubrange::BoundType UB, DIGenericSubrange::BoundType Stride) {
|
||||
auto ConvToMetadata = [&](DIGenericSubrange::BoundType Bound) -> Metadata * {
|
||||
return Bound.is<DIExpression *>() ? (Metadata *)Bound.get<DIExpression *>()
|
||||
: (Metadata *)Bound.get<DIVariable *>();
|
||||
};
|
||||
return DIGenericSubrange::get(VMContext, ConvToMetadata(CountNode),
|
||||
ConvToMetadata(LB), ConvToMetadata(UB),
|
||||
ConvToMetadata(Stride));
|
||||
}
|
||||
|
||||
static void checkGlobalVariableScope(DIScope *Context) {
|
||||
#ifndef NDEBUG
|
||||
if (auto *CT =
|
||||
|
@ -435,6 +435,84 @@ DISubrange::BoundType DISubrange::getStride() const {
|
||||
return BoundType();
|
||||
}
|
||||
|
||||
DIGenericSubrange *DIGenericSubrange::getImpl(LLVMContext &Context,
|
||||
Metadata *CountNode, Metadata *LB,
|
||||
Metadata *UB, Metadata *Stride,
|
||||
StorageType Storage,
|
||||
bool ShouldCreate) {
|
||||
DEFINE_GETIMPL_LOOKUP(DIGenericSubrange, (CountNode, LB, UB, Stride));
|
||||
Metadata *Ops[] = {CountNode, LB, UB, Stride};
|
||||
DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIGenericSubrange, Ops);
|
||||
}
|
||||
|
||||
DIGenericSubrange::BoundType DIGenericSubrange::getCount() const {
|
||||
Metadata *CB = getRawCountNode();
|
||||
if (!CB)
|
||||
return BoundType();
|
||||
|
||||
assert((isa<DIVariable>(CB) || isa<DIExpression>(CB)) &&
|
||||
"Count must be signed constant or DIVariable or DIExpression");
|
||||
|
||||
if (auto *MD = dyn_cast<DIVariable>(CB))
|
||||
return BoundType(MD);
|
||||
|
||||
if (auto *MD = dyn_cast<DIExpression>(CB))
|
||||
return BoundType(MD);
|
||||
|
||||
return BoundType();
|
||||
}
|
||||
|
||||
DIGenericSubrange::BoundType DIGenericSubrange::getLowerBound() const {
|
||||
Metadata *LB = getRawLowerBound();
|
||||
if (!LB)
|
||||
return BoundType();
|
||||
|
||||
assert((isa<DIVariable>(LB) || isa<DIExpression>(LB)) &&
|
||||
"LowerBound must be signed constant or DIVariable or DIExpression");
|
||||
|
||||
if (auto *MD = dyn_cast<DIVariable>(LB))
|
||||
return BoundType(MD);
|
||||
|
||||
if (auto *MD = dyn_cast<DIExpression>(LB))
|
||||
return BoundType(MD);
|
||||
|
||||
return BoundType();
|
||||
}
|
||||
|
||||
DIGenericSubrange::BoundType DIGenericSubrange::getUpperBound() const {
|
||||
Metadata *UB = getRawUpperBound();
|
||||
if (!UB)
|
||||
return BoundType();
|
||||
|
||||
assert((isa<DIVariable>(UB) || isa<DIExpression>(UB)) &&
|
||||
"UpperBound must be signed constant or DIVariable or DIExpression");
|
||||
|
||||
if (auto *MD = dyn_cast<DIVariable>(UB))
|
||||
return BoundType(MD);
|
||||
|
||||
if (auto *MD = dyn_cast<DIExpression>(UB))
|
||||
return BoundType(MD);
|
||||
|
||||
return BoundType();
|
||||
}
|
||||
|
||||
DIGenericSubrange::BoundType DIGenericSubrange::getStride() const {
|
||||
Metadata *ST = getRawStride();
|
||||
if (!ST)
|
||||
return BoundType();
|
||||
|
||||
assert((isa<DIVariable>(ST) || isa<DIExpression>(ST)) &&
|
||||
"Stride must be signed constant or DIVariable or DIExpression");
|
||||
|
||||
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, const APInt &Value,
|
||||
bool IsUnsigned, MDString *Name,
|
||||
StorageType Storage, bool ShouldCreate) {
|
||||
@ -1061,6 +1139,7 @@ bool DIExpression::isValid() const {
|
||||
case dwarf::DW_OP_bregx:
|
||||
case dwarf::DW_OP_push_object_address:
|
||||
case dwarf::DW_OP_over:
|
||||
case dwarf::DW_OP_consts:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1334,6 +1413,15 @@ bool DIExpression::isConstant() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DIExpression::isSignedConstant() const {
|
||||
// Recognize DW_OP_consts C
|
||||
if (getNumElements() != 2)
|
||||
return false;
|
||||
if (getElement(0) != dwarf::DW_OP_consts)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
DIExpression::ExtOps DIExpression::getExtOps(unsigned FromSize, unsigned ToSize,
|
||||
bool Signed) {
|
||||
dwarf::TypeKind TK = Signed ? dwarf::DW_ATE_signed : dwarf::DW_ATE_unsigned;
|
||||
|
@ -346,6 +346,36 @@ template <> struct MDNodeKeyImpl<DISubrange> {
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MDNodeKeyImpl<DIGenericSubrange> {
|
||||
Metadata *CountNode;
|
||||
Metadata *LowerBound;
|
||||
Metadata *UpperBound;
|
||||
Metadata *Stride;
|
||||
|
||||
MDNodeKeyImpl(Metadata *CountNode, Metadata *LowerBound, Metadata *UpperBound,
|
||||
Metadata *Stride)
|
||||
: CountNode(CountNode), LowerBound(LowerBound), UpperBound(UpperBound),
|
||||
Stride(Stride) {}
|
||||
MDNodeKeyImpl(const DIGenericSubrange *N)
|
||||
: CountNode(N->getRawCountNode()), LowerBound(N->getRawLowerBound()),
|
||||
UpperBound(N->getRawUpperBound()), Stride(N->getRawStride()) {}
|
||||
|
||||
bool isKeyOf(const DIGenericSubrange *RHS) const {
|
||||
return (CountNode == RHS->getRawCountNode()) &&
|
||||
(LowerBound == RHS->getRawLowerBound()) &&
|
||||
(UpperBound == RHS->getRawUpperBound()) &&
|
||||
(Stride == RHS->getRawStride());
|
||||
}
|
||||
|
||||
unsigned getHashValue() const {
|
||||
auto *MD = dyn_cast_or_null<ConstantAsMetadata>(CountNode);
|
||||
if (CountNode && MD)
|
||||
return hash_combine(cast<ConstantInt>(MD->getValue())->getSExtValue(),
|
||||
LowerBound, UpperBound, Stride);
|
||||
return hash_combine(CountNode, LowerBound, UpperBound, Stride);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MDNodeKeyImpl<DIEnumerator> {
|
||||
APInt Value;
|
||||
MDString *Name;
|
||||
|
@ -926,6 +926,30 @@ void Verifier::visitDISubrange(const DISubrange &N) {
|
||||
"Stride must be signed constant or DIVariable or DIExpression", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIGenericSubrange(const DIGenericSubrange &N) {
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_generic_subrange, "invalid tag", &N);
|
||||
AssertDI(N.getRawCountNode() || N.getRawUpperBound(),
|
||||
"GenericSubrange must contain count or upperBound", &N);
|
||||
AssertDI(!N.getRawCountNode() || !N.getRawUpperBound(),
|
||||
"GenericSubrange can have any one of count or upperBound", &N);
|
||||
auto *CBound = N.getRawCountNode();
|
||||
AssertDI(!CBound || isa<DIVariable>(CBound) || isa<DIExpression>(CBound),
|
||||
"Count must be signed constant or DIVariable or DIExpression", &N);
|
||||
auto *LBound = N.getRawLowerBound();
|
||||
AssertDI(LBound, "GenericSubrange must contain lowerBound", &N);
|
||||
AssertDI(isa<DIVariable>(LBound) || isa<DIExpression>(LBound),
|
||||
"LowerBound must be signed constant or DIVariable or DIExpression",
|
||||
&N);
|
||||
auto *UBound = N.getRawUpperBound();
|
||||
AssertDI(!UBound || isa<DIVariable>(UBound) || isa<DIExpression>(UBound),
|
||||
"UpperBound must be signed constant or DIVariable or DIExpression",
|
||||
&N);
|
||||
auto *Stride = N.getRawStride();
|
||||
AssertDI(Stride, "GenericSubrange must contain stride", &N);
|
||||
AssertDI(isa<DIVariable>(Stride) || isa<DIExpression>(Stride),
|
||||
"Stride must be signed constant or DIVariable or DIExpression", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIEnumerator(const DIEnumerator &N) {
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_enumerator, "invalid tag", &N);
|
||||
}
|
||||
|
35
test/Bitcode/generic_subrange.ll
Normal file
35
test/Bitcode/generic_subrange.ll
Normal file
@ -0,0 +1,35 @@
|
||||
;; This test checks generation of DIGenericSubrange.
|
||||
|
||||
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||
|
||||
;; Test whether DIGenericSubrange is generated.
|
||||
; CHECK: !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
||||
|
||||
; ModuleID = 'generic_subrange.f90'
|
||||
source_filename = "/dir/generic_subrange.ll"
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4)
|
||||
!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir")
|
||||
!4 = !{}
|
||||
!5 = !{!6}
|
||||
!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !8, dataLocation: !10, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref))
|
||||
!7 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float)
|
||||
!8 = !{!9}
|
||||
!9 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
||||
!10 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial)
|
||||
!11 = distinct !DISubprogram(name: "sub1", scope: !2, file: !3, line: 1, type: !12, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
|
||||
!12 = !DISubroutineType(types: !13)
|
||||
!13 = !{null, !14, !19}
|
||||
!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !15)
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(lowerBound: 1, upperBound: !17)
|
||||
!17 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial)
|
||||
!18 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 1024, align: 64, elements: !20)
|
||||
!20 = !{!21}
|
||||
!21 = !DISubrange(lowerBound: 1, upperBound: 16)
|
37
test/Bitcode/generic_subrange_const.ll
Normal file
37
test/Bitcode/generic_subrange_const.ll
Normal file
@ -0,0 +1,37 @@
|
||||
;; This test checks generation of DIGenericSubrange with constant bounds.
|
||||
;; constant bounds are interally represented as DIExpression
|
||||
|
||||
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||
|
||||
;; Test whether DIGenericSubrange is generated.
|
||||
|
||||
; CHECK: !DIGenericSubrange(lowerBound: -20, upperBound: 0, stride: 4)
|
||||
|
||||
; ModuleID = 'generic_subrange_const.f90'
|
||||
source_filename = "/dir/generic_subrange_const.ll"
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4)
|
||||
!3 = !DIFile(filename: "generic_subrange_const.f90", directory: "/dir")
|
||||
!4 = !{}
|
||||
!5 = !{!6}
|
||||
!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !8, dataLocation: !10, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref))
|
||||
!7 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float)
|
||||
!8 = !{!9}
|
||||
!9 = !DIGenericSubrange(lowerBound: -20, upperBound: 0, stride: 4)
|
||||
!10 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial)
|
||||
!11 = distinct !DISubprogram(name: "sub1", scope: !2, file: !3, line: 1, type: !12, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
|
||||
!12 = !DISubroutineType(types: !13)
|
||||
!13 = !{null, !14, !19}
|
||||
!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !15)
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(lowerBound: 1, upperBound: !17)
|
||||
!17 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial)
|
||||
!18 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 1024, align: 64, elements: !20)
|
||||
!20 = !{!21}
|
||||
!21 = !DISubrange(lowerBound: 1, upperBound: 16)
|
35
test/Bitcode/generic_subrange_count.ll
Normal file
35
test/Bitcode/generic_subrange_count.ll
Normal file
@ -0,0 +1,35 @@
|
||||
;; This test checks generation of DIGenericSubrange.
|
||||
|
||||
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||
|
||||
;; Test whether DIGenericSubrange is generated.
|
||||
; CHECK: !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
||||
|
||||
; ModuleID = 'generic_subrange.f90'
|
||||
source_filename = "/dir/generic_subrange.ll"
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4)
|
||||
!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir")
|
||||
!4 = !{}
|
||||
!5 = !{!6}
|
||||
!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !8, dataLocation: !10, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref))
|
||||
!7 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float)
|
||||
!8 = !{!9}
|
||||
!9 = !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
||||
!10 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial)
|
||||
!11 = distinct !DISubprogram(name: "sub1", scope: !2, file: !3, line: 1, type: !12, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
|
||||
!12 = !DISubroutineType(types: !13)
|
||||
!13 = !{null, !14, !19}
|
||||
!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 32, align: 32, elements: !15)
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(lowerBound: 1, upperBound: !17)
|
||||
!17 = distinct !DILocalVariable(scope: !11, file: !3, type: !18, flags: DIFlagArtificial)
|
||||
!18 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 1024, align: 64, elements: !20)
|
||||
!20 = !{!21}
|
||||
!21 = !DISubrange(lowerBound: 1, upperBound: 16)
|
65
test/DebugInfo/X86/dwarfdump-generic_subrange.ll
Normal file
65
test/DebugInfo/X86/dwarfdump-generic_subrange.ll
Normal file
@ -0,0 +1,65 @@
|
||||
;; This test checks whether DW_AT_rank attribute accepts DIExpression.
|
||||
|
||||
; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
;; Test whether DW_AT_data_location is generated.
|
||||
; CHECK-LABEL: DW_TAG_array_type
|
||||
|
||||
; CHECK: DW_AT_rank (DW_OP_push_object_address, DW_OP_plus_uconst 0x8, DW_OP_deref)
|
||||
; CHECK: DW_TAG_generic_subrange
|
||||
; CHECK: DW_AT_lower_bound (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x50, DW_OP_plus, DW_OP_deref)
|
||||
; CHECK: DW_AT_upper_bound (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x78, DW_OP_plus, DW_OP_deref)
|
||||
; CHECK: DW_AT_byte_stride (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x70, DW_OP_plus, DW_OP_deref, DW_OP_lit4, DW_OP_mul)
|
||||
|
||||
;; Test case is hand written with the help of below testcase
|
||||
;;------------------------------
|
||||
;;subroutine sub(arank)
|
||||
;; real :: arank(..)
|
||||
;; print *, RANK(arank)
|
||||
;;end
|
||||
;;------------------------------
|
||||
|
||||
; ModuleID = 'dwarfdump-generic_subrange.ll'
|
||||
source_filename = "dwarfdump-generic_subrange.ll"
|
||||
|
||||
define void @sub_(i64* noalias %arank, i64* noalias %"arank$sd") !dbg !5 {
|
||||
L.entry:
|
||||
call void @llvm.dbg.value(metadata i64* %arank, metadata !17, metadata !DIExpression()), !dbg !18
|
||||
call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !19, metadata !DIExpression()), !dbg !18
|
||||
call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !29, metadata !DIExpression()), !dbg !18
|
||||
ret void, !dbg !18
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable willreturn
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata)
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable willreturn
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !4, imports: !4)
|
||||
!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir")
|
||||
!4 = !{}
|
||||
!5 = distinct !DISubprogram(name: "sub", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
|
||||
!6 = !DISubroutineType(types: !7)
|
||||
!7 = !{null, !8, !14}
|
||||
!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !10)
|
||||
!9 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float)
|
||||
!10 = !{!11}
|
||||
!11 = !DISubrange(lowerBound: 1, upperBound: !12)
|
||||
!12 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
|
||||
!13 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 1024, align: 64, elements: !15)
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(lowerBound: 1, upperBound: 16)
|
||||
!17 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
|
||||
!18 = !DILocation(line: 0, scope: !5)
|
||||
!19 = !DILocalVariable(name: "arank", arg: 1, scope: !5, file: !3, line: 1, type: !20)
|
||||
!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !21, dataLocation: !17, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref))
|
||||
!21 = !{!22}
|
||||
!22 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
||||
!29 = !DILocalVariable(arg: 2, scope: !5, file: !3, line: 1, type: !14, flags: DIFlagArtificial)
|
66
test/DebugInfo/X86/dwarfdump-generic_subrange_const.ll
Normal file
66
test/DebugInfo/X86/dwarfdump-generic_subrange_const.ll
Normal file
@ -0,0 +1,66 @@
|
||||
;; This test checks whether DW_AT_rank attribute accepts constants.
|
||||
;; constants are interally stored as DIExpression.
|
||||
|
||||
; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
;; Test whether DW_AT_data_location is generated.
|
||||
; CHECK-LABEL: DW_TAG_array_type
|
||||
|
||||
; CHECK: DW_AT_rank (DW_OP_push_object_address, DW_OP_plus_uconst 0x8, DW_OP_deref)
|
||||
; CHECK: DW_TAG_generic_subrange
|
||||
; CHECK: DW_AT_lower_bound (-20)
|
||||
; CHECK: DW_AT_upper_bound (0)
|
||||
; CHECK: DW_AT_byte_stride (4)
|
||||
|
||||
;; Test case is hand written with the help of below testcase
|
||||
;;------------------------------
|
||||
;;subroutine sub(arank)
|
||||
;; real :: arank(..)
|
||||
;; print *, RANK(arank)
|
||||
;;end
|
||||
;;------------------------------
|
||||
|
||||
; ModuleID = 'dwarfdump-subrange_const.ll'
|
||||
source_filename = "dwarfdump-subrange_const.ll"
|
||||
|
||||
define void @sub_(i64* noalias %arank, i64* noalias %"arank$sd") !dbg !5 {
|
||||
L.entry:
|
||||
call void @llvm.dbg.value(metadata i64* %arank, metadata !17, metadata !DIExpression()), !dbg !18
|
||||
call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !19, metadata !DIExpression()), !dbg !18
|
||||
call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !29, metadata !DIExpression()), !dbg !18
|
||||
ret void, !dbg !18
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable willreturn
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata)
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable willreturn
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !4, imports: !4)
|
||||
!3 = !DIFile(filename: "generic_subrange_const.f90", directory: "/dir")
|
||||
!4 = !{}
|
||||
!5 = distinct !DISubprogram(name: "sub", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
|
||||
!6 = !DISubroutineType(types: !7)
|
||||
!7 = !{null, !8, !14}
|
||||
!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !10)
|
||||
!9 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float)
|
||||
!10 = !{!11}
|
||||
!11 = !DISubrange(lowerBound: 1, upperBound: !12)
|
||||
!12 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
|
||||
!13 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 1024, align: 64, elements: !15)
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(lowerBound: 1, upperBound: 16)
|
||||
!17 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
|
||||
!18 = !DILocation(line: 0, scope: !5)
|
||||
!19 = !DILocalVariable(name: "arank", arg: 1, scope: !5, file: !3, line: 1, type: !20)
|
||||
!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !21, dataLocation: !17, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref))
|
||||
!21 = !{!22}
|
||||
!22 = !DIGenericSubrange(lowerBound: -20, upperBound: 0, stride: 4)
|
||||
!29 = !DILocalVariable(arg: 2, scope: !5, file: !3, line: 1, type: !14, flags: DIFlagArtificial)
|
65
test/DebugInfo/X86/dwarfdump-generic_subrange_count.ll
Normal file
65
test/DebugInfo/X86/dwarfdump-generic_subrange_count.ll
Normal file
@ -0,0 +1,65 @@
|
||||
;; This test checks whether DW_AT_rank attribute accepts DIExpression.
|
||||
|
||||
; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s
|
||||
|
||||
;; Test whether DW_AT_data_location is generated.
|
||||
; CHECK-LABEL: DW_TAG_array_type
|
||||
|
||||
; CHECK: DW_AT_rank (DW_OP_push_object_address, DW_OP_plus_uconst 0x8, DW_OP_deref)
|
||||
; CHECK: DW_TAG_generic_subrange
|
||||
; CHECK: DW_AT_lower_bound (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x50, DW_OP_plus, DW_OP_deref)
|
||||
; CHECK: DW_AT_count (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x58, DW_OP_plus, DW_OP_deref)
|
||||
; CHECK: DW_AT_byte_stride (DW_OP_push_object_address, DW_OP_over, DW_OP_constu 0x30, DW_OP_mul, DW_OP_plus_uconst 0x70, DW_OP_plus, DW_OP_deref, DW_OP_lit4, DW_OP_mul)
|
||||
|
||||
;; Test case is hand written with the help of below testcase
|
||||
;;------------------------------
|
||||
;;subroutine sub(arank)
|
||||
;; real :: arank(..)
|
||||
;; print *, RANK(arank)
|
||||
;;end
|
||||
;;------------------------------
|
||||
|
||||
; ModuleID = 'dwarfdump-rank.ll'
|
||||
source_filename = "dwarfdump-rank.ll"
|
||||
|
||||
define void @sub_(i64* noalias %arank, i64* noalias %"arank$sd") !dbg !5 {
|
||||
L.entry:
|
||||
call void @llvm.dbg.value(metadata i64* %arank, metadata !17, metadata !DIExpression()), !dbg !18
|
||||
call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !19, metadata !DIExpression()), !dbg !18
|
||||
call void @llvm.dbg.declare(metadata i64* %"arank$sd", metadata !29, metadata !DIExpression()), !dbg !18
|
||||
ret void, !dbg !18
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable willreturn
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata)
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable willreturn
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !4, imports: !4)
|
||||
!3 = !DIFile(filename: "generic_subrange.f90", directory: "/dir")
|
||||
!4 = !{}
|
||||
!5 = distinct !DISubprogram(name: "sub", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
|
||||
!6 = !DISubroutineType(types: !7)
|
||||
!7 = !{null, !8, !14}
|
||||
!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !10)
|
||||
!9 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float)
|
||||
!10 = !{!11}
|
||||
!11 = !DISubrange(lowerBound: 1, upperBound: !12)
|
||||
!12 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
|
||||
!13 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 1024, align: 64, elements: !15)
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(lowerBound: 1, upperBound: 16)
|
||||
!17 = distinct !DILocalVariable(scope: !5, file: !3, type: !13, flags: DIFlagArtificial)
|
||||
!18 = !DILocation(line: 0, scope: !5)
|
||||
!19 = !DILocalVariable(name: "arank", arg: 1, scope: !5, file: !3, line: 1, type: !20)
|
||||
!20 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 32, align: 32, elements: !21, dataLocation: !17, rank: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8, DW_OP_deref))
|
||||
!21 = !{!22}
|
||||
!22 = !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
||||
!29 = !DILocalVariable(arg: 2, scope: !5, file: !3, line: 1, type: !14, flags: DIFlagArtificial)
|
5
test/Verifier/digenericsubrange-count-upperBound.ll
Normal file
5
test/Verifier/digenericsubrange-count-upperBound.ll
Normal file
@ -0,0 +1,5 @@
|
||||
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
|
||||
|
||||
!named = !{!0}
|
||||
; CHECK: GenericSubrange can have any one of count or upperBound
|
||||
!0 = !DIGenericSubrange(count: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 88, DW_OP_plus, DW_OP_deref), lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
5
test/Verifier/digenericsubrange-missing-stride.ll
Normal file
5
test/Verifier/digenericsubrange-missing-stride.ll
Normal file
@ -0,0 +1,5 @@
|
||||
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
|
||||
|
||||
!named = !{!0}
|
||||
; CHECK: GenericSubrange must contain stride
|
||||
!0 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 120, DW_OP_plus, DW_OP_deref))
|
5
test/Verifier/digenericsubrange-missing-upperBound.ll
Normal file
5
test/Verifier/digenericsubrange-missing-upperBound.ll
Normal file
@ -0,0 +1,5 @@
|
||||
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
|
||||
|
||||
!named = !{!0}
|
||||
; CHECK: GenericSubrange must contain count or upperBound
|
||||
!0 = !DIGenericSubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 80, DW_OP_plus, DW_OP_deref), stride: !DIExpression(DW_OP_push_object_address, DW_OP_over, DW_OP_constu, 48, DW_OP_mul, DW_OP_plus_uconst, 112, DW_OP_plus, DW_OP_deref, DW_OP_constu, 4, DW_OP_mul))
|
@ -10,6 +10,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DIBuilder.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
@ -1314,6 +1315,151 @@ TEST_F(DISubrangeTest, fortranAllocatableExpr) {
|
||||
EXPECT_NE(N, DISubrange::get(Context, nullptr, LVother, UE, SE));
|
||||
}
|
||||
|
||||
typedef MetadataTest DIGenericSubrangeTest;
|
||||
|
||||
TEST_F(DIGenericSubrangeTest, fortranAssumedRankInt) {
|
||||
DILocalScope *Scope = getSubprogram();
|
||||
DIFile *File = getFile();
|
||||
DIType *Type = getDerivedType();
|
||||
DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7);
|
||||
auto *LI = DIExpression::get(
|
||||
Context, {dwarf::DW_OP_consts, static_cast<uint64_t>(-10)});
|
||||
auto *UI = DIExpression::get(Context, {dwarf::DW_OP_consts, 10});
|
||||
auto *SI = DIExpression::get(Context, {dwarf::DW_OP_consts, 4});
|
||||
auto *UIother = DIExpression::get(Context, {dwarf::DW_OP_consts, 20});
|
||||
auto *UVother = DILocalVariable::get(Context, Scope, "ubother", File, 8, Type,
|
||||
2, Flags, 8);
|
||||
auto *UEother = DIExpression::get(Context, {5, 6});
|
||||
auto *LIZero = DIExpression::get(Context, {dwarf::DW_OP_consts, 0});
|
||||
auto *UIZero = DIExpression::get(Context, {dwarf::DW_OP_consts, 0});
|
||||
|
||||
auto *N = DIGenericSubrange::get(Context, nullptr, LI, UI, SI);
|
||||
|
||||
auto Lower = N->getLowerBound();
|
||||
ASSERT_TRUE(Lower);
|
||||
ASSERT_TRUE(Lower.is<DIExpression *>());
|
||||
EXPECT_EQ(dyn_cast_or_null<DIExpression>(LI), Lower.get<DIExpression *>());
|
||||
|
||||
auto Upper = N->getUpperBound();
|
||||
ASSERT_TRUE(Upper);
|
||||
ASSERT_TRUE(Upper.is<DIExpression *>());
|
||||
EXPECT_EQ(dyn_cast_or_null<DIExpression>(UI), Upper.get<DIExpression *>());
|
||||
|
||||
auto Stride = N->getStride();
|
||||
ASSERT_TRUE(Stride);
|
||||
ASSERT_TRUE(Stride.is<DIExpression *>());
|
||||
EXPECT_EQ(dyn_cast_or_null<DIExpression>(SI), Stride.get<DIExpression *>());
|
||||
|
||||
EXPECT_EQ(N, DIGenericSubrange::get(Context, nullptr, LI, UI, SI));
|
||||
|
||||
EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LI, UIother, SI));
|
||||
EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LI, UEother, SI));
|
||||
EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LI, UVother, SI));
|
||||
|
||||
auto *NZeroLower = DIGenericSubrange::get(Context, nullptr, LIZero, UI, SI);
|
||||
EXPECT_NE(NZeroLower,
|
||||
DIGenericSubrange::get(Context, nullptr, nullptr, UI, SI));
|
||||
|
||||
auto *NZeroUpper = DIGenericSubrange::get(Context, nullptr, LI, UIZero, SI);
|
||||
EXPECT_NE(NZeroUpper,
|
||||
DIGenericSubrange::get(Context, nullptr, LI, nullptr, SI));
|
||||
}
|
||||
|
||||
TEST_F(DIGenericSubrangeTest, fortranAssumedRankVar) {
|
||||
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 = DIExpression::get(
|
||||
Context, {dwarf::DW_OP_consts, static_cast<uint64_t>(-1)});
|
||||
auto *SEother = DIExpression::get(Context, {5, 6});
|
||||
|
||||
auto *N = DIGenericSubrange::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, DIGenericSubrange::get(Context, nullptr, LV, UV, SV));
|
||||
|
||||
EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LV, UV, SVother));
|
||||
EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LV, UV, SEother));
|
||||
EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LV, UV, SIother));
|
||||
}
|
||||
|
||||
TEST_F(DIGenericSubrangeTest, useDIBuilder) {
|
||||
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 *UE = DIExpression::get(Context, {2, 3});
|
||||
auto *SE = DIExpression::get(Context, {3, 4});
|
||||
|
||||
auto *LVother = DILocalVariable::get(Context, Scope, "lbother", File, 8, Type,
|
||||
2, Flags, 8);
|
||||
auto *LIother = DIExpression::get(
|
||||
Context, {dwarf::DW_OP_consts, static_cast<uint64_t>(-1)});
|
||||
|
||||
Module M("M", Context);
|
||||
DIBuilder DIB(M);
|
||||
|
||||
auto *N = DIB.getOrCreateGenericSubrange(
|
||||
DIGenericSubrange::BoundType(nullptr), DIGenericSubrange::BoundType(LV),
|
||||
DIGenericSubrange::BoundType(UE), DIGenericSubrange::BoundType(SE));
|
||||
|
||||
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<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, DIB.getOrCreateGenericSubrange(DIGenericSubrange::BoundType(nullptr),
|
||||
DIGenericSubrange::BoundType(LV),
|
||||
DIGenericSubrange::BoundType(UE),
|
||||
DIGenericSubrange::BoundType(SE)));
|
||||
|
||||
EXPECT_NE(
|
||||
N, DIB.getOrCreateGenericSubrange(DIGenericSubrange::BoundType(nullptr),
|
||||
DIGenericSubrange::BoundType(LVother),
|
||||
DIGenericSubrange::BoundType(UE),
|
||||
DIGenericSubrange::BoundType(SE)));
|
||||
EXPECT_NE(
|
||||
N, DIB.getOrCreateGenericSubrange(DIGenericSubrange::BoundType(nullptr),
|
||||
DIGenericSubrange::BoundType(LIother),
|
||||
DIGenericSubrange::BoundType(UE),
|
||||
DIGenericSubrange::BoundType(SE)));
|
||||
}
|
||||
typedef MetadataTest DIEnumeratorTest;
|
||||
|
||||
TEST_F(DIEnumeratorTest, get) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user