[Coroutines] Handle InvokeInst in SalvageDebugInfo
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>
Fri, 3 Dec 2021 05:46:52 +0000 (13:46 +0800)
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>
Fri, 3 Dec 2021 05:46:54 +0000 (13:46 +0800)
Since coroutine would be splitted into pieces, compiler would move the
dbg.declare intrinsic after the Storage is created to make sure the
corresponding dbg instruction is still available aftet splitted.
However, it would be problematic if the storage instruction is an
InvokeInst, which is a terminator. We couldn't move instruction after an
InvokeInst. This patch tries to move the dbg.declare intrinsic in the
normal destination of the InvokeInst. It should make sense due to the
Storage should be invalid in exception path.

llvm/lib/Transforms/Coroutines/CoroFrame.cpp
llvm/test/Transforms/Coroutines/coro-debug.ll

index ac3d078..e691dec 100644 (file)
@@ -2572,9 +2572,13 @@ void coro::salvageDebugInfo(
   DVI->setExpression(Expr);
   /// It makes no sense to move the dbg.value intrinsic.
   if (!isa<DbgValueInst>(DVI)) {
-    if (auto *InsertPt = dyn_cast<Instruction>(Storage))
+    if (auto *II = dyn_cast<InvokeInst>(Storage))
+      DVI->moveBefore(II->getNormalDest()->getFirstNonPHI());
+    else if (auto *InsertPt = dyn_cast<Instruction>(Storage)) {
+      assert(!InsertPt->isTerminator() &&
+             "Unimaged terminator that could return a storage.");
       DVI->moveAfter(InsertPt);
-    else if (isa<Argument>(Storage))
+    else if (isa<Argument>(Storage))
       DVI->moveAfter(F->getEntryBlock().getFirstNonPHI());
   }
 }
index 6bff547..0108f7c 100644 (file)
@@ -6,7 +6,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
 
 ; Function Attrs: noinline nounwind
-define i8* @f(i32 %x) #0 !dbg !6 {
+define i8* @f(i32 %x) #0 personality i32 0 !dbg !6 {
 entry:
   %x.addr = alloca i32, align 4
   %coro_hdl = alloca i8*, align 8
@@ -39,7 +39,8 @@ sw.bb:                                            ; preds = %entry
   ; don't crash when encountering nonsensical debug info, verfifier doesn't yet reject these
   call void @llvm.dbg.declare(metadata i8* null, metadata !28, metadata !13), !dbg !16
   call void @llvm.dbg.declare(metadata !{}, metadata !28, metadata !13), !dbg !16
-  br label %next, !dbg !18
+  %new_storgae = invoke i8* @allocate()
+    to label %next unwind label %ehcleanup, !dbg !18
 
 next:
   br label %sw.epilog, !dbg !18
@@ -51,6 +52,7 @@ sw.default:                                       ; preds = %entry
   br label %coro_Suspend, !dbg !18
 
 sw.epilog:                                        ; preds = %sw.bb
+  call void @llvm.dbg.declare(metadata i8* %new_storgae, metadata !31, metadata !13), !dbg !16
   %4 = load i32, i32* %x.addr, align 4, !dbg !20
   %add = add nsw i32 %4, 1, !dbg !21
   store i32 %add, i32* %x.addr, align 4, !dbg !22
@@ -67,6 +69,12 @@ coro_Suspend:                                     ; preds = %coro_Cleanup, %sw.d
   %8 = load i8*, i8** %coro_hdl, align 8, !dbg !24
   store i32 0, i32* %late_local, !dbg !24
   ret i8* %8, !dbg !24
+
+ehcleanup:
+  %ex = landingpad { i8*, i32 }
+          catch i8* null
+  call void @print({ i8*, i32 } %ex)
+  unreachable
 }
 
 ; Function Attrs: nounwind readnone speculatable
@@ -79,6 +87,8 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
 declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) #2
 
 declare i8* @malloc(i64) #3
+declare i8* @allocate() 
+declare void @print({ i8*, i32 })
 
 ; Function Attrs: nounwind readnone
 declare i64 @llvm.coro.size.i64() #4
@@ -151,9 +161,10 @@ attributes #7 = { noduplicate }
 !28 = !DILocalVariable(name: "null", scope: !6, file: !7, line: 55, type: !11)
 !29 = !DILocalVariable(name: "partial_dead", scope: !6, file: !7, line: 55, type: !11)
 !30 = !DILocalVariable(name: "direct_value", scope: !6, file: !7, line: 55, type: !11)
+!31 = !DILocalVariable(name: "allocated", scope: !6, file: !7, line: 55, type: !11)
 
-; CHECK: define i8* @f(i32 %x) #0 !dbg ![[ORIG:[0-9]+]]
-; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[RESUME:[0-9]+]]
+; CHECK: define i8* @f(i32 %x) #0 personality i32 0 !dbg ![[ORIG:[0-9]+]]
+; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 personality i32 0 !dbg ![[RESUME:[0-9]+]]
 ; CHECK: entry.resume:
 ; CHECK: %[[DBG_PTR:.*]] = alloca %f.Frame*
 ; CHECK: call void @llvm.dbg.declare(metadata %f.Frame** %[[DBG_PTR]], metadata ![[RESUME_COROHDL:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst,
@@ -166,8 +177,13 @@ attributes #7 = { noduplicate }
 ; CHECK-NOT: call void @llvm.dbg.declare(metadata i32* undef, metadata !{{[0-9]+}}, metadata !DIExpression())
 ; CHECK: call void @coro.devirt.trigger(i8* null)
 ; CHECK: call void @llvm.dbg.value(metadata %f.Frame** {{.*}}, metadata ![[RESUME_DIRECT_VALUE:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref))
-; CHECK: define internal fastcc void @f.destroy(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[DESTROY:[0-9]+]]
-; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[CLEANUP:[0-9]+]]
+; Check that the dbg.declare intrinsic of invoke instruction is hanled correctly.
+; CHECK: %[[ALLOCATED_STORAGE:.+]] = invoke i8* @allocate()
+; CHECK-NEXT: to label %[[NORMAL_DEST:.+]] unwind
+; CHECK: [[NORMAL_DEST]]
+; CHEKC-NEXT: call void @llvm.dbg.declare(metadata i8* %[[ALLOCATED_STORAGE]]
+; CHECK: define internal fastcc void @f.destroy(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 personality i32 0 !dbg ![[DESTROY:[0-9]+]]
+; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 personality i32 0 !dbg ![[CLEANUP:[0-9]+]]
 
 ; CHECK: ![[ORIG]] = distinct !DISubprogram(name: "f", linkageName: "flink"