Skip to content

Commit a53c2f9

Browse files
[clang][CodeGen] Set dead_on_return on indirect ptr arguments
Let Clang emit `dead_on_return` attribute on indirect pointer arguments, namely, large aggregates that the ABI mandates be passed by value, but lowered to an indirect argument. Writes to such arguments are not observable by the caller after the callee returns. This should desirably enable further MemCpyOpt/DSE optimizations. Previous discussion: https://discourse.llvm.org/t/rfc-add-dead-on-return-attribute/86871.
1 parent 9544bb5 commit a53c2f9

File tree

107 files changed

+1222
-1217
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+1222
-1217
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2852,8 +2852,12 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
28522852
if (AI.getInReg())
28532853
Attrs.addAttribute(llvm::Attribute::InReg);
28542854

2855+
// Depending on the ABI, this is either a byval or a dead_on_return
2856+
// argument.
28552857
if (AI.getIndirectByVal())
28562858
Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType));
2859+
else
2860+
Attrs.addAttribute(llvm::Attribute::DeadOnReturn);
28572861

28582862
auto *Decl = ParamType->getAsRecordDecl();
28592863
if (CodeGenOpts.PassByValueIsNoAlias && Decl &&

clang/test/CodeGen/64bit-swiftcall.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ TEST(struct_big_1)
239239
// CHECK-LABEL: define {{.*}} void @return_struct_big_1(ptr dead_on_unwind noalias writable sret
240240

241241
// Should not be byval.
242-
// CHECK-LABEL: define {{.*}} void @take_struct_big_1(ptr{{( %.*)?}})
242+
// CHECK-LABEL: define {{.*}} void @take_struct_big_1(ptr dead_on_return{{( %.*)?}})
243243

244244
/*****************************************************************************/
245245
/********************************* TYPE MERGING ******************************/

clang/test/CodeGen/AArch64/byval-temp.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ void example(void) {
3030
// Then, memcpy `l` to the temporary stack space.
3131
// CHECK-O0-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp]], ptr align 8 %[[l]], i64 64, i1 false)
3232
// Finally, call using a pointer to the temporary stack space.
33-
// CHECK-O0-NEXT: call void @pass_large(ptr noundef %[[byvaltemp]])
33+
// CHECK-O0-NEXT: call void @pass_large(ptr dead_on_return noundef %[[byvaltemp]])
3434
// Now, do the same for the second call, using the second temporary alloca.
3535
// CHECK-O0-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp1]], ptr align 8 %[[l]], i64 64, i1 false)
36-
// CHECK-O0-NEXT: call void @pass_large(ptr noundef %[[byvaltemp1]])
36+
// CHECK-O0-NEXT: call void @pass_large(ptr dead_on_return noundef %[[byvaltemp1]])
3737
// CHECK-O0-NEXT: ret void
3838
//
3939
// At O3, we should have lifetime markers to help the optimizer re-use the temporary allocas.
@@ -58,15 +58,15 @@ void example(void) {
5858
// Then, memcpy `l` to the temporary stack space.
5959
// CHECK-O3-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp]], ptr align 8 %[[l]], i64 64, i1 false)
6060
// Finally, call using a pointer to the temporary stack space.
61-
// CHECK-O3-NEXT: call void @pass_large(ptr noundef %[[byvaltemp]])
61+
// CHECK-O3-NEXT: call void @pass_large(ptr dead_on_return noundef %[[byvaltemp]])
6262
//
6363
// The lifetime of the temporary used to pass a pointer to the struct ends here.
6464
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 64, ptr %[[byvaltemp]])
6565
//
6666
// Now, do the same for the second call, using the second temporary alloca.
6767
// CHECK-O3-NEXT: call void @llvm.lifetime.start.p0(i64 64, ptr %[[byvaltemp1]])
6868
// CHECK-O3-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp1]], ptr align 8 %[[l]], i64 64, i1 false)
69-
// CHECK-O3-NEXT: call void @pass_large(ptr noundef %[[byvaltemp1]])
69+
// CHECK-O3-NEXT: call void @pass_large(ptr dead_on_return noundef %[[byvaltemp1]])
7070
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 64, ptr %[[byvaltemp1]])
7171
//
7272
// Mark the end of the lifetime of `l`.
@@ -88,12 +88,12 @@ void example_BitInt(void) {
8888
// CHECK-O0-NEXT: [[LOADEDV:%.*]] = trunc i256 [[TMP0]] to i129
8989
// CHECK-O0-NEXT: [[STOREDV:%.*]] = sext i129 [[LOADEDV]] to i256
9090
// CHECK-O0-NEXT: store i256 [[STOREDV]], ptr [[INDIRECT_ARG_TEMP]], align 16
91-
// CHECK-O0-NEXT: call void @pass_large_BitInt(ptr noundef [[INDIRECT_ARG_TEMP]])
91+
// CHECK-O0-NEXT: call void @pass_large_BitInt(ptr dead_on_return noundef [[INDIRECT_ARG_TEMP]])
9292
// CHECK-O0-NEXT: [[TMP1:%.*]] = load i256, ptr [[L]], align 16
9393
// CHECK-O0-NEXT: [[LOADEDV1:%.*]] = trunc i256 [[TMP1]] to i129
9494
// CHECK-O0-NEXT: [[STOREDV1:%.*]] = sext i129 [[LOADEDV1]] to i256
9595
// CHECK-O0-NEXT: store i256 [[STOREDV1]], ptr [[INDIRECT_ARG_TEMP1]], align 16
96-
// CHECK-O0-NEXT: call void @pass_large_BitInt(ptr noundef [[INDIRECT_ARG_TEMP1]])
96+
// CHECK-O0-NEXT: call void @pass_large_BitInt(ptr dead_on_return noundef [[INDIRECT_ARG_TEMP1]])
9797
// CHECK-O0-NEXT: ret void
9898
//
9999
// CHECK-O3-LABEL: define dso_local void @example_BitInt(
@@ -108,13 +108,13 @@ void example_BitInt(void) {
108108
// CHECK-O3-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr [[INDIRECT_ARG_TEMP]])
109109
// CHECK-O3-NEXT: [[STOREDV:%.*]] = sext i129 [[LOADEDV]] to i256
110110
// CHECK-O3-NEXT: store i256 [[STOREDV]], ptr [[INDIRECT_ARG_TEMP]], align 16, !tbaa [[TBAA6]]
111-
// CHECK-O3-NEXT: call void @pass_large_BitInt(ptr noundef [[INDIRECT_ARG_TEMP]])
111+
// CHECK-O3-NEXT: call void @pass_large_BitInt(ptr dead_on_return noundef [[INDIRECT_ARG_TEMP]])
112112
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr [[INDIRECT_ARG_TEMP]])
113113
// CHECK-O3-NEXT: [[TMP1:%.*]] = load i256, ptr [[L]], align 16, !tbaa [[TBAA6]]
114114
// CHECK-O3-NEXT: [[LOADEDV1:%.*]] = trunc i256 [[TMP1]] to i129
115115
// CHECK-O3-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr [[INDIRECT_ARG_TEMP1]])
116116
// CHECK-O3-NEXT: [[STOREDV1:%.*]] = sext i129 [[LOADEDV1]] to i256
117117
// CHECK-O3-NEXT: store i256 [[STOREDV1]], ptr [[INDIRECT_ARG_TEMP1]], align 16, !tbaa [[TBAA6]]
118-
// CHECK-O3-NEXT: call void @pass_large_BitInt(ptr noundef [[INDIRECT_ARG_TEMP1]])
118+
// CHECK-O3-NEXT: call void @pass_large_BitInt(ptr dead_on_return noundef [[INDIRECT_ARG_TEMP1]])
119119
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr [[INDIRECT_ARG_TEMP1]])
120120
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr [[L]])

clang/test/CodeGen/AArch64/pure-scalable-args-empty-union.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ void f0(S0 *p) {
1919
use0(*p);
2020
}
2121
// CHECK-C: declare void @use0(<vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>)
22-
// CHECK-CXX: declare void @use0(ptr noundef)
22+
// CHECK-CXX: declare void @use0(ptr dead_on_return noundef)
2323

2424
#ifdef __cplusplus
2525

0 commit comments

Comments
 (0)