Index: include/llvm-c/DebugInfo.h =================================================================== --- include/llvm-c/DebugInfo.h +++ include/llvm-c/DebugInfo.h @@ -59,6 +59,10 @@ LLVMDIFlagTrivial = 1 << 26, LLVMDIFlagBigEndian = 1 << 27, LLVMDIFlagLittleEndian = 1 << 28, + LLVMDIFlagFortran = 1 << 30, + LLVMDIFlagPure = (1 << 30) | (1 << 9), + LLVMDIFlagElemental = (1 << 30) | (1 << 15), + LLVMDIFlagRecursive = (1 << 30) | (1 << 19), LLVMDIFlagIndirectVirtualBase = (1 << 2) | (1 << 5), LLVMDIFlagAccessibility = LLVMDIFlagPrivate | LLVMDIFlagProtected | LLVMDIFlagPublic, Index: include/llvm/IR/DebugInfoFlags.def =================================================================== --- include/llvm/IR/DebugInfoFlags.def +++ include/llvm/IR/DebugInfoFlags.def @@ -52,6 +52,14 @@ HANDLE_DI_FLAG((1 << 28), LittleEndian) HANDLE_DI_FLAG((1 << 29), AllCallsDescribed) +// Fortran flags: use bit 30 to indicate it's Fortran and then overload some +// flags that otherwise have no semantics with respect to Fortran and are not +// used in DISubprogram's member functions +HANDLE_DI_FLAG((1 << 30), Fortran) +HANDLE_DI_FLAG((1 << 30)|(1 << 9), Pure) +HANDLE_DI_FLAG((1 << 30)|(1 << 15), Elemental) +HANDLE_DI_FLAG((1 << 30)|(1 << 19), Recursive) + // To avoid needing a dedicated value for IndirectVirtualBase, we use // the bitwise or of Virtual and FwdDecl, which does not otherwise // make sense for inheritance. @@ -60,7 +68,7 @@ #ifdef DI_FLAG_LARGEST_NEEDED // intended to be used with ADT/BitmaskEnum.h // NOTE: always must be equal to largest flag, check this when adding new flag -HANDLE_DI_FLAG((1 << 29), Largest) +HANDLE_DI_FLAG((1 << 30), Largest) #undef DI_FLAG_LARGEST_NEEDED #endif Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -1740,6 +1740,13 @@ return getFlags() & FlagAllCallsDescribed; } bool isMainSubprogram() const { return getFlags() & FlagMainSubprogram; } + bool isPure() const { return (getFlags() & FlagPure) == FlagPure; } + bool isElemental() const { + return (getFlags() & FlagElemental) == FlagElemental; + } + bool isRecursive() const { + return (getFlags() & FlagRecursive) == FlagRecursive; + } /// Check if this is reference-qualified. /// Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1261,6 +1261,12 @@ if (SP->isMainSubprogram()) addFlag(SPDie, dwarf::DW_AT_main_subprogram); + if (SP->isPure()) + addFlag(SPDie, dwarf::DW_AT_pure); + if (SP->isElemental()) + addFlag(SPDie, dwarf::DW_AT_elemental); + if (SP->isRecursive()) + addFlag(SPDie, dwarf::DW_AT_recursive); } void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -153,6 +153,15 @@ SplitFlags.push_back(FlagVirtualInheritance); Flags &= ~R; } + if (Flags & FlagFortran) { + if ((Flags & FlagPure) == FlagPure) + SplitFlags.push_back(FlagPure); + if ((Flags & FlagElemental) == FlagElemental) + SplitFlags.push_back(FlagElemental); + if ((Flags & FlagRecursive) == FlagRecursive) + SplitFlags.push_back(FlagRecursive); + Flags &= ~(FlagPure|FlagElemental|FlagRecursive); + } if ((Flags & FlagIndirectVirtualBase) == FlagIndirectVirtualBase) { Flags &= ~FlagIndirectVirtualBase; SplitFlags.push_back(FlagIndirectVirtualBase); Index: test/DebugInfo/fortran-subprogram-at.ll =================================================================== --- /dev/null +++ test/DebugInfo/fortran-subprogram-at.ll @@ -0,0 +1,24 @@ +; Test for DIFlagPure, DIFlagElement and DIFlagRecursive. These three +; DIFlags are used to attach DW_AT_pure, DW_AT_element, and DW_AT_recursive +; attributes to DW_TAG_subprogram DIEs. + +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; CHECK: !DISubprogram({{.*}}, flags: DIFlagPure | DIFlagElemental | DIFlagRecursive, + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +define void @subprgm() !dbg !6 { +L: + ret void +} + +!0 = !{i32 2, !"Dwarf Version", i32 2} +!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: !4, globals: !4, imports: !4) +!3 = !DIFile(filename: "fortran-subprogram-at.f", directory: "/") +!4 = !{} +!5 = !DIBasicType(name: "real", size: 32, align: 32, encoding: DW_ATE_float) +!6 = distinct !DISubprogram(name: "subprgm", scope: !2, file: !3, line: 256, type: !7, isLocal: false, isDefinition: true, scopeLine: 256, flags: DIFlagPure|DIFlagElemental|DIFlagRecursive, isOptimized: false, unit: !2) +!7 = !DISubroutineType(types: !8) +!8 = !{null, !5}