Skip to content

Commit 821639d

Browse files
committed
[KeyInstr][Clang] Assignment atom group (llvm#134637)
This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. RFC: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.
1 parent b1dc990 commit 821639d

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5814,6 +5814,15 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
58145814

58155815
assert(E->getOpcode() == BO_Assign && "unexpected binary l-value");
58165816

5817+
// Create a Key Instructions source location atom group that covers both
5818+
// LHS and RHS expressions. Nested RHS expressions may get subsequently
5819+
// separately grouped (1 below):
5820+
//
5821+
// 1. `a = b = c` -> Two atoms.
5822+
// 2. `x = new(1)` -> One atom (for both addr store and value store).
5823+
// 3. Complex and agg assignment -> One atom.
5824+
ApplyAtomGroup Grp(getDebugInfo());
5825+
58175826
// Note that in all of these cases, __block variables need the RHS
58185827
// evaluated first just in case the variable gets moved by the RHS.
58195828

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,7 @@ class ScalarExprEmitter
892892
return result; \
893893
} \
894894
Value *VisitBin##OP##Assign(const CompoundAssignOperator *E) { \
895+
ApplyAtomGroup Grp(CGF.getDebugInfo()); \
895896
return EmitCompoundAssign(E, &ScalarExprEmitter::Emit##OP); \
896897
}
897898
HANDLEBINOP(Mul)
@@ -2935,6 +2936,7 @@ class OMPLastprivateConditionalUpdateRAII {
29352936
llvm::Value *
29362937
ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
29372938
bool isInc, bool isPre) {
2939+
ApplyAtomGroup Grp(CGF.getDebugInfo());
29382940
OMPLastprivateConditionalUpdateRAII OMPRegion(CGF, E);
29392941
QualType type = E->getSubExpr()->getType();
29402942
llvm::PHINode *atomicPHI = nullptr;
@@ -4953,6 +4955,7 @@ llvm::Value *CodeGenFunction::EmitWithOriginalRHSBitfieldAssignment(
49534955
}
49544956

49554957
Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
4958+
ApplyAtomGroup Grp(CGF.getDebugInfo());
49564959
bool Ignore = TestAndClearIgnoreResultAssign();
49574960

49584961
Value *RHS;
@@ -5720,6 +5723,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
57205723

57215724
LValue CodeGenFunction::EmitCompoundAssignmentLValue(
57225725
const CompoundAssignOperator *E) {
5726+
ApplyAtomGroup Grp(getDebugInfo());
57235727
ScalarExprEmitter Scalar(*this);
57245728
Value *Result = nullptr;
57255729
switch (E->getOpcode()) {
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// RUN: %clang_cc1 -gkey-instructions -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \
2+
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
3+
4+
// RUN: %clang_cc1 -gkey-instructions -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \
5+
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
6+
7+
unsigned long long g, h, i;
8+
void fun() {
9+
// CHECK: store i64 0, ptr @g{{.*}}, !dbg [[G1R1:!.*]]
10+
g = 0;
11+
12+
// Treat the two assignments as two atoms.
13+
//
14+
// FIXME: Because of the atomGroup implementation the load can only be
15+
// associated with one of the two stores, despite being a good backup
16+
// loction for both.
17+
// CHECK-NEXT: %0 = load i64, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
18+
// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G3R1:!.*]]
19+
// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G2R1:!.*]]
20+
g = g = g;
21+
22+
// Compound assignment.
23+
// CHECK: %1 = load i64, ptr @g
24+
// CHECK: %add = add i64 %1, 50, !dbg [[G4R2:!.*]]
25+
// CHECK: store i64 %add, ptr @g{{.*}}, !dbg [[G4R1:!.*]]
26+
g += 50;
27+
28+
// Pre/Post Inc/Dec.
29+
// CHECK: %2 = load i64, ptr @g
30+
// CHECK: %inc = add i64 %2, 1, !dbg [[G5R2:!.*]]
31+
// CHECK: store i64 %inc, ptr @g{{.*}}, !dbg [[G5R1:!.*]]
32+
++g;
33+
// CHECK: %3 = load i64, ptr @g
34+
// CHECK: %dec = add i64 %3, -1, !dbg [[G6R2:!.*]]
35+
// CHECK: store i64 %dec, ptr @g{{.*}}, !dbg [[G6R1:!.*]]
36+
g--;
37+
38+
// Compound assignment with assignment on RHS, the assignments should have
39+
// their own separate atom groups.
40+
// CHECK-NEXT: %4 = load i64, ptr @h{{.*}}, !dbg [[load_h_loc:!.*]]
41+
// CHECK-NEXT: %inc1 = add i64 %4, 1, !dbg [[G8R2:!.*]]
42+
// CHECK-NEXT: store i64 %inc1, ptr @h{{.*}}, !dbg [[G8R1:!.*]]
43+
// CHECK-NEXT: %5 = load i64, ptr @g{{.*}}, !dbg [[load_g_loc:!.*]]
44+
// CHECK-NEXT: %add2 = add i64 %5, %inc1, !dbg [[G7R2:!.*]]
45+
// CHECK-NEXT: store i64 %add2, ptr @g{{.*}}, !dbg [[G7R1:!.*]]
46+
g += ++h;
47+
48+
// Double check the comma operator doesn't disturb atom groupings. There
49+
// are three assignments, so we should get three groups.
50+
// FIXME: Same situation as earlier in the test - because of the atomGroup
51+
// implementation the load (from h) can only be associated with one of the two
52+
// stores (to h and g) despite being a good backup location for both.
53+
// CHECK-NEXT: %6 = load i64, ptr @h{{.*}}, !dbg [[load_h_loc2:!.*]]
54+
// CHECK-NEXT: %inc3 = add i64 %6, 1, !dbg [[G9R2:!.*]]
55+
// CHECK-NEXT: store i64 %inc3, ptr @h{{.*}}, !dbg [[G10R1:!.*]]
56+
// CHECK-NEXT: store i64 %inc3, ptr @g{{.*}}, !dbg [[G9R1:!.*]]
57+
// CHECK-NEXT: %7 = load i64, ptr @i{{.*}}, !dbg [[load_i_loc:!.*]]
58+
// CHECK-NEXT: %inc4 = add i64 %7, 1, !dbg [[G11R2:!.*]]
59+
// CHECK-NEXT: store i64 %inc4, ptr @i{{.*}}, !dbg [[G11R1:!.*]]
60+
g = ++h, ++i;
61+
}
62+
63+
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
64+
// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
65+
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
66+
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
67+
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
68+
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
69+
// CHECK: [[G5R2]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 2)
70+
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
71+
// CHECK: [[G6R2]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 2)
72+
// CHECK: [[G6R1]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 1)
73+
// CHECK: [[load_h_loc]] = !DILocation(line: [[#]], column: [[#]], scope: ![[#]])
74+
// CHECK: [[G8R2]] = !DILocation({{.*}}, atomGroup: 8, atomRank: 2)
75+
// CHECK: [[G8R1]] = !DILocation({{.*}}, atomGroup: 8, atomRank: 1)
76+
// CHECK: [[load_g_loc]] = !DILocation(line: [[#]], column: [[#]], scope: ![[#]])
77+
// CHECK: [[G7R2]] = !DILocation({{.*}}, atomGroup: 7, atomRank: 2)
78+
// CHECK: [[G7R1]] = !DILocation({{.*}}, atomGroup: 7, atomRank: 1)
79+
// CHECK: [[load_h_loc2]] = !DILocation(line: [[#]], column: [[#]], scope: ![[#]])
80+
// CHECK: [[G9R2]] = !DILocation({{.*}}, atomGroup: 9, atomRank: 2)
81+
// CHECK: [[G10R1]] = !DILocation({{.*}}, atomGroup: 10, atomRank: 1)
82+
// CHECK: [[G9R1]] = !DILocation({{.*}}, atomGroup: 9, atomRank: 1)
83+
// CHECK: [[load_i_loc]] = !DILocation(line: [[#]], column: [[#]], scope: ![[#]])
84+
// CHECK: [[G11R2]] = !DILocation({{.*}}, atomGroup: 11, atomRank: 2)
85+
// CHECK: [[G11R1]] = !DILocation({{.*}}, atomGroup: 11, atomRank: 1)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gno-column-info -S -emit-llvm -o - -ftrivial-auto-var-init=pattern \
3+
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
4+
5+
// RUN: %clang -gkey-instructions -x c %s -gmlt -gno-column-info -S -emit-llvm -o - -ftrivial-auto-var-init=pattern \
6+
// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
7+
8+
// The implicit-check-not is important; we don't want the GEPs created for the
9+
// store locations to be included in the atom group.
10+
11+
int g;
12+
void a() {
13+
// CHECK: call void @llvm.memcpy{{.*}}%A{{.*}}, !dbg [[G1R1:!.*]]
14+
int A[] = { 1, 2, 3 };
15+
16+
// CHECK: store i32 1, ptr %{{.*}}, !dbg [[G2R1:!.*]]
17+
// CHECK: store i32 2, ptr %{{.*}}, !dbg [[G2R1]]
18+
// CHECK: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
19+
// CHECK: store i32 %0, ptr %{{.*}}, !dbg [[G2R1]]
20+
int B[] = { 1, 2, g };
21+
22+
// CHECK: call void @llvm.memset{{.*}}%big{{.*}}, !dbg [[G3R1:!.*]]
23+
// CHECK: store i8 97{{.*}}, !dbg [[G3R1]]
24+
// CHECK: store i8 98{{.*}}, !dbg [[G3R1]]
25+
// CHECK: store i8 99{{.*}}, !dbg [[G3R1]]
26+
// CHECK: store i8 100{{.*}}, !dbg [[G3R1]]
27+
char big[65536] = { 'a', 'b', 'c', 'd' };
28+
29+
// CHECK: call void @llvm.memset{{.*}}%arr{{.*}}, !dbg [[G4R1:!.*]]
30+
char arr[] = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, };
31+
32+
// CHECK: store i8 -86, ptr %uninit{{.*}}, !dbg [[G5R1:!.*]], !annotation
33+
char uninit; // -ftrivial-auto-var-init=pattern
34+
}
35+
36+
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
37+
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
38+
// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
39+
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
40+
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
41+
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)

0 commit comments

Comments
 (0)