Skip to content

Commit 5fc5769

Browse files
authored
[MLIR][LLVM] Exporter skip over inlined frame without debug scope (#90915)
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.
1 parent 69f1442 commit 5fc5769

File tree

2 files changed

+13
-8
lines changed

2 files changed

+13
-8
lines changed

mlir/lib/Target/LLVMIR/DebugTranslation.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,15 @@ llvm::DILocation *DebugTranslation::translateLoc(Location loc,
406406
if (auto callLoc = dyn_cast<CallSiteLoc>(loc)) {
407407
// For callsites, the caller is fed as the inlinedAt for the callee.
408408
auto *callerLoc = translateLoc(callLoc.getCaller(), scope, inlinedAt);
409-
// If the caller scope does not exist, the callsite cannot be represented
410-
// in LLVM (the callee scope may not match the function it is in).
411-
if (!callerLoc)
412-
return nullptr;
409+
// If the caller scope is not translatable, the overall callsite cannot be
410+
// represented in LLVM (the callee scope may not match the parent function).
411+
if (!callerLoc) {
412+
// If there is an inlinedAt scope (an outer caller), skip to that
413+
// directly. Otherwise, cannot translate.
414+
if (!inlinedAt)
415+
return nullptr;
416+
callerLoc = inlinedAt;
417+
}
413418
llvmLoc = translateLoc(callLoc.getCallee(), nullptr, callerLoc);
414419
// Fallback: Ignore callee if it has no debug scope.
415420
if (!llvmLoc)

mlir/test/Target/LLVMIR/llvmir-debug.mlir

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ llvm.func @func_with_debug(%arg: i64) {
114114
// CHECK: call void @func_no_debug(), !dbg ![[MY_SOURCE_LOC]]
115115
llvm.call @func_no_debug() : () -> () loc(callsite("nodebug.cc":3:4 at fused<#sp0>["mysource.cc":5:6]))
116116

117-
// CHECK: call void @func_no_debug(), !dbg ![[MY_SOURCE_LOC]]
118-
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]))
119-
120117
// CHECK: call void @func_no_debug(), !dbg ![[FUSED_LOC:[0-9]+]]
121118
llvm.call @func_no_debug() : () -> () loc(fused[callsite(fused<#callee>["mysource.cc":5:6] at "mysource.cc":1:1), "mysource.cc":1:1])
122119

123-
// CHECK: add i64 %[[ARG]], %[[ARG]], !dbg ![[FUSEDWITH_LOC:[0-9]+]]
120+
// CHECK: call void @func_no_debug(), !dbg ![[FUSEDWITH_LOC:[0-9]+]]
121+
llvm.call @func_no_debug() : () -> () loc(callsite(callsite(fused<#callee>["foo.mlir":2:4] at "foo.mlir":1:1) at fused<#sp0>["foo.mlir":28:5]))
122+
123+
// CHECK: add i64 %[[ARG]], %[[ARG]], !dbg ![[FUSEDWITH_LOC]]
124124
%sum = llvm.add %arg, %arg : i64 loc(callsite(fused<#callee>["foo.mlir":2:4] at fused<#sp0>["foo.mlir":28:5]))
125125

126126
llvm.return

0 commit comments

Comments
 (0)