-
Notifications
You must be signed in to change notification settings - Fork 14.1k
[MLIR][LLVM] CallSiteLoc without caller scope not translatable #90759
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
[MLIR][LLVM] CallSiteLoc without caller scope not translatable #90759
Conversation
@llvm/pr-subscribers-mlir-llvm @llvm/pr-subscribers-mlir Author: Billy Zhu (zyx-billy) ChangesIf a CallSiteLoc's caller cannot be translated (returns null), we cannot simply return the translation of the callee location. This is because the resulting DILocation will not have any InlinedAt field for the function it is in, and will fail the LLVM IR verifier. Example: This situation occurs when we have a nested callsite loc, where the middle function in the stack does not have a debug scope
When A is inlined into B, and B is inlined into C, we get
We do not want to translate this into just a Full diff: https://github.com/llvm/llvm-project/pull/90759.diff 2 Files Affected:
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index 2de5e372d88c0e..f02939abc5fe18 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -406,6 +406,10 @@ llvm::DILocation *DebugTranslation::translateLoc(Location loc,
if (auto callLoc = dyn_cast<CallSiteLoc>(loc)) {
// For callsites, the caller is fed as the inlinedAt for the callee.
auto *callerLoc = translateLoc(callLoc.getCaller(), scope, inlinedAt);
+ // If the caller scope does not exist, the callsite cannot be represented
+ // in LLVM (the callee scope may not match the function it is in).
+ if (!callerLoc)
+ return nullptr;
llvmLoc = translateLoc(callLoc.getCallee(), nullptr, callerLoc);
// Fallback: Ignore callee if it has no debug scope.
if (!llvmLoc)
diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
index 8ab1a1b290dad3..e8a3d65209afde 100644
--- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
@@ -108,12 +108,15 @@ llvm.func @func_with_debug(%arg: i64) {
// CHECK: call void @func_no_debug(), !dbg ![[NAMED_LOC:[0-9]+]]
llvm.call @func_no_debug() : () -> () loc("named"("foo.mlir":10:10))
- // CHECK: call void @func_no_debug(), !dbg ![[CALLSITE_LOC:[0-9]+]]
+ // CHECK: call void @func_no_debug(), !dbg ![[MY_SOURCE_LOC:[0-9]+]]
llvm.call @func_no_debug() : () -> () loc(callsite("nodebug.cc":3:4 at "mysource.cc":5:6))
- // CHECK: call void @func_no_debug(), !dbg ![[CALLSITE_LOC:[0-9]+]]
+ // CHECK: call void @func_no_debug(), !dbg ![[MY_SOURCE_LOC]]
llvm.call @func_no_debug() : () -> () loc(callsite("nodebug.cc":3:4 at fused<#sp0>["mysource.cc":5:6]))
+ // CHECK: call void @func_no_debug(), !dbg ![[MY_SOURCE_LOC]]
+ llvm.call @func_no_debug() : () -> () loc(callsite(callsite(fused<#callee>["nodebug.cc":3:4] at "foo.mlir":2:4) at fused<#sp0>["mysource.cc":5:6]))
+
// CHECK: call void @func_no_debug(), !dbg ![[FUSED_LOC:[0-9]+]]
llvm.call @func_no_debug() : () -> () loc(fused[callsite(fused<#callee>["mysource.cc":5:6] at "mysource.cc":1:1), "mysource.cc":1:1])
@@ -153,7 +156,7 @@ llvm.func @empty_types() {
// CHECK: ![[BLOCK_LOC]] = distinct !DILexicalBlock(scope: ![[FUNC_LOC]])
// CHECK: ![[NO_NAME_VAR]] = !DILocalVariable(scope: ![[BLOCK_LOC]])
-// CHECK-DAG: ![[CALLSITE_LOC]] = !DILocation(line: 5, column: 6,
+// CHECK-DAG: ![[MY_SOURCE_LOC]] = !DILocation(line: 5, column: 6
// CHECK-DAG: ![[FILE_LOC]] = !DILocation(line: 1, column: 2,
// CHECK-DAG: ![[NAMED_LOC]] = !DILocation(line: 10, column: 10
// CHECK-DAG: ![[FUSED_LOC]] = !DILocation(line: 1, column: 1
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks for fixing!
…0915) Followup to #90759. Instead of just returning null when the caller scope is not translatable, "jump over" the current caller scope and use the outer scope as the caller if that is available. This means that in an inlined call stack if there are frames without debug scope, those frames are skipped to preserve what is available. In the original example where ``` func A { foo loc(fused<#A>["a":1:1]) } func B { call @A loc("b":1:1) } func C { call @b loc(fused<#C>["c":1:1]) } ``` is inlined into ``` func C { foo loc(callsite( callsite(fused<#A>["a":1:1] at loc("b":1:1)) at fused<#C>["c":1:1])) } ``` The translated result would be `!1`: ``` !0 = !DILocation(line: 1, column: 1, scope: !C) !1 = !DILocation(line: 1, column: 1, scope: !A, inlinedAt: !0) ``` This has a neat benefit in maintaining callsite associativity: No matter if we have `callsite(callsite(A at B) at C)` or `callsite(A at callsite(B at C))`, the translation now is the same. The previous solution did not provide this guarantee, which meant the callsite construction would somehow impact this translation.
If a CallSiteLoc's caller cannot be translated (returns null), we cannot simply return the translation of the callee location. This is because the resulting DILocation will not have any InlinedAt field for the function it is in, and will fail the LLVM IR verifier.
Example:
This situation occurs when we have a nested callsite loc, where the middle function in the stack does not have a debug scope
When A is inlined into B, and B is inlined into C, we get
We do not want to translate this into just a
!DILocation(line: 1, column: 1, scope: !A)
, as that would not be legal in func C, so this is not something we can represent in LLVM IR.