Skip to content

Commit a42015a

Browse files
Reland "[codegen] Store address of indirect arguments on the stack"
The commit was reverted due to a regression in debug information of an optimized code test in lldb. This has since been addressed by: 1. rGf753e5be8239: [LiveDebugValues] Allow EntryValue with OP_deref expressions 2. rG055f2f04e658: [mem2reg][debuginfo] Handle op_deref when converting dbg.declare Differential Revision: https://reviews.llvm.org/D141381 (cherry picked from commit f84d30e)
1 parent 659de1c commit a42015a

24 files changed

+278
-16
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ Non-comprehensive list of changes in this release
366366
timestamp to be used in replacement of the current date and time in
367367
the ``__DATE__``, ``__TIME__``, and ``__TIMESTAMP__`` macros. See
368368
`<https://reproducible-builds.org/docs/source-date-epoch/>`_.
369+
- Clang now saves the address of ABI-indirect function parameters on the stack,
370+
improving the debug information available in programs compiled without
371+
optimizations.
369372

370373
New Compiler Flags
371374
------------------

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4813,9 +4813,10 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
48134813

48144814
llvm::DILocalVariable *
48154815
CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
4816-
unsigned ArgNo, CGBuilderTy &Builder) {
4816+
unsigned ArgNo, CGBuilderTy &Builder,
4817+
bool UsePointerValue) {
48174818
assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
4818-
return EmitDeclare(VD, AI, ArgNo, Builder);
4819+
return EmitDeclare(VD, AI, ArgNo, Builder, UsePointerValue);
48194820
}
48204821

48214822
namespace {

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,10 +487,9 @@ class CGDebugInfo {
487487

488488
/// Emit call to \c llvm.dbg.declare for an argument variable
489489
/// declaration.
490-
llvm::DILocalVariable *EmitDeclareOfArgVariable(const VarDecl *Decl,
491-
llvm::Value *AI,
492-
unsigned ArgNo,
493-
CGBuilderTy &Builder);
490+
llvm::DILocalVariable *
491+
EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, unsigned ArgNo,
492+
CGBuilderTy &Builder, bool UsePointerValue = false);
494493

495494
/// Emit call to \c llvm.dbg.declare for the block-literal argument
496495
/// to a block invocation function.

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2481,6 +2481,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
24812481
Address AllocaPtr = Address::invalid();
24822482
bool DoStore = false;
24832483
bool IsScalar = hasScalarEvaluationKind(Ty);
2484+
bool UseIndirectDebugAddress = false;
2485+
24842486
// If we already have a pointer to the argument, reuse the input pointer.
24852487
if (Arg.isIndirect()) {
24862488
// If we have a prettier pointer type at this point, bitcast to that.
@@ -2492,6 +2494,19 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
24922494
auto AllocaAS = CGM.getASTAllocaAddressSpace();
24932495
auto *V = DeclPtr.getPointer();
24942496
AllocaPtr = DeclPtr;
2497+
2498+
// For truly ABI indirect arguments -- those that are not `byval` -- store
2499+
// the address of the argument on the stack to preserve debug information.
2500+
ABIArgInfo ArgInfo = CurFnInfo->arguments()[ArgNo - 1].info;
2501+
if (ArgInfo.isIndirect())
2502+
UseIndirectDebugAddress = !ArgInfo.getIndirectByVal();
2503+
if (UseIndirectDebugAddress) {
2504+
auto PtrTy = getContext().getPointerType(Ty);
2505+
AllocaPtr = CreateMemTemp(PtrTy, getContext().getTypeAlignInChars(PtrTy),
2506+
D.getName() + ".indirect_addr");
2507+
EmitStoreOfScalar(V, AllocaPtr, /* Volatile */ false, PtrTy);
2508+
}
2509+
24952510
auto SrcLangAS = getLangOpts().OpenCL ? LangAS::opencl_private : AllocaAS;
24962511
auto DestLangAS =
24972512
getLangOpts().OpenCL ? LangAS::opencl_private : LangAS::Default;
@@ -2608,7 +2623,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
26082623
if (CGM.getCodeGenOpts().hasReducedDebugInfo() && !CurFuncIsThunk &&
26092624
!NoDebugInfo) {
26102625
llvm::DILocalVariable *DILocalVar = DI->EmitDeclareOfArgVariable(
2611-
&D, AllocaPtr.getPointer(), ArgNo, Builder);
2626+
&D, AllocaPtr.getPointer(), ArgNo, Builder, UseIndirectDebugAddress);
26122627
if (const auto *Var = dyn_cast_or_null<ParmVarDecl>(&D))
26132628
DI->getParamDbgMappings().insert({Var, DILocalVar});
26142629
}

clang/test/CodeGen/aarch64-ls64.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,13 @@ EXTERN_C void test_ld64b(void)
100100
// CHECK-C-LABEL: @test_st64b(
101101
// CHECK-C-NEXT: entry:
102102
// CHECK-C-NEXT: [[__ADDR_ADDR_I:%.*]] = alloca i8*, align 8
103+
// CHECK-C-NEXT: [[VALUE_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
103104
// CHECK-C-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_DATA512_T:%.*]], align 8
104105
// CHECK-C-NEXT: [[TMP0:%.*]] = load i8*, i8** @addr, align 8
105106
// CHECK-C-NEXT: [[TMP1:%.*]] = bitcast %struct.data512_t* [[BYVAL_TEMP]] to i8*
106107
// CHECK-C-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 bitcast (%struct.data512_t* @val to i8*), i64 64, i1 false)
107108
// CHECK-C-NEXT: store i8* [[TMP0]], i8** [[__ADDR_ADDR_I]], align 8
109+
// CHECK-C-NEXT: store ptr [[BYVAL_TEMP]], ptr [[VALUE_INDIRECT_ADDR]], align 8
108110
// CHECK-C-NEXT: [[TMP2:%.*]] = load i8*, i8** [[__ADDR_ADDR_I]], align 8
109111
// CHECK-C-NEXT: [[VAL_I:%.*]] = getelementptr inbounds [[STRUCT_DATA512_T]], %struct.data512_t* [[BYVAL_TEMP]], i32 0, i32 0
110112
// CHECK-C-NEXT: [[ARRAYDECAY_I:%.*]] = getelementptr inbounds [8 x i64], [8 x i64]* [[VAL_I]], i64 0, i64 0
@@ -129,11 +131,13 @@ EXTERN_C void test_ld64b(void)
129131
// CHECK-CXX-LABEL: @test_st64b(
130132
// CHECK-CXX-NEXT: entry:
131133
// CHECK-CXX-NEXT: [[__ADDR_ADDR_I:%.*]] = alloca i8*, align 8
134+
// CHECK-CXX-NEXT: [[VALUE_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
132135
// CHECK-CXX-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_DATA512_T:%.*]], align 8
133136
// CHECK-CXX-NEXT: [[TMP0:%.*]] = load i8*, i8** @addr, align 8
134137
// CHECK-CXX-NEXT: [[TMP1:%.*]] = bitcast %struct.data512_t* [[AGG_TMP]] to i8*
135138
// CHECK-CXX-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 bitcast (%struct.data512_t* @val to i8*), i64 64, i1 false)
136139
// CHECK-CXX-NEXT: store i8* [[TMP0]], i8** [[__ADDR_ADDR_I]], align 8
140+
// CHECK-CXX-NEXT: store ptr [[AGG_TMP]], ptr [[VALUE_INDIRECT_ADDR]], align 8
137141
// CHECK-CXX-NEXT: [[TMP2:%.*]] = load i8*, i8** [[__ADDR_ADDR_I]], align 8
138142
// CHECK-CXX-NEXT: [[VAL_I:%.*]] = getelementptr inbounds [[STRUCT_DATA512_T]], %struct.data512_t* [[AGG_TMP]], i32 0, i32 0
139143
// CHECK-CXX-NEXT: [[ARRAYDECAY_I:%.*]] = getelementptr inbounds [8 x i64], [8 x i64]* [[VAL_I]], i64 0, i64 0
@@ -163,11 +167,13 @@ EXTERN_C void test_st64b(void)
163167
// CHECK-C-LABEL: @test_st64bv(
164168
// CHECK-C-NEXT: entry:
165169
// CHECK-C-NEXT: [[__ADDR_ADDR_I:%.*]] = alloca i8*, align 8
170+
// CHECK-C-NEXT: [[VALUE_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
166171
// CHECK-C-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_DATA512_T:%.*]], align 8
167172
// CHECK-C-NEXT: [[TMP0:%.*]] = load i8*, i8** @addr, align 8
168173
// CHECK-C-NEXT: [[TMP1:%.*]] = bitcast %struct.data512_t* [[BYVAL_TEMP]] to i8*
169174
// CHECK-C-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 bitcast (%struct.data512_t* @val to i8*), i64 64, i1 false)
170175
// CHECK-C-NEXT: store i8* [[TMP0]], i8** [[__ADDR_ADDR_I]], align 8
176+
// CHECK-C-NEXT: store ptr [[BYVAL_TEMP]], ptr [[VALUE_INDIRECT_ADDR]], align 8
171177
// CHECK-C-NEXT: [[TMP2:%.*]] = load i8*, i8** [[__ADDR_ADDR_I]], align 8
172178
// CHECK-C-NEXT: [[VAL_I:%.*]] = getelementptr inbounds [[STRUCT_DATA512_T]], %struct.data512_t* [[BYVAL_TEMP]], i32 0, i32 0
173179
// CHECK-C-NEXT: [[ARRAYDECAY_I:%.*]] = getelementptr inbounds [8 x i64], [8 x i64]* [[VAL_I]], i64 0, i64 0
@@ -193,11 +199,13 @@ EXTERN_C void test_st64b(void)
193199
// CHECK-CXX-LABEL: @test_st64bv(
194200
// CHECK-CXX-NEXT: entry:
195201
// CHECK-CXX-NEXT: [[__ADDR_ADDR_I:%.*]] = alloca i8*, align 8
202+
// CHECK-CXX-NEXT: [[VALUE_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
196203
// CHECK-CXX-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_DATA512_T:%.*]], align 8
197204
// CHECK-CXX-NEXT: [[TMP0:%.*]] = load i8*, i8** @addr, align 8
198205
// CHECK-CXX-NEXT: [[TMP1:%.*]] = bitcast %struct.data512_t* [[AGG_TMP]] to i8*
199206
// CHECK-CXX-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 bitcast (%struct.data512_t* @val to i8*), i64 64, i1 false)
200207
// CHECK-CXX-NEXT: store i8* [[TMP0]], i8** [[__ADDR_ADDR_I]], align 8
208+
// CHECK-CXX-NEXT: store ptr [[AGG_TMP]], ptr [[VALUE_INDIRECT_ADDR]], align 8
201209
// CHECK-CXX-NEXT: [[TMP2:%.*]] = load i8*, i8** [[__ADDR_ADDR_I]], align 8
202210
// CHECK-CXX-NEXT: [[VAL_I:%.*]] = getelementptr inbounds [[STRUCT_DATA512_T]], %struct.data512_t* [[AGG_TMP]], i32 0, i32 0
203211
// CHECK-CXX-NEXT: [[ARRAYDECAY_I:%.*]] = getelementptr inbounds [8 x i64], [8 x i64]* [[VAL_I]], i64 0, i64 0
@@ -228,11 +236,13 @@ EXTERN_C void test_st64bv(void)
228236
// CHECK-C-LABEL: @test_st64bv0(
229237
// CHECK-C-NEXT: entry:
230238
// CHECK-C-NEXT: [[__ADDR_ADDR_I:%.*]] = alloca i8*, align 8
239+
// CHECK-C-NEXT: [[VALUE_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
231240
// CHECK-C-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_DATA512_T:%.*]], align 8
232241
// CHECK-C-NEXT: [[TMP0:%.*]] = load i8*, i8** @addr, align 8
233242
// CHECK-C-NEXT: [[TMP1:%.*]] = bitcast %struct.data512_t* [[BYVAL_TEMP]] to i8*
234243
// CHECK-C-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 bitcast (%struct.data512_t* @val to i8*), i64 64, i1 false)
235244
// CHECK-C-NEXT: store i8* [[TMP0]], i8** [[__ADDR_ADDR_I]], align 8
245+
// CHECK-C-NEXT: store ptr [[BYVAL_TEMP]], ptr [[VALUE_INDIRECT_ADDR]], align 8
236246
// CHECK-C-NEXT: [[TMP2:%.*]] = load i8*, i8** [[__ADDR_ADDR_I]], align 8
237247
// CHECK-C-NEXT: [[VAL_I:%.*]] = getelementptr inbounds [[STRUCT_DATA512_T]], %struct.data512_t* [[BYVAL_TEMP]], i32 0, i32 0
238248
// CHECK-C-NEXT: [[ARRAYDECAY_I:%.*]] = getelementptr inbounds [8 x i64], [8 x i64]* [[VAL_I]], i64 0, i64 0
@@ -258,11 +268,13 @@ EXTERN_C void test_st64bv(void)
258268
// CHECK-CXX-LABEL: @test_st64bv0(
259269
// CHECK-CXX-NEXT: entry:
260270
// CHECK-CXX-NEXT: [[__ADDR_ADDR_I:%.*]] = alloca i8*, align 8
271+
// CHECK-CXX-NEXT: [[VALUE_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
261272
// CHECK-CXX-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_DATA512_T:%.*]], align 8
262273
// CHECK-CXX-NEXT: [[TMP0:%.*]] = load i8*, i8** @addr, align 8
263274
// CHECK-CXX-NEXT: [[TMP1:%.*]] = bitcast %struct.data512_t* [[AGG_TMP]] to i8*
264275
// CHECK-CXX-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 [[TMP1]], i8* align 8 bitcast (%struct.data512_t* @val to i8*), i64 64, i1 false)
265276
// CHECK-CXX-NEXT: store i8* [[TMP0]], i8** [[__ADDR_ADDR_I]], align 8
277+
// CHECK-CXX-NEXT: store ptr [[AGG_TMP]], ptr [[VALUE_INDIRECT_ADDR]], align 8
266278
// CHECK-CXX-NEXT: [[TMP2:%.*]] = load i8*, i8** [[__ADDR_ADDR_I]], align 8
267279
// CHECK-CXX-NEXT: [[VAL_I:%.*]] = getelementptr inbounds [[STRUCT_DATA512_T]], %struct.data512_t* [[AGG_TMP]], i32 0, i32 0
268280
// CHECK-CXX-NEXT: [[ARRAYDECAY_I:%.*]] = getelementptr inbounds [8 x i64], [8 x i64]* [[VAL_I]], i64 0, i64 0

clang/test/CodeGen/atomic-arm64.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ void test3(pointer_pair_t pair) {
5959
}
6060

6161
// CHECK-LABEL:define{{.*}} void @test4(
62-
// CHECK: [[TEMP:%.*]] = alloca [[QUAD_T:%.*]], align 8
62+
// CHECK-SAME: ptr noundef [[QUAD:%.*]])
63+
// CHECK: [[QUAD_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
64+
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[QUAD_T:%.*]], align 8
65+
// CHECK-NEXT: store ptr [[QUAD]], ptr [[QUAD_INDIRECT_ADDR]]
6366
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TEMP]], ptr align 8 {{%.*}}, i64 32, i1 false)
6467
// CHECK-NEXT: call void @__atomic_store(i64 noundef 32, ptr noundef @a_pointer_quad, ptr noundef [[TEMP]], i32 noundef 5)
6568
void test4(pointer_quad_t quad) {

clang/test/CodeGenCXX/amdgcn-func-arg.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ void func_with_ref_arg(A &a);
1919
void func_with_ref_arg(B &b);
2020

2121
// CHECK-LABEL: @_Z22func_with_indirect_arg1A(
22+
// CHECK-SAME: ptr addrspace(5) noundef [[ARG:%.*]])
2223
// CHECK-NEXT: entry:
24+
// CHECK-NEXT: [[INDIRECT_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
2325
// CHECK-NEXT: [[P:%.*]] = alloca %class.A*, align 8, addrspace(5)
26+
// CHECK-NEXT: [[INDIRECT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[INDIRECT_ADDR]] to ptr
2427
// CHECK-NEXT: [[P_ASCAST:%.*]] = addrspacecast %class.A* addrspace(5)* [[P]] to %class.A**
28+
// CHECK-NEXT: store ptr addrspace(5) [[ARG]], ptr [[INDIRECT_ADDR_ASCAST]]
2529
// CHECK-NEXT: [[A_ASCAST:%.*]] = addrspacecast [[CLASS_A:%.*]] addrspace(5)* [[A:%.*]] to %class.A*
2630
// CHECK-NEXT: store %class.A* [[A_ASCAST]], %class.A** [[P_ASCAST]], align 8
2731
// CHECK-NEXT: ret void

clang/test/CodeGenCXX/debug-info.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44
// CHECK: @_ZN6pr96081xE ={{.*}} global ptr null, align 8, !dbg [[X:![0-9]+]]
55

66
// CHECK: define{{.*}} void @_ZN7pr147634funcENS_3fooE
7-
// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[F:[0-9]+]], metadata !DIExpression())
7+
// CHECK-SAME: ptr noundef [[param:%.*]])
8+
// CHECK-NEXT: entry:
9+
// CHECK-NEXT: alloca ptr, align 8
10+
// CHECK-NEXT: [[param_addr_storage:%.*]] = alloca ptr, align 8
11+
// CHECK-NEXT: store
12+
// CHECK-NEXT: store ptr [[param]], ptr [[param_addr_storage]], align 8
13+
// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[param_addr_storage]], metadata ![[F:[0-9]+]], metadata !DIExpression(DW_OP_deref))
814

915
// !llvm.dbg.cu pulls in globals and their types first.
1016
// CHECK-NOT: !DIGlobalVariable(name: "c"

clang/test/CodeGenCXX/derived-to-base-conv.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ void test0_helper(A);
3232
void test0(X x) {
3333
test0_helper(x);
3434
// CHECK-LABEL: define{{.*}} void @_Z5test01X(
35-
// CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align
35+
// CHECK-SAME: ptr noundef [[ARG:%.*]])
36+
// CHECK: [[ARG_ADDR:%.*]] = alloca ptr
37+
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A:%.*]], align
38+
// CHECK-NEXT: store ptr [[ARG]], ptr [[ARG_ADDR]]
3639
// CHECK-NEXT: [[T0:%.*]] = call noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @_ZN1XcvR1BEv(
3740
// CHECK-NEXT: call void @_ZN1AC1ERKS_(ptr {{[^,]*}} [[TMP]], ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[T0]])
3841
// CHECK-NEXT: call void @_Z12test0_helper1A(ptr noundef [[TMP]])

clang/test/CodeGenCoroutines/coro-params-exp-namespace.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ void consume(int, int, int) noexcept;
6464
// TODO: Add support for CopyOnly params
6565
// CHECK: define{{.*}} void @_Z1fi8MoveOnly11MoveAndCopy(i32 noundef %val, %struct.MoveOnly* noundef %[[MoParam:.+]], %struct.MoveAndCopy* noundef %[[McParam:.+]]) #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*
6666
void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
67-
// CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly
68-
// CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy
67+
// CHECK: %[[MoCopy:.+]] = alloca %struct.MoveOnly,
68+
// CHECK: %[[McCopy:.+]] = alloca %struct.MoveAndCopy,
6969
// CHECK: store i32 %val, i32* %[[ValAddr:.+]]
7070

7171
// CHECK: call i8* @llvm.coro.begin(
@@ -110,7 +110,7 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam) {
110110
// CHECK-LABEL: void @_Z16dependent_paramsI1A1BEvT_T0_S3_(%struct.A* noundef %x, %struct.B* noundef %0, %struct.B* noundef %y)
111111
template <typename T, typename U>
112112
void dependent_params(T x, U, U y) {
113-
// CHECK: %[[x_copy:.+]] = alloca %struct.A
113+
// CHECK: %[[x_copy:.+]] = alloca %struct.A,
114114
// CHECK-NEXT: %[[unnamed_copy:.+]] = alloca %struct.B
115115
// CHECK-NEXT: %[[y_copy:.+]] = alloca %struct.B
116116

0 commit comments

Comments
 (0)