Skip to content

Commit f91d18e

Browse files
committed
[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
1 parent 86fc193 commit f91d18e

20 files changed

+457
-5
lines changed

llvm/docs/SourceLevelDebugging.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,32 @@ and this will materialize an additional DWARF attribute as:
10541054
...
10551055
DW_AT_elemental [DW_FORM_flag_present] (true)
10561056
1057+
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.
1058+
1059+
.. code-block:: fortran
1060+
1061+
character(len=*), intent(in) :: string
1062+
1063+
a Fortran front-end would generate the following descriptors:
1064+
1065+
.. code-block:: text
1066+
1067+
!DILocalVariable(name: "string", arg: 1, scope: !10, file: !3, line: 4, type: !15)
1068+
!DIStringType(name: "character(*)!2", stringLength: !16, stringLengthExpression: !DIExpression(), size: 32)
1069+
1070+
and this will materialize in DWARF tags as:
1071+
1072+
.. code-block:: text
1073+
1074+
DW_TAG_string_type
1075+
DW_AT_name ("character(*)!2")
1076+
DW_AT_string_length (0x00000064)
1077+
0x00000064: DW_TAG_variable
1078+
DW_AT_location (DW_OP_fbreg +16)
1079+
DW_AT_type (0x00000083 "integer*8")
1080+
...
1081+
DW_AT_artificial (true)
1082+
10571083
Debugging information format
10581084
============================
10591085

llvm/include/llvm-c/DebugInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ enum {
159159
LLVMDIImportedEntityMetadataKind,
160160
LLVMDIMacroMetadataKind,
161161
LLVMDIMacroFileMetadataKind,
162-
LLVMDICommonBlockMetadataKind
162+
LLVMDICommonBlockMetadataKind,
163+
LLVMDIStringTypeMetadataKind
163164
};
164165
typedef unsigned LLVMMetadataKind;
165166

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,10 @@ enum MetadataCodes {
338338
METADATA_INDEX_OFFSET = 38, // [offset]
339339
METADATA_INDEX = 39, // [bitpos]
340340
METADATA_LABEL = 40, // [distinct, scope, name, file, line]
341-
METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...]
341+
METADATA_STRING_TYPE = 41, // [distinct, name, size, align,...]
342+
// Codes 42 and 43 are reserved for support for Fortran array specific debug
343+
// info.
344+
METADATA_COMMON_BLOCK = 44 // [distinct, scope, name, variable,...]
342345
};
343346

344347
// The constants block (CONSTANTS_BLOCK_ID) describes emission for each

llvm/include/llvm/IR/DIBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ namespace llvm {
199199
unsigned Encoding,
200200
DINode::DIFlags Flags = DINode::FlagZero);
201201

202+
/// Create debugging information entry for a string
203+
/// type.
204+
/// \param Name Type name.
205+
/// \param SizeInBits Size of the type.
206+
DIStringType *createStringType(StringRef Name, uint64_t SizeInBits);
207+
202208
/// Create debugging information entry for a qualified
203209
/// type, e.g. 'const int'.
204210
/// \param Tag Tag identifing type, e.g. dwarf::TAG_volatile_type

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class DINode : public MDNode {
182182
case DISubrangeKind:
183183
case DIEnumeratorKind:
184184
case DIBasicTypeKind:
185+
case DIStringTypeKind:
185186
case DIDerivedTypeKind:
186187
case DICompositeTypeKind:
187188
case DISubroutineTypeKind:
@@ -451,6 +452,7 @@ class DIScope : public DINode {
451452
default:
452453
return false;
453454
case DIBasicTypeKind:
455+
case DIStringTypeKind:
454456
case DIDerivedTypeKind:
455457
case DICompositeTypeKind:
456458
case DISubroutineTypeKind:
@@ -697,6 +699,7 @@ class DIType : public DIScope {
697699
default:
698700
return false;
699701
case DIBasicTypeKind:
702+
case DIStringTypeKind:
700703
case DIDerivedTypeKind:
701704
case DICompositeTypeKind:
702705
case DISubroutineTypeKind:
@@ -746,6 +749,12 @@ class DIBasicType : public DIType {
746749
public:
747750
DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name),
748751
(Tag, Name, 0, 0, 0, FlagZero))
752+
DEFINE_MDNODE_GET(DIBasicType,
753+
(unsigned Tag, StringRef Name, uint64_t SizeInBits),
754+
(Tag, Name, SizeInBits, 0, 0, FlagZero))
755+
DEFINE_MDNODE_GET(DIBasicType,
756+
(unsigned Tag, MDString *Name, uint64_t SizeInBits),
757+
(Tag, Name, SizeInBits, 0, 0, FlagZero))
749758
DEFINE_MDNODE_GET(DIBasicType,
750759
(unsigned Tag, StringRef Name, uint64_t SizeInBits,
751760
uint32_t AlignInBits, unsigned Encoding, DIFlags Flags),
@@ -770,6 +779,81 @@ class DIBasicType : public DIType {
770779
}
771780
};
772781

782+
/// String type, Fortran CHARACTER(n)
783+
class DIStringType : public DIType {
784+
friend class LLVMContextImpl;
785+
friend class MDNode;
786+
787+
unsigned Encoding;
788+
789+
DIStringType(LLVMContext &C, StorageType Storage, unsigned Tag,
790+
uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding,
791+
ArrayRef<Metadata *> Ops)
792+
: DIType(C, DIStringTypeKind, Storage, Tag, 0, SizeInBits, AlignInBits, 0,
793+
FlagZero, Ops),
794+
Encoding(Encoding) {}
795+
~DIStringType() = default;
796+
797+
static DIStringType *getImpl(LLVMContext &Context, unsigned Tag,
798+
StringRef Name, Metadata *StringLength,
799+
Metadata *StrLenExp, uint64_t SizeInBits,
800+
uint32_t AlignInBits, unsigned Encoding,
801+
StorageType Storage, bool ShouldCreate = true) {
802+
return getImpl(Context, Tag, getCanonicalMDString(Context, Name),
803+
StringLength, StrLenExp, SizeInBits, AlignInBits, Encoding,
804+
Storage, ShouldCreate);
805+
}
806+
static DIStringType *getImpl(LLVMContext &Context, unsigned Tag,
807+
MDString *Name, Metadata *StringLength,
808+
Metadata *StrLenExp, uint64_t SizeInBits,
809+
uint32_t AlignInBits, unsigned Encoding,
810+
StorageType Storage, bool ShouldCreate = true);
811+
812+
TempDIStringType cloneImpl() const {
813+
return getTemporary(getContext(), getTag(), getRawName(),
814+
getRawStringLength(), getRawStringLengthExp(),
815+
getSizeInBits(), getAlignInBits(), getEncoding());
816+
}
817+
818+
public:
819+
DEFINE_MDNODE_GET(DIStringType,
820+
(unsigned Tag, StringRef Name, uint64_t SizeInBits,
821+
uint32_t AlignInBits),
822+
(Tag, Name, nullptr, nullptr, SizeInBits, AlignInBits, 0))
823+
DEFINE_MDNODE_GET(DIStringType,
824+
(unsigned Tag, MDString *Name, Metadata *StringLength,
825+
Metadata *StringLengthExp, uint64_t SizeInBits,
826+
uint32_t AlignInBits, unsigned Encoding),
827+
(Tag, Name, StringLength, StringLengthExp, SizeInBits,
828+
AlignInBits, Encoding))
829+
DEFINE_MDNODE_GET(DIStringType,
830+
(unsigned Tag, StringRef Name, Metadata *StringLength,
831+
Metadata *StringLengthExp, uint64_t SizeInBits,
832+
uint32_t AlignInBits, unsigned Encoding),
833+
(Tag, Name, StringLength, StringLengthExp, SizeInBits,
834+
AlignInBits, Encoding))
835+
836+
TempDIStringType clone() const { return cloneImpl(); }
837+
838+
static bool classof(const Metadata *MD) {
839+
return MD->getMetadataID() == DIStringTypeKind;
840+
}
841+
842+
DIVariable *getStringLength() const {
843+
return cast_or_null<DIVariable>(getRawStringLength());
844+
}
845+
846+
DIExpression *getStringLengthExp() const {
847+
return cast_or_null<DIExpression>(getRawStringLengthExp());
848+
}
849+
850+
unsigned getEncoding() const { return Encoding; }
851+
852+
Metadata *getRawStringLength() const { return getOperand(3); }
853+
854+
Metadata *getRawStringLengthExp() const { return getOperand(4); }
855+
};
856+
773857
/// Derived types.
774858
///
775859
/// This includes qualified types, pointers, references, friends, typedefs, and

llvm/include/llvm/IR/Metadata.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ HANDLE_SPECIALIZED_MDNODE_BRANCH(DIMacroNode)
114114
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro)
115115
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile)
116116
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock)
117+
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType)
117118

118119
#undef HANDLE_METADATA
119120
#undef HANDLE_METADATA_LEAF

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4637,6 +4637,27 @@ bool LLParser::ParseDIBasicType(MDNode *&Result, bool IsDistinct) {
46374637
return false;
46384638
}
46394639

4640+
/// ParseDIStringType:
4641+
/// ::= !DIStringType(name: "character(4)", size: 32, align: 32)
4642+
bool LLParser::ParseDIStringType(MDNode *&Result, bool IsDistinct) {
4643+
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
4644+
OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_string_type)); \
4645+
OPTIONAL(name, MDStringField, ); \
4646+
OPTIONAL(stringLength, MDField, ); \
4647+
OPTIONAL(stringLengthExpression, MDField, ); \
4648+
OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \
4649+
OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \
4650+
OPTIONAL(encoding, DwarfAttEncodingField, );
4651+
PARSE_MD_FIELDS();
4652+
#undef VISIT_MD_FIELDS
4653+
4654+
Result = GET_OR_DISTINCT(DIStringType,
4655+
(Context, tag.Val, name.Val, stringLength.Val,
4656+
stringLengthExpression.Val, size.Val, align.Val,
4657+
encoding.Val));
4658+
return false;
4659+
}
4660+
46404661
/// ParseDIDerivedType:
46414662
/// ::= !DIDerivedType(tag: DW_TAG_pointer_type, name: "int", file: !0,
46424663
/// line: 7, scope: !1, baseType: !2, size: 32,

llvm/lib/Bitcode/Reader/MetadataLoader.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock() {
853853
case bitc::METADATA_SUBRANGE:
854854
case bitc::METADATA_ENUMERATOR:
855855
case bitc::METADATA_BASIC_TYPE:
856+
case bitc::METADATA_STRING_TYPE:
856857
case bitc::METADATA_DERIVED_TYPE:
857858
case bitc::METADATA_COMPOSITE_TYPE:
858859
case bitc::METADATA_SUBROUTINE_TYPE:
@@ -1325,6 +1326,20 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
13251326
NextMetadataNo++;
13261327
break;
13271328
}
1329+
case bitc::METADATA_STRING_TYPE: {
1330+
if (Record.size() != 8)
1331+
return error("Invalid record");
1332+
1333+
IsDistinct = Record[0];
1334+
MetadataList.assignValue(
1335+
GET_OR_DISTINCT(DIStringType,
1336+
(Context, Record[1], getMDString(Record[2]),
1337+
getMDOrNull(Record[3]), getMDOrNull(Record[4]),
1338+
Record[5], Record[6], Record[7])),
1339+
NextMetadataNo);
1340+
NextMetadataNo++;
1341+
break;
1342+
}
13281343
case bitc::METADATA_DERIVED_TYPE: {
13291344
if (Record.size() < 12 || Record.size() > 13)
13301345
return error("Invalid record");

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ class ModuleBitcodeWriter : public ModuleBitcodeWriterBase {
301301
SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
302302
void writeDIBasicType(const DIBasicType *N, SmallVectorImpl<uint64_t> &Record,
303303
unsigned Abbrev);
304+
void writeDIStringType(const DIStringType *N,
305+
SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
304306
void writeDIDerivedType(const DIDerivedType *N,
305307
SmallVectorImpl<uint64_t> &Record, unsigned Abbrev);
306308
void writeDICompositeType(const DICompositeType *N,
@@ -1590,6 +1592,22 @@ void ModuleBitcodeWriter::writeDIBasicType(const DIBasicType *N,
15901592
Record.clear();
15911593
}
15921594

1595+
void ModuleBitcodeWriter::writeDIStringType(const DIStringType *N,
1596+
SmallVectorImpl<uint64_t> &Record,
1597+
unsigned Abbrev) {
1598+
Record.push_back(N->isDistinct());
1599+
Record.push_back(N->getTag());
1600+
Record.push_back(VE.getMetadataOrNullID(N->getRawName()));
1601+
Record.push_back(VE.getMetadataOrNullID(N->getStringLength()));
1602+
Record.push_back(VE.getMetadataOrNullID(N->getStringLengthExp()));
1603+
Record.push_back(N->getSizeInBits());
1604+
Record.push_back(N->getAlignInBits());
1605+
Record.push_back(N->getEncoding());
1606+
1607+
Stream.EmitRecord(bitc::METADATA_STRING_TYPE, Record, Abbrev);
1608+
Record.clear();
1609+
}
1610+
15931611
void ModuleBitcodeWriter::writeDIDerivedType(const DIDerivedType *N,
15941612
SmallVectorImpl<uint64_t> &Record,
15951613
unsigned Abbrev) {

llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ class DebugLocEntry {
178178
DebugLocStream::ListBuilder &List,
179179
const DIBasicType *BT,
180180
DwarfCompileUnit &TheCU);
181+
182+
void finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List,
183+
const DIStringType *ST);
181184
};
182185

183186
/// Compare two DbgValueLocs for equality.

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,9 @@ class DwarfDebug : public DebugHandlerBase {
412412
bool SingleCU;
413413
bool IsDarwin;
414414

415+
/// Map for tracking Fortran deferred CHARACTER lengths.
416+
DenseMap<const DIStringType *, unsigned> StringTypeLocMap;
417+
415418
AddressPool AddrPool;
416419

417420
/// Accelerator tables.
@@ -772,6 +775,17 @@ class DwarfDebug : public DebugHandlerBase {
772775
return CUDieMap.lookup(Die);
773776
}
774777

778+
unsigned getStringTypeLoc(const DIStringType *ST) const {
779+
auto I = StringTypeLocMap.find(ST);
780+
return I != StringTypeLocMap.end() ? I->second : 0;
781+
}
782+
783+
void addStringTypeLoc(const DIStringType *ST, unsigned Loc) {
784+
assert(ST);
785+
if (Loc)
786+
StringTypeLocMap[ST] = Loc;
787+
}
788+
775789
/// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger.
776790
///
777791
/// Returns whether we are "tuning" for a given debugger.

llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,8 @@ DIE *DwarfUnit::createTypeDIE(const DIScope *Context, DIE &ContextDIE,
635635

636636
if (auto *BT = dyn_cast<DIBasicType>(Ty))
637637
constructTypeDIE(TyDIE, BT);
638+
else if (auto *ST = dyn_cast<DIStringType>(Ty))
639+
constructTypeDIE(TyDIE, ST);
638640
else if (auto *STy = dyn_cast<DISubroutineType>(Ty))
639641
constructTypeDIE(TyDIE, STy);
640642
else if (auto *CTy = dyn_cast<DICompositeType>(Ty)) {
@@ -753,8 +755,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
753755
if (BTy->getTag() == dwarf::DW_TAG_unspecified_type)
754756
return;
755757

756-
addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
757-
BTy->getEncoding());
758+
if (BTy->getTag() != dwarf::DW_TAG_string_type)
759+
addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
760+
BTy->getEncoding());
758761

759762
uint64_t Size = BTy->getSizeInBits() >> 3;
760763
addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size);
@@ -765,6 +768,28 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
765768
addUInt(Buffer, dwarf::DW_AT_endianity, None, dwarf::DW_END_little);
766769
}
767770

771+
void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) {
772+
// Get core information.
773+
StringRef Name = STy->getName();
774+
// Add name if not anonymous or intermediate type.
775+
if (!Name.empty())
776+
addString(Buffer, dwarf::DW_AT_name, Name);
777+
778+
if (DIVariable *Var = STy->getStringLength()) {
779+
if (auto *VarDIE = getDIE(Var))
780+
addDIEEntry(Buffer, dwarf::DW_AT_string_length, *VarDIE);
781+
} else {
782+
uint64_t Size = STy->getSizeInBits() >> 3;
783+
addUInt(Buffer, dwarf::DW_AT_byte_size, None, Size);
784+
}
785+
786+
if (STy->getEncoding()) {
787+
// For eventual Unicode support.
788+
addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
789+
STy->getEncoding());
790+
}
791+
}
792+
768793
void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
769794
// Get core information.
770795
StringRef Name = DTy->getName();

llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ class DwarfUnit : public DIEUnit {
300300

301301
private:
302302
void constructTypeDIE(DIE &Buffer, const DIBasicType *BTy);
303+
void constructTypeDIE(DIE &Buffer, const DIStringType *BTy);
303304
void constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy);
304305
void constructTypeDIE(DIE &Buffer, const DISubroutineType *CTy);
305306
void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy);

0 commit comments

Comments
 (0)