mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[DebugInfo][flang]Added support for representing Fortran assumed length strings
This patch adds support for representing Fortran `character(n)`. Primarily patch is based out of D54114 with appropriate modifications. Test case IR is generated using our downstream classic-flang. We're in process of upstreaming flang PR's but classic-flang has dependencies on llvm, so this has to get in first. Patch includes functional test case for both IR and corresponding dwarf, furthermore it has been manually tested as well using GDB. Source snippet: ``` program assumedLength call sub('Hello') call sub('Goodbye') contains subroutine sub(string) implicit none character(len=*), intent(in) :: string print *, string end subroutine sub end program assumedLength ``` GDB: ``` (gdb) ptype string type = character (5) (gdb) p string $1 = 'Hello' ``` Reviewed By: aprantl, schweitz Differential Revision: https://reviews.llvm.org/D86305
This commit is contained in:
parent
f788387c0b
commit
9241b8151b
@ -1054,6 +1054,32 @@ and this will materialize an additional DWARF attribute as:
|
||||
...
|
||||
DW_AT_elemental [DW_FORM_flag_present] (true)
|
||||
|
||||
There are a few DWARF tags defined to represent Fortran specific constructs i.e DW_TAG_string_type for representing Fortran character(n). In LLVM this is represented as DIStringType.
|
||||
|
||||
.. code-block:: fortran
|
||||
|
||||
character(len=*), intent(in) :: string
|
||||
|
||||
a Fortran front-end would generate the following descriptors:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
!DILocalVariable(name: "string", arg: 1, scope: !10, file: !3, line: 4, type: !15)
|
||||
!DIStringType(name: "character(*)!2", stringLength: !16, stringLengthExpression: !DIExpression(), size: 32)
|
||||
|
||||
and this will materialize in DWARF tags as:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
DW_TAG_string_type
|
||||
DW_AT_name ("character(*)!2")
|
||||
DW_AT_string_length (0x00000064)
|
||||
0x00000064: DW_TAG_variable
|
||||
DW_AT_location (DW_OP_fbreg +16)
|
||||
DW_AT_type (0x00000083 "integer*8")
|
||||
...
|
||||
DW_AT_artificial (true)
|
||||
|
||||
Debugging information format
|
||||
============================
|
||||
|
||||
|
@ -159,7 +159,8 @@ enum {
|
||||
LLVMDIImportedEntityMetadataKind,
|
||||
LLVMDIMacroMetadataKind,
|
||||
LLVMDIMacroFileMetadataKind,
|
||||
LLVMDICommonBlockMetadataKind
|
||||
LLVMDICommonBlockMetadataKind,
|
||||
LLVMDIStringTypeMetadataKind
|
||||
};
|
||||
typedef unsigned LLVMMetadataKind;
|
||||
|
||||
|
@ -338,7 +338,10 @@ enum MetadataCodes {
|
||||
METADATA_INDEX_OFFSET = 38, // [offset]
|
||||
METADATA_INDEX = 39, // [bitpos]
|
||||
METADATA_LABEL = 40, // [distinct, scope, name, file, line]
|
||||
METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...]
|
||||
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,...]
|
||||
};
|
||||
|
||||
// The constants block (CONSTANTS_BLOCK_ID) describes emission for each
|
||||
|
@ -199,6 +199,12 @@ namespace llvm {
|
||||
unsigned Encoding,
|
||||
DINode::DIFlags Flags = DINode::FlagZero);
|
||||
|
||||
/// Create debugging information entry for a string
|
||||
/// type.
|
||||
/// \param Name Type name.
|
||||
/// \param SizeInBits Size of the type.
|
||||
DIStringType *createStringType(StringRef Name, uint64_t SizeInBits);
|
||||
|
||||
/// Create debugging information entry for a qualified
|
||||
/// type, e.g. 'const int'.
|
||||
/// \param Tag Tag identifing type, e.g. dwarf::TAG_volatile_type
|
||||
|
@ -182,6 +182,7 @@ public:
|
||||
case DISubrangeKind:
|
||||
case DIEnumeratorKind:
|
||||
case DIBasicTypeKind:
|
||||
case DIStringTypeKind:
|
||||
case DIDerivedTypeKind:
|
||||
case DICompositeTypeKind:
|
||||
case DISubroutineTypeKind:
|
||||
@ -451,6 +452,7 @@ public:
|
||||
default:
|
||||
return false;
|
||||
case DIBasicTypeKind:
|
||||
case DIStringTypeKind:
|
||||
case DIDerivedTypeKind:
|
||||
case DICompositeTypeKind:
|
||||
case DISubroutineTypeKind:
|
||||
@ -697,6 +699,7 @@ public:
|
||||
default:
|
||||
return false;
|
||||
case DIBasicTypeKind:
|
||||
case DIStringTypeKind:
|
||||
case DIDerivedTypeKind:
|
||||
case DICompositeTypeKind:
|
||||
case DISubroutineTypeKind:
|
||||
@ -746,6 +749,12 @@ class DIBasicType : public DIType {
|
||||
public:
|
||||
DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name),
|
||||
(Tag, Name, 0, 0, 0, FlagZero))
|
||||
DEFINE_MDNODE_GET(DIBasicType,
|
||||
(unsigned Tag, StringRef Name, uint64_t SizeInBits),
|
||||
(Tag, Name, SizeInBits, 0, 0, FlagZero))
|
||||
DEFINE_MDNODE_GET(DIBasicType,
|
||||
(unsigned Tag, MDString *Name, uint64_t SizeInBits),
|
||||
(Tag, Name, SizeInBits, 0, 0, FlagZero))
|
||||
DEFINE_MDNODE_GET(DIBasicType,
|
||||
(unsigned Tag, StringRef Name, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, unsigned Encoding, DIFlags Flags),
|
||||
@ -770,6 +779,81 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// String type, Fortran CHARACTER(n)
|
||||
class DIStringType : public DIType {
|
||||
friend class LLVMContextImpl;
|
||||
friend class MDNode;
|
||||
|
||||
unsigned Encoding;
|
||||
|
||||
DIStringType(LLVMContext &C, StorageType Storage, unsigned Tag,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding,
|
||||
ArrayRef<Metadata *> Ops)
|
||||
: DIType(C, DIStringTypeKind, Storage, Tag, 0, SizeInBits, AlignInBits, 0,
|
||||
FlagZero, Ops),
|
||||
Encoding(Encoding) {}
|
||||
~DIStringType() = default;
|
||||
|
||||
static DIStringType *getImpl(LLVMContext &Context, unsigned Tag,
|
||||
StringRef Name, Metadata *StringLength,
|
||||
Metadata *StrLenExp, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, unsigned Encoding,
|
||||
StorageType Storage, bool ShouldCreate = true) {
|
||||
return getImpl(Context, Tag, getCanonicalMDString(Context, Name),
|
||||
StringLength, StrLenExp, SizeInBits, AlignInBits, Encoding,
|
||||
Storage, ShouldCreate);
|
||||
}
|
||||
static DIStringType *getImpl(LLVMContext &Context, unsigned Tag,
|
||||
MDString *Name, Metadata *StringLength,
|
||||
Metadata *StrLenExp, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, unsigned Encoding,
|
||||
StorageType Storage, bool ShouldCreate = true);
|
||||
|
||||
TempDIStringType cloneImpl() const {
|
||||
return getTemporary(getContext(), getTag(), getRawName(),
|
||||
getRawStringLength(), getRawStringLengthExp(),
|
||||
getSizeInBits(), getAlignInBits(), getEncoding());
|
||||
}
|
||||
|
||||
public:
|
||||
DEFINE_MDNODE_GET(DIStringType,
|
||||
(unsigned Tag, StringRef Name, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits),
|
||||
(Tag, Name, nullptr, nullptr, SizeInBits, AlignInBits, 0))
|
||||
DEFINE_MDNODE_GET(DIStringType,
|
||||
(unsigned Tag, MDString *Name, Metadata *StringLength,
|
||||
Metadata *StringLengthExp, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, unsigned Encoding),
|
||||
(Tag, Name, StringLength, StringLengthExp, SizeInBits,
|
||||
AlignInBits, Encoding))
|
||||
DEFINE_MDNODE_GET(DIStringType,
|
||||
(unsigned Tag, StringRef Name, Metadata *StringLength,
|
||||
Metadata *StringLengthExp, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, unsigned Encoding),
|
||||
(Tag, Name, StringLength, StringLengthExp, SizeInBits,
|
||||
AlignInBits, Encoding))
|
||||
|
||||
TempDIStringType clone() const { return cloneImpl(); }
|
||||
|
||||
static bool classof(const Metadata *MD) {
|
||||
return MD->getMetadataID() == DIStringTypeKind;
|
||||
}
|
||||
|
||||
DIVariable *getStringLength() const {
|
||||
return cast_or_null<DIVariable>(getRawStringLength());
|
||||
}
|
||||
|
||||
DIExpression *getStringLengthExp() const {
|
||||
return cast_or_null<DIExpression>(getRawStringLengthExp());
|
||||
}
|
||||
|
||||
unsigned getEncoding() const { return Encoding; }
|
||||
|
||||
Metadata *getRawStringLength() const { return getOperand(3); }
|
||||
|
||||
Metadata *getRawStringLengthExp() const { return getOperand(4); }
|
||||
};
|
||||
|
||||
/// Derived types.
|
||||
///
|
||||
/// This includes qualified types, pointers, references, friends, typedefs, and
|
||||
|
@ -114,6 +114,7 @@ HANDLE_SPECIALIZED_MDNODE_BRANCH(DIMacroNode)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock)
|
||||
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType)
|
||||
|
||||
#undef HANDLE_METADATA
|
||||
#undef HANDLE_METADATA_LEAF
|
||||
|
@ -4637,6 +4637,27 @@ bool LLParser::ParseDIBasicType(MDNode *&Result, bool IsDistinct) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ParseDIStringType:
|
||||
/// ::= !DIStringType(name: "character(4)", size: 32, align: 32)
|
||||
bool LLParser::ParseDIStringType(MDNode *&Result, bool IsDistinct) {
|
||||
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
|
||||
OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_string_type)); \
|
||||
OPTIONAL(name, MDStringField, ); \
|
||||
OPTIONAL(stringLength, MDField, ); \
|
||||
OPTIONAL(stringLengthExpression, MDField, ); \
|
||||
OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \
|
||||
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \
|
||||
OPTIONAL(encoding, DwarfAttEncodingField, );
|
||||
PARSE_MD_FIELDS();
|
||||
#undef VISIT_MD_FIELDS
|
||||
|
||||
Result = GET_OR_DISTINCT(DIStringType,
|
||||
(Context, tag.Val, name.Val, stringLength.Val,
|
||||
stringLengthExpression.Val, size.Val, align.Val,
|
||||
encoding.Val));
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ParseDIDerivedType:
|
||||
/// ::= !DIDerivedType(tag: DW_TAG_pointer_type, name: "int", file: !0,
|
||||
/// line: 7, scope: !1, baseType: !2, size: 32,
|
||||
|
@ -853,6 +853,7 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
|
||||
case bitc::METADATA_SUBRANGE:
|
||||
case bitc::METADATA_ENUMERATOR:
|
||||
case bitc::METADATA_BASIC_TYPE:
|
||||
case bitc::METADATA_STRING_TYPE:
|
||||
case bitc::METADATA_DERIVED_TYPE:
|
||||
case bitc::METADATA_COMPOSITE_TYPE:
|
||||
case bitc::METADATA_SUBROUTINE_TYPE:
|
||||
@ -1325,6 +1326,20 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||
NextMetadataNo++;
|
||||
break;
|
||||
}
|
||||
case bitc::METADATA_STRING_TYPE: {
|
||||
if (Record.size() != 8)
|
||||
return error("Invalid record");
|
||||
|
||||
IsDistinct = Record[0];
|
||||
MetadataList.assignValue(
|
||||
GET_OR_DISTINCT(DIStringType,
|
||||
(Context, Record[1], getMDString(Record[2]),
|
||||
getMDOrNull(Record[3]), getMDOrNull(Record[4]),
|
||||
Record[5], Record[6], Record[7])),
|
||||
NextMetadataNo);
|
||||
NextMetadataNo++;
|
||||
break;
|
||||
}
|
||||
case bitc::METADATA_DERIVED_TYPE: {
|
||||
if (Record.size() < 12 || Record.size() > 13)
|
||||
return error("Invalid record");
|
||||
|
@ -301,6 +301,8 @@ private:
|
||||
SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
|
||||
void writeDIBasicType(const DIBasicType *N, SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned Abbrev);
|
||||
void writeDIStringType(const DIStringType *N,
|
||||
SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
|
||||
void writeDIDerivedType(const DIDerivedType *N,
|
||||
SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
|
||||
void writeDICompositeType(const DICompositeType *N,
|
||||
@ -1590,6 +1592,22 @@ void ModuleBitcodeWriter::writeDIBasicType(const DIBasicType *N,
|
||||
Record.clear();
|
||||
}
|
||||
|
||||
void ModuleBitcodeWriter::writeDIStringType(const DIStringType *N,
|
||||
SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned Abbrev) {
|
||||
Record.push_back(N->isDistinct());
|
||||
Record.push_back(N->getTag());
|
||||
Record.push_back(VE.getMetadataOrNullID(N->getRawName()));
|
||||
Record.push_back(VE.getMetadataOrNullID(N->getStringLength()));
|
||||
Record.push_back(VE.getMetadataOrNullID(N->getStringLengthExp()));
|
||||
Record.push_back(N->getSizeInBits());
|
||||
Record.push_back(N->getAlignInBits());
|
||||
Record.push_back(N->getEncoding());
|
||||
|
||||
Stream.EmitRecord(bitc::METADATA_STRING_TYPE, Record, Abbrev);
|
||||
Record.clear();
|
||||
}
|
||||
|
||||
void ModuleBitcodeWriter::writeDIDerivedType(const DIDerivedType *N,
|
||||
SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned Abbrev) {
|
||||
|
@ -178,6 +178,9 @@ public:
|
||||
DebugLocStream::ListBuilder &List,
|
||||
const DIBasicType *BT,
|
||||
DwarfCompileUnit &TheCU);
|
||||
|
||||
void finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List,
|
||||
const DIStringType *ST);
|
||||
};
|
||||
|
||||
/// Compare two DbgValueLocs for equality.
|
||||
|
@ -412,6 +412,9 @@ class DwarfDebug : public DebugHandlerBase {
|
||||
bool SingleCU;
|
||||
bool IsDarwin;
|
||||
|
||||
/// Map for tracking Fortran deferred CHARACTER lengths.
|
||||
DenseMap<const DIStringType *, unsigned> StringTypeLocMap;
|
||||
|
||||
AddressPool AddrPool;
|
||||
|
||||
/// Accelerator tables.
|
||||
@ -772,6 +775,17 @@ public:
|
||||
return CUDieMap.lookup(Die);
|
||||
}
|
||||
|
||||
unsigned getStringTypeLoc(const DIStringType *ST) const {
|
||||
auto I = StringTypeLocMap.find(ST);
|
||||
return I != StringTypeLocMap.end() ? I->second : 0;
|
||||
}
|
||||
|
||||
void addStringTypeLoc(const DIStringType *ST, unsigned Loc) {
|
||||
assert(ST);
|
||||
if (Loc)
|
||||
StringTypeLocMap[ST] = Loc;
|
||||
}
|
||||
|
||||
/// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger.
|
||||
///
|
||||
/// Returns whether we are "tuning" for a given debugger.
|
||||
|
@ -635,6 +635,8 @@ DIE *DwarfUnit::createTypeDIE(const DIScope *Context, DIE &ContextDIE,
|
||||
|
||||
if (auto *BT = dyn_cast<DIBasicType>(Ty))
|
||||
constructTypeDIE(TyDIE, BT);
|
||||
else if (auto *ST = dyn_cast<DIStringType>(Ty))
|
||||
constructTypeDIE(TyDIE, ST);
|
||||
else if (auto *STy = dyn_cast<DISubroutineType>(Ty))
|
||||
constructTypeDIE(TyDIE, STy);
|
||||
else if (auto *CTy = dyn_cast<DICompositeType>(Ty)) {
|
||||
@ -753,8 +755,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
|
||||
if (BTy->getTag() == dwarf::DW_TAG_unspecified_type)
|
||||
return;
|
||||
|
||||
addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
|
||||
BTy->getEncoding());
|
||||
if (BTy->getTag() != dwarf::DW_TAG_string_type)
|
||||
addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
|
||||
BTy->getEncoding());
|
||||
|
||||
uint64_t Size = BTy->getSizeInBits() >> 3;
|
||||
addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size);
|
||||
@ -765,6 +768,28 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
|
||||
addUInt(Buffer, dwarf::DW_AT_endianity, None, dwarf::DW_END_little);
|
||||
}
|
||||
|
||||
void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) {
|
||||
// Get core information.
|
||||
StringRef Name = STy->getName();
|
||||
// Add name if not anonymous or intermediate type.
|
||||
if (!Name.empty())
|
||||
addString(Buffer, dwarf::DW_AT_name, Name);
|
||||
|
||||
if (DIVariable *Var = STy->getStringLength()) {
|
||||
if (auto *VarDIE = getDIE(Var))
|
||||
addDIEEntry(Buffer, dwarf::DW_AT_string_length, *VarDIE);
|
||||
} else {
|
||||
uint64_t Size = STy->getSizeInBits() >> 3;
|
||||
addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size);
|
||||
}
|
||||
|
||||
if (STy->getEncoding()) {
|
||||
// For eventual Unicode support.
|
||||
addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
|
||||
STy->getEncoding());
|
||||
}
|
||||
}
|
||||
|
||||
void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
|
||||
// Get core information.
|
||||
StringRef Name = DTy->getName();
|
||||
|
@ -300,6 +300,7 @@ protected:
|
||||
|
||||
private:
|
||||
void constructTypeDIE(DIE &Buffer, const DIBasicType *BTy);
|
||||
void constructTypeDIE(DIE &Buffer, const DIStringType *BTy);
|
||||
void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy);
|
||||
void constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy);
|
||||
void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy);
|
||||
|
@ -1916,6 +1916,23 @@ static void writeDIBasicType(raw_ostream &Out, const DIBasicType *N,
|
||||
Out << ")";
|
||||
}
|
||||
|
||||
static void writeDIStringType(raw_ostream &Out, const DIStringType *N,
|
||||
TypePrinting *TypePrinter, SlotTracker *Machine,
|
||||
const Module *Context) {
|
||||
Out << "!DIStringType(";
|
||||
MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
|
||||
if (N->getTag() != dwarf::DW_TAG_string_type)
|
||||
Printer.printTag(N);
|
||||
Printer.printString("name", N->getName());
|
||||
Printer.printMetadata("stringLength", N->getRawStringLength());
|
||||
Printer.printMetadata("stringLengthExpression", N->getRawStringLengthExp());
|
||||
Printer.printInt("size", N->getSizeInBits());
|
||||
Printer.printInt("align", N->getAlignInBits());
|
||||
Printer.printDwarfEnum("encoding", N->getEncoding(),
|
||||
dwarf::AttributeEncodingString);
|
||||
Out << ")";
|
||||
}
|
||||
|
||||
static void writeDIDerivedType(raw_ostream &Out, const DIDerivedType *N,
|
||||
TypePrinting *TypePrinter, SlotTracker *Machine,
|
||||
const Module *Context) {
|
||||
|
@ -267,6 +267,12 @@ DIBasicType *DIBuilder::createBasicType(StringRef Name, uint64_t SizeInBits,
|
||||
0, Encoding, Flags);
|
||||
}
|
||||
|
||||
DIStringType *DIBuilder::createStringType(StringRef Name, uint64_t SizeInBits) {
|
||||
assert(!Name.empty() && "Unable to create type without name");
|
||||
return DIStringType::get(VMContext, dwarf::DW_TAG_string_type, Name,
|
||||
SizeInBits, 0);
|
||||
}
|
||||
|
||||
DIDerivedType *DIBuilder::createQualifiedType(unsigned Tag, DIType *FromTy) {
|
||||
return DIDerivedType::get(VMContext, Tag, "", nullptr, 0, nullptr, FromTy, 0,
|
||||
0, 0, None, DINode::FlagZero);
|
||||
|
@ -470,6 +470,20 @@ Optional<DIBasicType::Signedness> DIBasicType::getSignedness() const {
|
||||
}
|
||||
}
|
||||
|
||||
DIStringType *DIStringType::getImpl(LLVMContext &Context, unsigned Tag,
|
||||
MDString *Name, Metadata *StringLength,
|
||||
Metadata *StringLengthExp,
|
||||
uint64_t SizeInBits, uint32_t AlignInBits,
|
||||
unsigned Encoding, StorageType Storage,
|
||||
bool ShouldCreate) {
|
||||
assert(isCanonical(Name) && "Expected canonical MDString");
|
||||
DEFINE_GETIMPL_LOOKUP(DIStringType, (Tag, Name, StringLength, StringLengthExp,
|
||||
SizeInBits, AlignInBits, Encoding));
|
||||
Metadata *Ops[] = {nullptr, nullptr, Name, StringLength, StringLengthExp};
|
||||
DEFINE_GETIMPL_STORE(DIStringType, (Tag, SizeInBits, AlignInBits, Encoding),
|
||||
Ops);
|
||||
}
|
||||
|
||||
DIDerivedType *DIDerivedType::getImpl(
|
||||
LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File,
|
||||
unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits,
|
||||
|
@ -397,6 +397,37 @@ template <> struct MDNodeKeyImpl<DIBasicType> {
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MDNodeKeyImpl<DIStringType> {
|
||||
unsigned Tag;
|
||||
MDString *Name;
|
||||
Metadata *StringLength;
|
||||
Metadata *StringLengthExp;
|
||||
uint64_t SizeInBits;
|
||||
uint32_t AlignInBits;
|
||||
unsigned Encoding;
|
||||
|
||||
MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *StringLength,
|
||||
Metadata *StringLengthExp, uint64_t SizeInBits,
|
||||
uint32_t AlignInBits, unsigned Encoding)
|
||||
: Tag(Tag), Name(Name), StringLength(StringLength),
|
||||
StringLengthExp(StringLengthExp), SizeInBits(SizeInBits),
|
||||
AlignInBits(AlignInBits), Encoding(Encoding) {}
|
||||
MDNodeKeyImpl(const DIStringType *N)
|
||||
: Tag(N->getTag()), Name(N->getRawName()),
|
||||
StringLength(N->getRawStringLength()),
|
||||
StringLengthExp(N->getRawStringLengthExp()),
|
||||
SizeInBits(N->getSizeInBits()), AlignInBits(N->getAlignInBits()),
|
||||
Encoding(N->getEncoding()) {}
|
||||
|
||||
bool isKeyOf(const DIStringType *RHS) const {
|
||||
return Tag == RHS->getTag() && Name == RHS->getRawName() &&
|
||||
SizeInBits == RHS->getSizeInBits() &&
|
||||
AlignInBits == RHS->getAlignInBits() &&
|
||||
Encoding == RHS->getEncoding();
|
||||
}
|
||||
unsigned getHashValue() const { return hash_combine(Tag, Name, Encoding); }
|
||||
};
|
||||
|
||||
template <> struct MDNodeKeyImpl<DIDerivedType> {
|
||||
unsigned Tag;
|
||||
MDString *Name;
|
||||
|
@ -926,8 +926,13 @@ void Verifier::visitDIEnumerator(const DIEnumerator &N) {
|
||||
|
||||
void Verifier::visitDIBasicType(const DIBasicType &N) {
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_base_type ||
|
||||
N.getTag() == dwarf::DW_TAG_unspecified_type,
|
||||
N.getTag() == dwarf::DW_TAG_unspecified_type ||
|
||||
N.getTag() == dwarf::DW_TAG_string_type,
|
||||
"invalid tag", &N);
|
||||
}
|
||||
|
||||
void Verifier::visitDIStringType(const DIStringType &N) {
|
||||
AssertDI(N.getTag() == dwarf::DW_TAG_string_type, "invalid tag", &N);
|
||||
AssertDI(!(N.isBigEndian() && N.isLittleEndian()) ,
|
||||
"has conflicting flags", &N);
|
||||
}
|
||||
|
134
test/DebugInfo/distringtype.ll
Normal file
134
test/DebugInfo/distringtype.ll
Normal file
@ -0,0 +1,134 @@
|
||||
;; Test for !DIStringType.!DIStringType is used to construct a Fortran
|
||||
;; CHARACTER intrinsic type, with a LEN type parameter where LEN is a
|
||||
;; dynamic parameter as in a deferred-length CHARACTER. LLVM after
|
||||
;; processing this !DIStringType metadata, generates DW_AT_string_length attribute.
|
||||
;; !DIStringType(name: "character(*)", stringLength: !{{[0-9]+}},
|
||||
;; stringLengthExpression: !DIExpression(), size: 32)
|
||||
|
||||
; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s
|
||||
; CHECK: DW_TAG_string_type
|
||||
; CHECK: DW_AT_name ("character(*)!2")
|
||||
; CHECK-NEXT: DW_AT_string_length
|
||||
|
||||
;; sample fortran testcase involving assumed length string type.
|
||||
;; program assumedLength
|
||||
;; call sub('Hello')
|
||||
;; call sub('Goodbye')
|
||||
;; contains
|
||||
;; subroutine sub(string)
|
||||
;; implicit none
|
||||
;; character(len=*), intent(in) :: string
|
||||
;; print *, string
|
||||
;; end subroutine sub
|
||||
;; end program assumedLength
|
||||
|
||||
; ModuleID = 'test.ll'
|
||||
source_filename = "test.ll"
|
||||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
%struct.struct_ul_MAIN__324 = type <{ i8* }>
|
||||
|
||||
@.C327_MAIN_ = internal constant [7 x i8] c"Goodbye"
|
||||
@.C326_MAIN_ = internal constant [5 x i8] c"Hello"
|
||||
@.C306_MAIN_ = internal constant i32 0
|
||||
@.C336_assumedlength_sub = internal constant i32 14
|
||||
@.C306_assumedlength_sub = internal constant i32 0
|
||||
@.C307_assumedlength_sub = internal constant i64 0
|
||||
@.C331_assumedlength_sub = internal constant i32 6
|
||||
@.C329_assumedlength_sub = internal constant [8 x i8] c"test.f90"
|
||||
@.C328_assumedlength_sub = internal constant i32 8
|
||||
|
||||
define void @MAIN_() !dbg !5 {
|
||||
L.entry:
|
||||
%.S0000_331 = alloca %struct.struct_ul_MAIN__324, align 8
|
||||
%0 = bitcast i32* @.C306_MAIN_ to i8*, !dbg !8
|
||||
%1 = bitcast void (...)* @fort_init to void (i8*, ...)*, !dbg !8
|
||||
call void (i8*, ...) %1(i8* %0), !dbg !8
|
||||
br label %L.LB1_335
|
||||
|
||||
L.LB1_335: ; preds = %L.entry
|
||||
%2 = bitcast [5 x i8]* @.C326_MAIN_ to i64*, !dbg !9
|
||||
%3 = bitcast %struct.struct_ul_MAIN__324* %.S0000_331 to i64*, !dbg !9
|
||||
call void @assumedlength_sub(i64* %2, i64 5, i64* %3), !dbg !9
|
||||
%4 = bitcast [7 x i8]* @.C327_MAIN_ to i64*, !dbg !10
|
||||
%5 = bitcast %struct.struct_ul_MAIN__324* %.S0000_331 to i64*, !dbg !10
|
||||
call void @assumedlength_sub(i64* %4, i64 7, i64* %5), !dbg !10
|
||||
ret void, !dbg !11
|
||||
}
|
||||
|
||||
define internal void @assumedlength_sub(i64* noalias %string, i64 %.U0001.arg, i64* noalias %.S0000) !dbg !12 {
|
||||
L.entry:
|
||||
%.U0001.addr = alloca i64, align 8
|
||||
%z__io_333 = alloca i32, align 4
|
||||
call void @llvm.dbg.declare(metadata i64* %string, metadata !16, metadata !DIExpression()), !dbg !20
|
||||
store i64 %.U0001.arg, i64* %.U0001.addr, align 8
|
||||
call void @llvm.dbg.declare(metadata i64* %.U0001.addr, metadata !18, metadata !DIExpression()), !dbg !20
|
||||
call void @llvm.dbg.declare(metadata i64* %.S0000, metadata !21, metadata !DIExpression()), !dbg !20
|
||||
br label %L.LB2_347
|
||||
|
||||
L.LB2_347: ; preds = %L.entry
|
||||
%0 = bitcast i32* @.C328_assumedlength_sub to i8*, !dbg !23
|
||||
%1 = bitcast [8 x i8]* @.C329_assumedlength_sub to i8*, !dbg !23
|
||||
%2 = bitcast void (...)* @f90io_src_info03a to void (i8*, i8*, i64, ...)*, !dbg !23
|
||||
call void (i8*, i8*, i64, ...) %2(i8* %0, i8* %1, i64 8), !dbg !23
|
||||
%3 = bitcast i32* @.C331_assumedlength_sub to i8*, !dbg !23
|
||||
%4 = bitcast i32* @.C306_assumedlength_sub to i8*, !dbg !23
|
||||
%5 = bitcast i32* @.C306_assumedlength_sub to i8*, !dbg !23
|
||||
%6 = bitcast i32 (...)* @f90io_print_init to i32 (i8*, i8*, i8*, i8*, ...)*, !dbg !23
|
||||
%7 = call i32 (i8*, i8*, i8*, i8*, ...) %6(i8* %3, i8* null, i8* %4, i8* %5), !dbg !23
|
||||
call void @llvm.dbg.declare(metadata i32* %z__io_333, metadata !24, metadata !DIExpression()), !dbg !20
|
||||
store i32 %7, i32* %z__io_333, align 4, !dbg !23
|
||||
%8 = bitcast i64* %string to i8*, !dbg !23
|
||||
%9 = load i64, i64* %.U0001.addr, align 8, !dbg !23
|
||||
%10 = bitcast i32 (...)* @f90io_sc_ch_ldw to i32 (i8*, i32, i64, ...)*, !dbg !23
|
||||
%11 = call i32 (i8*, i32, i64, ...) %10(i8* %8, i32 14, i64 %9), !dbg !23
|
||||
store i32 %11, i32* %z__io_333, align 4, !dbg !23
|
||||
%12 = call i32 (...) @f90io_ldw_end(), !dbg !23
|
||||
store i32 %12, i32* %z__io_333, align 4, !dbg !23
|
||||
ret void, !dbg !26
|
||||
}
|
||||
|
||||
declare signext i32 @f90io_ldw_end(...)
|
||||
|
||||
declare signext i32 @f90io_sc_ch_ldw(...)
|
||||
|
||||
declare signext i32 @f90io_print_init(...)
|
||||
|
||||
declare void @f90io_src_info03a(...)
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable willreturn
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata)
|
||||
|
||||
declare void @fort_init(...)
|
||||
|
||||
!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: "test.f90", directory: "/tmp")
|
||||
!4 = !{}
|
||||
!5 = distinct !DISubprogram(name: "assumedlength", 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 = !DILocation(line: 1, column: 1, scope: !5)
|
||||
!9 = !DILocation(line: 2, column: 1, scope: !5)
|
||||
!10 = !DILocation(line: 3, column: 1, scope: !5)
|
||||
!11 = !DILocation(line: 4, column: 1, scope: !5)
|
||||
!12 = distinct !DISubprogram(name: "sub", scope: !5, file: !3, line: 5, type: !13, scopeLine: 5, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !2)
|
||||
!13 = !DISubroutineType(types: !14)
|
||||
!14 = !{null, !15}
|
||||
!15 = !DIStringType(name: "character(*)!1", size: 32)
|
||||
!16 = !DILocalVariable(name: "string", arg: 1, scope: !12, file: !3, type: !17)
|
||||
!17 = !DIStringType(name: "character(*)!2", stringLength: !18, stringLengthExpression: !DIExpression(), size: 32)
|
||||
!18 = !DILocalVariable(arg: 2, scope: !12, file: !3, type: !19, flags: DIFlagArtificial)
|
||||
!19 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!20 = !DILocation(line: 0, scope: !12)
|
||||
!21 = !DILocalVariable(arg: 3, scope: !12, file: !3, type: !22, flags: DIFlagArtificial)
|
||||
!22 = !DIBasicType(name: "uinteger*8", size: 64, align: 64, encoding: DW_ATE_unsigned)
|
||||
!23 = !DILocation(line: 8, column: 1, scope: !12)
|
||||
!24 = distinct !DILocalVariable(scope: !12, file: !3, type: !25, flags: DIFlagArtificial)
|
||||
!25 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed)
|
||||
!26 = !DILocation(line: 9, column: 1, scope: !12)
|
27
test/DebugInfo/fortran-string-type.ll
Normal file
27
test/DebugInfo/fortran-string-type.ll
Normal file
@ -0,0 +1,27 @@
|
||||
;; Test for !DIStringType. This DI is used to construct a Fortran CHARACTER
|
||||
;; intrinsic type, either with a compile-time constant LEN type parameter or
|
||||
;; when LEN is a dynamic parameter as in a deferred-length CHARACTER. (See
|
||||
;; section 7.4.4 of the Fortran 2018 standard.)
|
||||
|
||||
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||
; CHECK: !DIStringType(name: "character(*)", stringLength: !{{[0-9]+}}, stringLengthExpression: !DIExpression(), size: 32)
|
||||
; CHECK: !DIStringType(name: "character(10)", size: 80, align: 8)
|
||||
; CHECK: !DIBasicType(tag: DW_TAG_string_type
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.dbg.cu = !{!2}
|
||||
|
||||
!0 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!1 = !{i32 1, !"Debug Info Version", i32 3}
|
||||
!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: "Flang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4)
|
||||
!3 = !DIFile(filename: "fortran-string-type.f", directory: "/")
|
||||
!4 = !{}
|
||||
!5 = !{!6, !9, !12, !13}
|
||||
!6 = !DIStringType(name: "character(*)", stringLength: !7, stringLengthExpression: !DIExpression(), size: 32)
|
||||
!7 = !DILocalVariable(arg: 2, scope: !8, file: !3, line: 256, type: !11, flags: DIFlagArtificial)
|
||||
!8 = distinct !DISubprogram(name: "subprgm", scope: !2, file: !3, line: 256, type: !9, isLocal: false, isDefinition: true, scopeLine: 256, isOptimized: false, unit: !2)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{null, !6, !11}
|
||||
!11 = !DIBasicType(name: "integer*8", size: 64, align: 64, encoding: DW_ATE_signed)
|
||||
!12 = !DIStringType(name: "character(10)", size: 80, align: 8)
|
||||
!13 = !DIBasicType(tag: DW_TAG_string_type, name: "character")
|
Loading…
x
Reference in New Issue
Block a user