[clang] [IRGen] Mark pointers as noalias when passing trivial types by value. (PR #131885)
Florian Hahn via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 18 12:00:25 PDT 2025
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/131885
None
>From fb1120b5a4abd716f6071ce8c7cfc81e725e9030 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 14 Mar 2025 15:40:47 +0000
Subject: [PATCH] [IRGen] Mark pointers as noalias when passing trivial types
by value.
---
clang/lib/CodeGen/CGCall.cpp | 7 ++++---
clang/test/CodeGen/AArch64/byval-temp.c | 8 ++++----
clang/test/CodeGen/atomic-arm64.c | 2 +-
clang/test/CodeGen/attr-noundef.cpp | 2 +-
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7aa77e55dbfcc..434b821ad864a 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -2797,9 +2797,10 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
Attrs.addByValAttr(getTypes().ConvertTypeForMem(ParamType));
auto *Decl = ParamType->getAsRecordDecl();
- if (CodeGenOpts.PassByValueIsNoAlias && Decl &&
- Decl->getArgPassingRestrictions() ==
- RecordArgPassingKind::CanPassInRegs)
+ if (Decl && ((CodeGenOpts.PassByValueIsNoAlias &&
+ Decl->getArgPassingRestrictions() ==
+ RecordArgPassingKind::CanPassInRegs) ||
+ (!AI.getIndirectByVal() && Context.getTypeDeclType(Decl).isTrivialType(Context))))
// When calling the function, the pointer passed in will be the only
// reference to the underlying object. Mark it accordingly.
Attrs.addAttribute(llvm::Attribute::NoAlias);
diff --git a/clang/test/CodeGen/AArch64/byval-temp.c b/clang/test/CodeGen/AArch64/byval-temp.c
index 0ee0312b2362d..05491e8f99542 100644
--- a/clang/test/CodeGen/AArch64/byval-temp.c
+++ b/clang/test/CodeGen/AArch64/byval-temp.c
@@ -30,10 +30,10 @@ void example(void) {
// Then, memcpy `l` to the temporary stack space.
// CHECK-O0-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp]], ptr align 8 %[[l]], i64 64, i1 false)
// Finally, call using a pointer to the temporary stack space.
-// CHECK-O0-NEXT: call void @pass_large(ptr noundef %[[byvaltemp]])
+// CHECK-O0-NEXT: call void @pass_large(ptr noalias noundef %[[byvaltemp]])
// Now, do the same for the second call, using the second temporary alloca.
// CHECK-O0-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp1]], ptr align 8 %[[l]], i64 64, i1 false)
-// CHECK-O0-NEXT: call void @pass_large(ptr noundef %[[byvaltemp1]])
+// CHECK-O0-NEXT: call void @pass_large(ptr noalias noundef %[[byvaltemp1]])
// CHECK-O0-NEXT: ret void
//
// At O3, we should have lifetime markers to help the optimizer re-use the temporary allocas.
@@ -58,7 +58,7 @@ void example(void) {
// Then, memcpy `l` to the temporary stack space.
// CHECK-O3-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp]], ptr align 8 %[[l]], i64 64, i1 false)
// Finally, call using a pointer to the temporary stack space.
-// CHECK-O3-NEXT: call void @pass_large(ptr noundef %[[byvaltemp]])
+// CHECK-O3-NEXT: call void @pass_large(ptr noalias noundef %[[byvaltemp]])
//
// The lifetime of the temporary used to pass a pointer to the struct ends here.
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 64, ptr %[[byvaltemp]])
@@ -66,7 +66,7 @@ void example(void) {
// Now, do the same for the second call, using the second temporary alloca.
// CHECK-O3-NEXT: call void @llvm.lifetime.start.p0(i64 64, ptr %[[byvaltemp1]])
// CHECK-O3-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[byvaltemp1]], ptr align 8 %[[l]], i64 64, i1 false)
-// CHECK-O3-NEXT: call void @pass_large(ptr noundef %[[byvaltemp1]])
+// CHECK-O3-NEXT: call void @pass_large(ptr noalias noundef %[[byvaltemp1]])
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0(i64 64, ptr %[[byvaltemp1]])
//
// Mark the end of the lifetime of `l`.
diff --git a/clang/test/CodeGen/atomic-arm64.c b/clang/test/CodeGen/atomic-arm64.c
index d2a30a3b6e66f..6a3acf899bba6 100644
--- a/clang/test/CodeGen/atomic-arm64.c
+++ b/clang/test/CodeGen/atomic-arm64.c
@@ -57,7 +57,7 @@ void test3(pointer_pair_t pair) {
}
// CHECK-LABEL:define{{.*}} void @test4(
-// CHECK-SAME: ptr noundef [[QUAD:%.*]])
+// CHECK-SAME: ptr noalias noundef [[QUAD:%.*]])
// CHECK: [[QUAD_INDIRECT_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[QUAD_T:%.*]], align 8
// CHECK-NEXT: store ptr [[QUAD]], ptr [[QUAD_INDIRECT_ADDR]]
diff --git a/clang/test/CodeGen/attr-noundef.cpp b/clang/test/CodeGen/attr-noundef.cpp
index abdf9496bd396..5431482969fc5 100644
--- a/clang/test/CodeGen/attr-noundef.cpp
+++ b/clang/test/CodeGen/attr-noundef.cpp
@@ -35,7 +35,7 @@ struct Huge {
Huge ret_huge() { return {}; }
void pass_huge(Huge h) {}
// CHECK: [[DEF]] void @{{.*}}ret_huge{{.*}}(ptr dead_on_unwind noalias writable sret({{[^)]+}}) align 4 %
-// CHECK: [[DEF]] void @{{.*}}pass_huge{{.*}}(ptr noundef
+// CHECK: [[DEF]] void @{{.*}}pass_huge{{.*}}(ptr noalias noundef
} // namespace check_structs
//************ Passing unions by value
More information about the cfe-commits
mailing list