Skip to content

[mlir][debug] Allow global with local scope. #98358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 11, 2024
Merged

Conversation

abidh
Copy link
Contributor

@abidh abidh commented Jul 10, 2024

Currently, only those global variables in debug info are allowed which have a compile unit or module scope. But global variable with function scope are used in debug info to represent certain type of variables. One example will be static local variables in C. Here the variable is represented as global variable with parent function as its scope. See the code and debug metadata as generated by clang below. You can see that scope of DIGlobalVariable is DISubprogram.

int test() {
    static int a = 0;
    return a++;
}

!0 = !DIGlobalVariableExpression(var: !1...)
!1 = !DIGlobalVariable(name: "a", scope: !2 ...)
!2 = !DISubprogram(name: "test" ...)
!7 = !DICompileUnit(... globals: !8...)
!8 = !{!0}

Similar issue exist in fortran where global variable with function scope are used to represent local variable with save attribute.

This PR will allows such variables during module translation.

Currently, only those global variables in debug info are allowed which
have a compile unit or module scope. But global variable with function
scope are used in debug info to represent certain type of variables.
One example will be static local variables in C. See the code
and debug metadata as generated by clang below. You can see that
scope of `DIGlobalVariable` is `DISubprogram`.

int test() {
    static int a = 0;
    return a++;
}

!0 = !DIGlobalVariableExpression(var: !1...)
!1 = !DIGlobalVariable(name: "a", scope: !2 ...)
!2 = !DISubprogram(name: "test" ...)
!7 = !DICompileUnit(... globals: !8...)
!8 = !{!0}

Similar issue exist in fortran where global variable with function
scope are used to represent local variable with save attribute.

This PR will allows such variable during module translation.
@llvmbot
Copy link
Member

llvmbot commented Jul 10, 2024

@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-mlir-llvm

Author: Abid Qadeer (abidh)

Changes

Currently, only those global variables in debug info are allowed which have a compile unit or module scope. But global variable with function scope are used in debug info to represent certain type of variables. One example will be static local variables in C. Here the variable is represented as global variable with parent function as its scope. See the code and debug metadata as generated by clang below. You can see that scope of DIGlobalVariable is DISubprogram.

int test() {
    static int a = 0;
    return a++;
}

!0 = !DIGlobalVariableExpression(var: !1...)
!1 = !DIGlobalVariable(name: "a", scope: !2 ...)
!2 = !DISubprogram(name: "test" ...)
!7 = !DICompileUnit(... globals: !8...)
!8 = !{!0}

Similar issue exist in fortran where global variable with function scope are used to represent local variable with save attribute.

This PR will allows such variables during module translation.


Full diff: https://github.com/llvm/llvm-project/pull/98358.diff

2 Files Affected:

  • (modified) mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (+7)
  • (modified) mlir/test/Target/LLVMIR/llvmir-debug.mlir (+19)
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 1d2e4725d5d63..9bfdb5b582212 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1073,9 +1073,16 @@ LogicalResult ModuleTranslation::convertGlobals() {
       // variable -> module -> compile unit
       // If a variable scope points to the module then we use the scope of the
       // module to get the compile unit.
+      // Global variables are also used for things like static local variables
+      // in C and local variables with the save attribute in Fortran. The scope
+      // of the variable is the parent function. We use the compile unit of the
+      // parent function in this case.
       llvm::DIScope *scope = diGlobalVar->getScope();
       if (llvm::DIModule *mod = dyn_cast_if_present<llvm::DIModule>(scope))
         scope = mod->getScope();
+      else if (llvm::DISubprogram *sp =
+                   dyn_cast_or_null<llvm::DISubprogram>(scope))
+        scope = sp->getUnit();
 
       // Get the compile unit (scope) of the the global variable.
       if (llvm::DICompileUnit *compileUnit =
diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
index 019e3565c3577..f89ef5af87f4b 100644
--- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
@@ -347,6 +347,25 @@ llvm.mlir.global external @module_global() {dbg_expr = #llvm.di_global_variable_
 
 // -----
 
+// CHECK: @func_global = external global i64, !dbg {{.*}}
+// CHECK-DAG: ![[CU:.*]] = distinct !DICompileUnit({{.*}}globals: ![[GVALS:.*]])
+// CHECK-DAG: ![[SP:.*]] = distinct !DISubprogram(name: "fn_with_gl"{{.*}}unit: ![[CU]])
+// CHECK-DAG: ![[GVAR:.*]] = distinct !DIGlobalVariable(name: "func_global"{{.*}}, scope: ![[SP]]{{.*}})
+// CHECK-DAG: ![[GEXPR:.*]] = !DIGlobalVariableExpression(var: ![[GVAR]], expr: !DIExpression())
+// CHECK-DAG: ![[GVALS]] = !{![[GEXPR]]}
+
+#file = #llvm.di_file<"test.f90" in "existence">
+#cu = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_Fortran95, file = #file, producer = "MLIR", isOptimized = true, emissionKind = Full>
+#ty1 = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "integer", sizeInBits = 64, encoding = DW_ATE_signed>
+#sp = #llvm.di_subprogram<compileUnit = #cu, scope = #file, name = "fn_with_gl", file = #file, subprogramFlags = "Definition|Optimized">
+llvm.mlir.global @func_global() {dbg_expr = #llvm.di_global_variable_expression<var = <scope = #sp, name = "func_global", linkageName = "func_global", file = #file, line = 121, type = #ty1, isLocalToUnit = true, isDefined = true>, expr = <>>} : i64
+
+llvm.func @fn_with_gl() {
+  llvm.return
+} loc(fused<#sp>["foo1.mlir":0:0])
+
+// -----
+
 // Nameless and scopeless global constant.
 
 // CHECK-LABEL: @.str.1 = external constant [10 x i8]

Copy link
Contributor

@gysit gysit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

LGTM modulo nit.

Comment on lines 1083 to 1084
else if (llvm::DISubprogram *sp =
dyn_cast_or_null<llvm::DISubprogram>(scope))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
else if (llvm::DISubprogram *sp =
dyn_cast_or_null<llvm::DISubprogram>(scope))
else if (auto *sp =
dyn_cast_if_present<llvm::DISubprogram>(scope))

nit: auto makes sense here and I believe dyn_cast_if_present is the more modern version.

PS feel free to change llvm::DIModule to auto in the if above as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for he review. I have made the suggested changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect!

@abidh abidh merged commit dab36b2 into llvm:main Jul 11, 2024
7 checks passed
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
Currently, only those global variables in debug info are allowed which
have a compile unit or module scope. But global variable with function
scope are used in debug info to represent certain type of variables. One
example will be static local variables in C. Here the variable is
represented as global variable with parent function as its scope. See
the code and debug metadata as generated by clang below. You can see
that scope of `DIGlobalVariable` is `DISubprogram`.

```
int test() {
    static int a = 0;
    return a++;
}

!0 = !DIGlobalVariableExpression(var: !1...)
!1 = !DIGlobalVariable(name: "a", scope: !2 ...)
!2 = !DISubprogram(name: "test" ...)
!7 = !DICompileUnit(... globals: !8...)
!8 = !{!0}
```

Similar issue exist in fortran where global variable with function scope
are used to represent local variable with save attribute.

This PR will allows such variables during module translation.
@abidh abidh deleted the func_global branch July 17, 2024 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants