[DebugInfo] Fix DWARF expressions for __block vars that are not on the heap
authorRaphael Isemann <teemperor@gmail.com>
Mon, 17 May 2021 12:02:48 +0000 (14:02 +0200)
committerRaphael Isemann <teemperor@gmail.com>
Mon, 17 May 2021 12:32:07 +0000 (14:32 +0200)
`__block` variables used to be always stored on the head instead of stack.
D51564 allowed `__block` variables to the stored on the stack like normal
variablesif they not captured by any escaping block, but the debug-info
generation code wasn't made aware of it so we still unconditionally emit DWARF
expressions pointing to the heap.

This patch makes CGDebugInfo use the `EscapingByref` introduced in D51564 that
tracks whether the `__block` variable is actually on the heap. If it's stored on
the stack instead we just use the debug info we would generate for normal
variables instead.

Reviewed By: ahatanak, aprantl

Differential Revision: https://reviews.llvm.org/D99946

clang/lib/CodeGen/CGDebugInfo.cpp
clang/test/CodeGen/debug-info-block-expr.c

index 3d96bf1..fefcf7a 100644 (file)
@@ -4303,7 +4303,9 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
   auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
   StringRef Name = VD->getName();
   if (!Name.empty()) {
-    if (VD->hasAttr<BlocksAttr>()) {
+    // __block vars are stored on the heap if they are captured by a block that
+    // can escape the local scope.
+    if (VD->isEscapingByref()) {
       // Here, we need an offset *into* the alloca.
       CharUnits offset = CharUnits::fromQuantity(32);
       Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
index 009e780..5626c5c 100644 (file)
@@ -1,9 +1,55 @@
 // RUN: %clang_cc1 -fblocks -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -DDEAD_CODE -fblocks -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s
+
+typedef void (^BlockTy)();
+void escapeFunc(BlockTy);
+typedef void (^BlockTy)();
+void noEscapeFunc(__attribute__((noescape)) BlockTy);
+
+// Verify that the desired DIExpression are generated for escaping (i.e, not
+// 'noescape') blocks.
+void test_escape_func() {
+// CHECK-LABEL: void @test_escape_func
+// CHECK: call void @llvm.dbg.declare({{.*}}metadata ![[ESCAPE_VAR:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}){{.*}})
+  __block int escape_var;
+// Blocks in dead code branches still capture __block variables.
+#ifdef DEAD_CODE
+  if (0)
+#endif
+  escapeFunc(^{ (void)escape_var; });
+}
+
+// Verify that the desired DIExpression are generated for noescape blocks.
+void test_noescape_func() {
+// CHECK-LABEL: void @test_noescape_func
+// CHECK: call void @llvm.dbg.declare({{.*}}metadata ![[NOESCAPE_VAR:[0-9]+]], metadata !DIExpression())
+  __block int noescape_var;
+  noEscapeFunc(^{ (void)noescape_var; });
+}
+
 // Verify that the desired DIExpression are generated for blocks.
+void test_local_block() {
+// CHECK-LABEL: void @test_local_block
+// CHECK: call void @llvm.dbg.declare({{.*}}metadata ![[BLOCK_VAR:[0-9]+]], metadata !DIExpression(DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}){{.*}})
+  __block int block_var;
 
-void test() {
-// CHECK: call void @llvm.dbg.declare({{.*}}!DIExpression(DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}){{.*}})
-  __block int i;
+// CHECK-LABEL: @__test_local_block_block_invoke
 // CHECK: call void @llvm.dbg.declare({{.*}}!DIExpression(DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref, DW_OP_plus_uconst, {{[0-9]+}}){{.*}})
-  ^ { i = 1; }();
+  ^ { block_var = 1; }();
+}
+
+// Verify that the desired DIExpression are generated for __block vars not used
+// in any block.
+void test_unused() {
+// CHECK-LABEL: void @test_unused
+// CHECK: call void @llvm.dbg.declare({{.*}}metadata ![[UNUSED_VAR:[0-9]+]], metadata !DIExpression())
+  __block int unused_var;
+// Use i (not inside a block).
+  ++unused_var;
 }
+
+// CHECK: ![[ESCAPE_VAR]] = !DILocalVariable(name: "escape_var"
+// CHECK: ![[NOESCAPE_VAR]] = !DILocalVariable(name: "noescape_var"
+// CHECK: ![[BLOCK_VAR]] = !DILocalVariable(name: "block_var"
+// CHECK: ![[UNUSED_VAR]] = !DILocalVariable(name: "unused_var"
+