Index: include/llvm/IR/DebugInfoFlags.def =================================================================== --- include/llvm/IR/DebugInfoFlags.def +++ include/llvm/IR/DebugInfoFlags.def @@ -85,11 +85,14 @@ HANDLE_DISP_FLAG((1u << 2), LocalToUnit) HANDLE_DISP_FLAG((1u << 3), Definition) HANDLE_DISP_FLAG((1u << 4), Optimized) +HANDLE_DISP_FLAG((1u << 5), Pure) +HANDLE_DISP_FLAG((1u << 6), Elemental) +HANDLE_DISP_FLAG((1u << 7), Recursive) #ifdef DISP_FLAG_LARGEST_NEEDED // Intended to be used with ADT/BitmaskEnum.h. // NOTE: Always must be equal to largest flag, check this when adding new flags. -HANDLE_DISP_FLAG((1 << 4), Largest) +HANDLE_DISP_FLAG((1 << 7), Largest) #undef DISP_FLAG_LARGEST_NEEDED #endif Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -1801,6 +1801,9 @@ return getFlags() & FlagAllCallsDescribed; } bool isMainSubprogram() const { return getFlags() & FlagMainSubprogram; } + bool isPure() const { return getSPFlags() & SPFlagPure; } + bool isElemental() const { return getSPFlags() & SPFlagElemental; } + bool isRecursive() const { return getSPFlags() & SPFlagRecursive; } /// Check if this is reference-qualified. /// Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1267,6 +1267,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: test/Assembler/disubprogram.ll =================================================================== --- test/Assembler/disubprogram.ll +++ test/Assembler/disubprogram.ll @@ -6,8 +6,8 @@ ret void } -; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15} -!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15} +; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17, !18, !19} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !17, !19, !20, !21} !0 = !{null} !1 = distinct !DICompositeType(tag: DW_TAG_structure_type) @@ -81,3 +81,14 @@ !16 = !{i32 1, !"Debug Info Version", i32 3} !llvm.module.flags = !{!16} !llvm.dbg.cu = !{!8} + +; CHECK: !DISubprogram({{.*}}subroutine1{{.*}}, spFlags: DISPFlagDefinition | DISPFlagPure, +; CHECK: !DISubprogram({{.*}}subroutine2{{.*}}, spFlags: DISPFlagDefinition | DISPFlagElemental, +; CHECK: !DISubprogram({{.*}}subroutine3{{.*}}, spFlags: DISPFlagDefinition | DISPFlagRecursive, +; CHECK: !DISubprogram({{.*}}subroutine4{{.*}}, spFlags: DISPFlagDefinition | DISPFlagPure | DISPFlagElemental | DISPFlagRecursive, + +!17 = distinct !DISubprogram(name: "subroutine1", scope: !1, file: !2, line: 1, type: !18, scopeLine: 2, spFlags: DISPFlagDefinition | DISPFlagPure, unit: !8, retainedNodes: !6) +!18 = !DISubroutineType(types: !0) +!19 = distinct !DISubprogram(name: "subroutine2", scope: !1, file: !2, line: 5, type: !18, scopeLine: 6, spFlags: DISPFlagDefinition | DISPFlagElemental, unit: !8, retainedNodes: !6) +!20 = distinct !DISubprogram(name: "subroutine3", scope: !1, file: !2, line: 9, type: !18, scopeLine: 10, spFlags: DISPFlagDefinition | DISPFlagRecursive, unit: !8, retainedNodes: !6) +!21 = distinct !DISubprogram(name: "subroutine4", scope: !1, file: !2, line: 13, type: !18, scopeLine: 14, spFlags: DISPFlagDefinition | DISPFlagPure | DISPFlagElemental | DISPFlagRecursive, unit: !8, retainedNodes: !6) Index: test/DebugInfo/Generic/fortran-subprogram-attr.ll =================================================================== --- /dev/null +++ test/DebugInfo/Generic/fortran-subprogram-attr.ll @@ -0,0 +1,74 @@ +; REQUIRES: object-emission + +; Test for DISPFlagPure, DISPFlagElement and DISPFlagRecursive. These +; three DISPFlags are used to attach DW_AT_pure, DW_AT_element, and +; DW_AT_recursive attributes to DW_TAG_subprogram DIEs. + +; -- test the resulting DWARF to make sure we're emitting +; DW_AT_{pure,elemental,recursive}. + +; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t.o +; RUN: llvm-dwarfdump -v -debug-info %t.o | FileCheck %s + +; CHECK: DW_TAG_subprogram +; CHECK-DAG: DW_AT_name {{.*}} "subroutine1" +; CHECK-DAG: DW_AT_pure [DW_FORM_flag_present] (true) +; CHECK: DW_TAG_subprogram +; CHECK-DAG: DW_AT_name {{.*}} "subroutine2" +; CHECK-DAG: DW_AT_elemental [DW_FORM_flag_present] (true) +; CHECK: DW_TAG_subprogram +; CHECK-DAG: DW_AT_name {{.*}} "subroutine3" +; CHECK-DAG: DW_AT_recursive [DW_FORM_flag_present] (true) +; CHECK: DW_TAG_subprogram +; CHECK-DAG: DW_AT_name {{.*}} "subroutine4" +; CHECK-DAG: DW_AT_pure [DW_FORM_flag_present] (true) +; CHECK-DAG: DW_AT_elemental [DW_FORM_flag_present] (true) +; CHECK-DAG: DW_AT_recursive [DW_FORM_flag_present] (true) +; CHECK: {{DW_TAG|NULL}} + + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @subroutine1() !dbg !7 { +entry: + ret void, !dbg !10 +} + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @subroutine2() !dbg !11 { +entry: + ret void, !dbg !12 +} + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @subroutine3() !dbg !13 { +entry: + ret void, !dbg !14 +} + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @subroutine4() !dbg !15 { +entry: + ret void, !dbg !16 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "c", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "x.f", directory: "/tmp") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"c"} +!7 = distinct !DISubprogram(name: "subroutine1", scope: !1, file: !1, line: 1, type: !8, scopeLine: 2, spFlags: DISPFlagDefinition | DISPFlagPure, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocation(line: 3, column: 1, scope: !7) +!11 = distinct !DISubprogram(name: "subroutine2", scope: !1, file: !1, line: 5, type: !8, scopeLine: 6, spFlags: DISPFlagDefinition | DISPFlagElemental, unit: !0, retainedNodes: !2) +!12 = !DILocation(line: 7, column: 1, scope: !11) +!13 = distinct !DISubprogram(name: "subroutine3", scope: !1, file: !1, line: 9, type: !8, scopeLine: 10, spFlags: DISPFlagDefinition | DISPFlagRecursive, unit: !0, retainedNodes: !2) +!14 = !DILocation(line: 11, column: 1, scope: !13) +!15 = distinct !DISubprogram(name: "subroutine4", scope: !1, file: !1, line: 13, type: !8, scopeLine: 14, spFlags: DISPFlagDefinition | DISPFlagPure | DISPFlagElemental | DISPFlagRecursive, unit: !0, retainedNodes: !2) +!16 = !DILocation(line: 15, column: 1, scope: !15)