Skip to content

Commit 059885c

Browse files
authored
[KeyInstr] Complex assignment atoms (#134638)
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 47d5e94 commit 059885c

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

clang/lib/CodeGen/CGExprComplex.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,15 +364,19 @@ class ComplexExprEmitter
364364

365365
// Compound assignments.
366366
ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
367+
ApplyAtomGroup Grp(CGF.getDebugInfo());
367368
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
368369
}
369370
ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) {
371+
ApplyAtomGroup Grp(CGF.getDebugInfo());
370372
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub);
371373
}
372374
ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) {
375+
ApplyAtomGroup Grp(CGF.getDebugInfo());
373376
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul);
374377
}
375378
ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) {
379+
ApplyAtomGroup Grp(CGF.getDebugInfo());
376380
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv);
377381
}
378382

@@ -461,8 +465,12 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue,
461465
Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType());
462466
Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType());
463467

464-
Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
465-
Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
468+
auto *R =
469+
Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
470+
CGF.addInstToCurrentSourceAtom(R, Val.first);
471+
auto *I =
472+
Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
473+
CGF.addInstToCurrentSourceAtom(I, Val.second);
466474
}
467475

468476

@@ -1357,6 +1365,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
13571365

13581366
ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
13591367
ComplexPairTy Val;
1368+
ApplyAtomGroup Grp(CGF.getDebugInfo());
13601369
LValue LV = EmitBinAssignLValue(E, Val);
13611370

13621371
// The result of an assignment in C is the assigned r-value.
@@ -1532,6 +1541,7 @@ static CompoundFunc getComplexOp(BinaryOperatorKind Op) {
15321541

15331542
LValue CodeGenFunction::
15341543
EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
1544+
ApplyAtomGroup Grp(getDebugInfo());
15351545
CompoundFunc Op = getComplexOp(E->getOpcode());
15361546
RValue Val;
15371547
return ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
@@ -1540,6 +1550,8 @@ EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
15401550
LValue CodeGenFunction::
15411551
EmitScalarCompoundAssignWithComplex(const CompoundAssignOperator *E,
15421552
llvm::Value *&Result) {
1553+
// Key Instructions: Don't need to create an atom group here; one will already
1554+
// be active through scalar handling code.
15431555
CompoundFunc Op = getComplexOp(E->getOpcode());
15441556
RValue Val;
15451557
LValue Ret = ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -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 -triple x86_64-linux-gnu -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 --check-prefixes=CHECK,CHECK-C
6+
7+
_Complex float ci;
8+
float f;
9+
void test() {
10+
// CHECK: %ci.real = load float, ptr @ci{{.*}}, !dbg [[G1R2:!.*]]
11+
// CHECK: %ci.imag = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G1R2]]
12+
// CHECK: store float %ci.real, ptr %lc.realp{{.*}}, !dbg [[G1R1:!.*]]
13+
// CHECK: store float %ci.imag, ptr %lc.imagp{{.*}}, !dbg [[G1R1]]
14+
_Complex float lc = ci;
15+
16+
// CHECK: %ci.real1 = load float, ptr @ci{{.*}}, !dbg [[G2R2:!.*]]
17+
// CHECK: %ci.imag2 = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R2]]
18+
// CHECK: store float %ci.real1, ptr @ci{{.*}}, !dbg [[G2R1:!.*]]
19+
// CHECK: store float %ci.imag2, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R1]]
20+
ci = ci;
21+
22+
// CHECK: %add.r = fadd float %ci.real5, %ci.real3, !dbg [[G3R2:!.*]]
23+
// CHECK: %add.i = fadd float %ci.imag6, %ci.imag4, !dbg [[G3R2]]
24+
// CHECK: store float %add.r, ptr @ci{{.*}}, !dbg [[G3R1:!.*]]
25+
// CHECK: store float %add.i, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G3R1]]
26+
ci += ci;
27+
28+
// CHECK: %sub.r = fsub float %ci.real9, %ci.real7, !dbg [[G4R2:!.*]]
29+
// CHECK: %sub.i = fsub float %ci.imag10, %ci.imag8, !dbg [[G4R2]]
30+
// CHECK: store float %sub.r, ptr @ci, align 4, !dbg [[G4R1:!.*]]
31+
// CHECK: store float %sub.i, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1]]
32+
ci -= ci;
33+
34+
// There's control flow introduced here to skip around nan and lib calls
35+
// (which is ignored in the test as none of those insts need be key). This does
36+
// make PHIs "backup" instructions, which is... odd. FIXME: Do we want to make
37+
// the instructions producing the values in the PHI backups instead/too?
38+
// CHECK: %real_mul_phi = phi float [ %mul_r, %entry ], [ %mul_r, %complex_mul_imag_nan ], [ %coerce.real, %complex_mul_libcall ], !dbg [[G5R2:!.*]]
39+
// CHECK: %imag_mul_phi = phi float [ %mul_i, %entry ], [ %mul_i, %complex_mul_imag_nan ], [ %coerce.imag, %complex_mul_libcall ], !dbg [[G5R2]]
40+
// CHECK: store float %real_mul_phi, ptr @ci, align 4, !dbg [[G5R1:!.*]]
41+
// CHECK: store float %imag_mul_phi, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1), align 4, !dbg [[G5R1]]
42+
ci *= ci;
43+
44+
// div goes straight to lib call, which gets saved into a temp.
45+
// CHECK: %coerce21.real = load float, ptr %coerce21.realp, align 4, !dbg [[G6R2:!.*]]
46+
// CHECK: %coerce21.imag = load float, ptr %coerce21.imagp, align 4, !dbg [[G6R2]]
47+
// CHECK: store float %coerce21.real, ptr @ci, align 4, !dbg [[G6R1:!.*]]
48+
// CHECK: store float %coerce21.imag, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1), align 4, !dbg [[G6R1]]
49+
ci /= ci;
50+
51+
// CHECK: %add = fadd float %0, %1, !dbg [[G7R2:!.*]]
52+
// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G7R1:!.*]]
53+
__imag ci = __imag ci + __imag ci;
54+
55+
#ifndef __cplusplus
56+
// CHECK-C: %2 = load float, ptr @f, align 4
57+
// CHECK-C: %add.r24 = fadd float %2, %ci.real22, !dbg [[G8R2:!.*]]
58+
// CHECK-C: store float %add.r24, ptr @f, align 4, !dbg [[G8R1:!.*]]
59+
f += ci;
60+
61+
// CHECK-C: %3 = load float, ptr @f, align 4
62+
// CHECK-C: %sub.r27 = fsub float %3, %ci.real25, !dbg [[G9R2:!.*]]
63+
// CHECK-C: store float %sub.r27, ptr @f, align 4, !dbg [[G9R1:!.*]]
64+
f -= ci;
65+
66+
// CHECK-C: %coerce32.real = load float, ptr %coerce32.realp, align 4, !dbg [[G10R2:!.*]]
67+
// CHECK-C: store float %coerce32.real, ptr @f, align 4, !dbg [[G10R1:!.*]]
68+
f /= ci;
69+
70+
// CHECK-C: %mul.rl = fmul float %5, %ci.real33, !dbg [[G11R2:!.*]]
71+
// CHECK-C: store float %mul.rl, ptr @f, align 4, !dbg [[G11R1:!.*]]
72+
f *= ci;
73+
#endif
74+
}
75+
76+
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
77+
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
78+
// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
79+
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
80+
// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
81+
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
82+
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
83+
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
84+
// CHECK: [[G5R2]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 2)
85+
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
86+
// CHECK: [[G6R2]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 2)
87+
// CHECK: [[G6R1]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 1)
88+
// CHECK: [[G7R2]] = !DILocation({{.*}}, atomGroup: 7, atomRank: 2)
89+
// CHECK: [[G7R1]] = !DILocation({{.*}}, atomGroup: 7, atomRank: 1)
90+
// CHECK-C: [[G8R2]] = !DILocation({{.*}}, atomGroup: 8, atomRank: 2)
91+
// CHECK-C: [[G8R1]] = !DILocation({{.*}}, atomGroup: 8, atomRank: 1)
92+
// CHECK-C: [[G9R2]] = !DILocation({{.*}}, atomGroup: 9, atomRank: 2)
93+
// CHECK-C: [[G9R1]] = !DILocation({{.*}}, atomGroup: 9, atomRank: 1)
94+
// CHECK-C: [[G10R2]] = !DILocation({{.*}}, atomGroup: 10, atomRank: 2)
95+
// CHECK-C: [[G10R1]] = !DILocation({{.*}}, atomGroup: 10, atomRank: 1)
96+
// CHECK-C: [[G11R2]] = !DILocation({{.*}}, atomGroup: 11, atomRank: 2)
97+
// CHECK-C: [[G11R1]] = !DILocation({{.*}}, atomGroup: 11, atomRank: 1)

0 commit comments

Comments
 (0)