[clang] 4b6b2b1 - Reapply: [Assignment Tracking][7/*] Add assignment tracking functionality to clang
via cfe-commits
cfe-commits at lists.llvm.org
Wed Nov 9 01:57:34 PST 2022
Author: OCHyams
Date: 2022-11-09T09:28:41Z
New Revision: 4b6b2b1a425a2eabb3a4b995bb05f4f53e313afa
URL: https://github.com/llvm/llvm-project/commit/4b6b2b1a425a2eabb3a4b995bb05f4f53e313afa
DIFF: https://github.com/llvm/llvm-project/commit/4b6b2b1a425a2eabb3a4b995bb05f4f53e313afa.diff
LOG: Reapply: [Assignment Tracking][7/*] Add assignment tracking functionality to clang
Reverted in 98fa95492f3bbd5befdeb36c88a3ac5ef2740b4e.
The Assignment Tracking debug-info feature is outlined in this RFC:
https://discourse.llvm.org/t/
rfc-assignment-tracking-a-better-way-of-specifying-variable-locations-in-ir
This patch plumbs the AssignmentTrackingPass (AKA declare-to-assign), added in
the previous patch in this set, into the optimisation pipeline from
clang. clang/test/CodeGen/assignment-tracking/assignment-tracking.cpp is the
main test for this patch.
Note: while clang (with the help of the declare-to-assign pass) can now emit
Assignment Tracking metadata, the llvm middle and back ends don't yet
understand it.
Reviewed By: jmorse
Differential Revision: https://reviews.llvm.org/D132226
Added:
clang/test/CodeGen/assignment-tracking/assignment-tracking.cpp
clang/test/CodeGen/assignment-tracking/flag.cpp
clang/test/CodeGen/assignment-tracking/memcpy-fragment.cpp
clang/test/CodeGen/assignment-tracking/nested-scope.cpp
clang/test/Driver/assignment-tracking-opts.c
Modified:
clang/lib/CodeGen/BackendUtil.cpp
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index f5c125da10da6..eb444c829381f 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -30,6 +30,7 @@
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
@@ -830,6 +831,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
SI.registerCallbacks(PIC, &FAM);
PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC);
+ if (CodeGenOpts.EnableAssignmentTracking) {
+ PB.registerPipelineStartEPCallback(
+ [&](ModulePassManager &MPM, OptimizationLevel Level) {
+ MPM.addPass(AssignmentTrackingPass());
+ });
+ }
+
// Enable verify-debuginfo-preserve-each for new PM.
DebugifyEachInstrumentation Debugify;
DebugInfoPerPass DebugInfoBeforePass;
diff --git a/clang/test/CodeGen/assignment-tracking/assignment-tracking.cpp b/clang/test/CodeGen/assignment-tracking/assignment-tracking.cpp
new file mode 100644
index 0000000000000..5cb4e9456a93f
--- /dev/null
+++ b/clang/test/CodeGen/assignment-tracking/assignment-tracking.cpp
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -debug-info-kind=standalone -O0 \
+// RUN: -emit-llvm -fexperimental-assignment-tracking %s -o - \
+// RUN: | FileCheck %s --implicit-check-not="call void @llvm.dbg"
+
+// Based on llvm/test/DebugInfo/Generic/track-assignments.ll - check that using
+// -Xclang -fexperimental-assignment-tracking results in emitting (or, as it is
+// set up currently, telling llvm to create) assignment tracking metadata.
+//
+// See the original test for more info.
+
+struct Inner { int A, B; };
+struct Outer { Inner A, B; };
+struct Large { int A[10]; };
+struct LCopyCtor { int A[4]; LCopyCtor(); LCopyCtor(LCopyCtor const &); };
+int Value, Index, Cond;
+Inner InnerA, InnerB;
+Large L;
+
+void zeroInit() { int Z[3] = {0, 0, 0}; }
+// CHECK-LABEL: define dso_local void @_Z8zeroInitv
+// CHECK: %Z = alloca [3 x i32], align 4, !DIAssignID ![[ID_0:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_0:[0-9]+]], metadata !DIExpression(), metadata ![[ID_0]], metadata ptr %Z, metadata !DIExpression())
+// CHECK: @llvm.memset{{.*}}, !DIAssignID ![[ID_1:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i8 0, metadata ![[VAR_0]], metadata !DIExpression(), metadata ![[ID_1]], metadata ptr %Z, metadata !DIExpression())
+
+void memcpyInit() { int A[4] = {0, 1, 2, 3}; }
+// CHECK-LABEL: define dso_local void @_Z10memcpyInitv
+// CHECK: %A = alloca [4 x i32], align 16, !DIAssignID ![[ID_2:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_1:[0-9]+]], metadata !DIExpression(), metadata ![[ID_2]], metadata ptr %A, metadata !DIExpression())
+// CHECK: @llvm.memcpy{{.*}}, !DIAssignID ![[ID_3:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_1]], metadata !DIExpression(), metadata ![[ID_3]], metadata ptr %A, metadata !DIExpression())
+
+void setField() {
+ Outer O;
+ O.A.B = Value;
+}
+// CHECK-LABEL: define dso_local void @_Z8setFieldv
+// CHECK: %O = alloca %struct.Outer, align 4, !DIAssignID ![[ID_4:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_2:[0-9]+]], metadata !DIExpression(), metadata ![[ID_4]], metadata ptr %O, metadata !DIExpression())
+// CHECK: store i32 %0, ptr %B, align 4,{{.*}}!DIAssignID ![[ID_5:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i32 %0, metadata ![[VAR_2]], metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32), metadata ![[ID_5]], metadata ptr %B, metadata !DIExpression())
+
+void unknownOffset() {
+ int A[2];
+ A[Index] = Value;
+}
+// CHECK-LABEL: define dso_local void @_Z13unknownOffsetv
+// CHECK: %A = alloca [2 x i32], align 4, !DIAssignID ![[ID_6:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_3:[0-9]+]], metadata !DIExpression(), metadata ![[ID_6]], metadata ptr %A, metadata !DIExpression())
+
+Inner sharedAlloca() {
+ if (Cond) {
+ Inner A = InnerA;
+ return A;
+ } else {
+ Inner B = InnerB;
+ return B;
+ }
+}
+// CHECK-LABEL: define dso_local i64 @_Z12sharedAllocav
+// CHECK: %retval = alloca %struct.Inner, align 4, !DIAssignID ![[ID_7:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_4:[0-9]+]], metadata !DIExpression(), metadata ![[ID_7]], metadata ptr %retval, metadata !DIExpression())
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_5:[0-9]+]], metadata !DIExpression(), metadata ![[ID_7]], metadata ptr %retval, metadata !DIExpression())
+// CHECK: if.then:
+// CHECK: call void @llvm.memcpy{{.*}}, !DIAssignID ![[ID_8:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_4]], metadata !DIExpression(), metadata ![[ID_8]], metadata ptr %retval, metadata !DIExpression())
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_5]], metadata !DIExpression(), metadata ![[ID_8]], metadata ptr %retval, metadata !DIExpression())
+// CHECK: if.else:
+// CHECK: call void @llvm.memcpy{{.*}}, !DIAssignID ![[ID_9:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_4]], metadata !DIExpression(), metadata ![[ID_9]], metadata ptr %retval, metadata !DIExpression())
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata i1 undef, metadata ![[VAR_5]], metadata !DIExpression(), metadata ![[ID_9]], metadata ptr %retval, metadata !DIExpression())
+
+Large sret() {
+ Large X = L;
+ return X;
+}
+// CHECK-LABEL: define dso_local void @_Z4sretv
+// CHECK: llvm.dbg.declare
+
+void byval(Large X) {}
+// CHECK-LABEL: define dso_local void @_Z5byval5Large
+// CHECK: llvm.dbg.declare
+
+LCopyCtor indirectReturn() {
+ LCopyCtor R;
+ return R;
+}
+// CHECK-LABEL: define dso_local void @_Z14indirectReturnv
+// CHECK: call void @llvm.dbg.declare
+
+// CHECK-DAG: ![[VAR_0]] = !DILocalVariable(name: "Z",
+// CHECK-DAG: ![[VAR_1]] = !DILocalVariable(name: "A",
+// CHECK-DAG: ![[VAR_2]] = !DILocalVariable(name: "O",
+// CHECK-DAG: ![[VAR_3]] = !DILocalVariable(name: "A",
+// CHECK-DAG: ![[VAR_4]] = !DILocalVariable(name: "B",
+// CHECK-DAG: ![[VAR_5]] = !DILocalVariable(name: "A",
diff --git a/clang/test/CodeGen/assignment-tracking/flag.cpp b/clang/test/CodeGen/assignment-tracking/flag.cpp
new file mode 100644
index 0000000000000..911fa1aca70d8
--- /dev/null
+++ b/clang/test/CodeGen/assignment-tracking/flag.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -debug-info-kind=standalone -O0 \
+// RUN: -emit-llvm -fexperimental-assignment-tracking %s -o - \
+// RUN: | FileCheck %s --check-prefixes=FLAG
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -debug-info-kind=standalone -O0 \
+// RUN: -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefixes=NO-FLAG
+
+// Check some assignment-tracking stuff appears in the output when the flag
+// -fexperimental-assignment-tracking is used, and that it doesn't when
+// the flag is not used (default behaviour: no assignment tracking).
+
+// FLAG: DIAssignID
+// FLAG: dbg.assign
+
+// NO-FLAG-NOT: DIAssignID
+// NO-FLAG-NOT: dbg.assign
+
+void fun(int a) {}
diff --git a/clang/test/CodeGen/assignment-tracking/memcpy-fragment.cpp b/clang/test/CodeGen/assignment-tracking/memcpy-fragment.cpp
new file mode 100644
index 0000000000000..48bb0bfbf7107
--- /dev/null
+++ b/clang/test/CodeGen/assignment-tracking/memcpy-fragment.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -debug-info-kind=standalone -O0 \
+// RUN: -emit-llvm -fexperimental-assignment-tracking %s -o - \
+// RUN: | FileCheck %s
+
+// Check that the (debug) codegen looks right with assignment tracking
+// enabled. Each fragment that is written to should have a dbg.assign that has
+// the DIAssignID of the write as an argument. The fragment offset and size
+// should match the offset into the base storage and size of the store. Each of
+// the scenarios below results in slightly
diff erent arguments generated for
+// the memcpy.
+
+// Test write a complete struct field only.
+void fragmentWhole()
+{
+ struct Record {
+ int num;
+ char ch;
+ };
+
+ Record dest;
+ char src = '\0';
+ __builtin_memcpy(&dest.ch, &src, sizeof(char));
+}
+// CHECK: call void @llvm.memcpy{{.+}}, !DIAssignID ![[memberID:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata{{.*}}undef, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 8), metadata ![[memberID]], metadata ptr %ch, metadata !DIExpression())
+
+// Write starting at a field and overlapping part of another.
+void fragmentWholeToPartial()
+{
+ struct Record {
+ int num1;
+ int num2;
+ };
+
+ Record dest;
+ char src[5]="\0\0\0\0";
+ __builtin_memcpy(&dest.num1, &src, 5);
+}
+// CHECK: call void @llvm.memcpy{{.+}}, !DIAssignID ![[exceed:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata{{.*}}undef, metadata !{{[0-9]+}}, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 40), metadata ![[exceed]], metadata ptr %num1, metadata !DIExpression())
+
+// Write starting between fields.
+void fragmentPartialToWhole()
+{
+ struct record {
+ int num1;
+ int num2;
+ int num3;
+};
+
+ record dest;
+ char src[5]="\0\0\0\0";
+ __builtin_memcpy((char*)&(dest.num2) + 3, &src, 5);
+}
+// CHECK: call void @llvm.memcpy{{.+}}, !DIAssignID ![[addendID:[0-9]+]]
+// CHECK-NEXT: call void @llvm.dbg.assign(metadata{{.*}}undef, metadata !{{.*}}, metadata !DIExpression(DW_OP_LLVM_fragment, 56, 40), metadata ![[addendID]], metadata ptr %add.ptr, metadata !DIExpression())
diff --git a/clang/test/CodeGen/assignment-tracking/nested-scope.cpp b/clang/test/CodeGen/assignment-tracking/nested-scope.cpp
new file mode 100644
index 0000000000000..cd8190462e517
--- /dev/null
+++ b/clang/test/CodeGen/assignment-tracking/nested-scope.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -debug-info-kind=standalone -O0 \
+// RUN: -emit-llvm -fexperimental-assignment-tracking %s -o - \
+// RUN: | FileCheck %s
+
+// Check that dbg.assign intrinsics get a !dbg with with the same scope as
+// their variable.
+
+// CHECK: call void @llvm.dbg.assign({{.+}}, metadata [[local:![0-9]+]], {{.+}}, {{.+}}, {{.+}}), !dbg [[dbg:![0-9]+]]
+// CHECK-DAG: [[local]] = !DILocalVariable(name: "local", scope: [[scope:![0-9]+]],
+// CHECK-DAG: [[dbg]] = !DILocation({{.+}}, scope: [[scope]])
+// CHECK-DAG: [[scope]] = distinct !DILexicalBlock
+
+void ext(int*);
+void fun() {
+ {
+ int local;
+ }
+}
+
diff --git a/clang/test/Driver/assignment-tracking-opts.c b/clang/test/Driver/assignment-tracking-opts.c
new file mode 100644
index 0000000000000..ec739e1ee25ad
--- /dev/null
+++ b/clang/test/Driver/assignment-tracking-opts.c
@@ -0,0 +1,10 @@
+// RUN: %clang -### -S %s -g -target x86_64-linux-gnu 2>&1 | FileCheck --check-prefix=CHECK-NO-AT %s
+// RUN: %clang -### -S %s -g -target x86_64-linux-gnu 2>&1 \
+// RUN: -Xclang -fexperimental-assignment-tracking \
+// RUN: | FileCheck --check-prefix=CHECK-AT %s
+
+// CHECK-NO-AT-NOT: "-mllvm" "-experimental-assignment-tracking"
+// CHECK-NO-AT-NOT: "-fexperimental-assignment-tracking"
+
+// CHECK-AT: "-mllvm" "-experimental-assignment-tracking"
+// CHECK-AT: "-fexperimental-assignment-tracking"
More information about the cfe-commits
mailing list