[clang] [CIR] Add noalias on malloc-like function returns (PR #221817)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 7 13:04:16 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: David Rivera (RiverDave)
<details>
<summary>Changes</summary>
## Summary
- Stamp `llvm.noalias` on function returns when the callee has `RestrictAttr` (`__attribute__((malloc))` / `__declspec(restrict)`) and no deallocator.
- Matches classic codegen in `CGCall.cpp`: return `noalias` on both `define` and `call`, and skip `malloc(dealloc)`.
- Extends `restrict-noalias.c` with a malloc call, a malloc definition, and a `malloc(dealloc)` negative.
## Test plan
- [x] `llvm-lit clang/test/CIR/CodeGen/restrict-noalias.c`
- [ ] Pre-merge Clang CIR checks
Made with [Cursor](https://cursor.com)
---
Full diff: https://github.com/llvm/llvm-project/pull/221817.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+9-3)
- (modified) clang/test/CIR/CodeGen/restrict-noalias.c (+59-3)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 3a4b7cecf2e08..db17709050018 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -403,9 +403,6 @@ void CIRGenModule::constructAttributeList(
attrs.set(cir::CIRDialect::getSideEffectAttrName(),
cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
- // TODO(cir): Add noalias to returns for malloc-like functions
- // (__attribute__((malloc)) / __declspec(restrict)).
-
if (targetDecl->hasAttr<ReturnsNonNullAttr>() &&
!codeGenOpts.NullPointerIsValid)
retAttrs.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(),
@@ -665,6 +662,15 @@ void CIRGenModule::constructFunctionReturnAttributes(
getNaturalPointeeTypeAlignment(retTy).getQuantity()));
}
}
+
+ // __attribute__((malloc)) / __declspec(restrict) -> noalias on the return
+ // value. Classic skips the attribute when a deallocator is specified
+ // (malloc(dealloc) / malloc(dealloc, N)).
+ if (const auto *restrictAttr =
+ targetDecl ? targetDecl->getAttr<RestrictAttr>() : nullptr;
+ restrictAttr && restrictAttr->getDeallocator() == nullptr)
+ retAttrs.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(),
+ mlir::UnitAttr::get(&getMLIRContext()));
}
void CIRGenModule::constructFunctionArgumentAttributes(
diff --git a/clang/test/CIR/CodeGen/restrict-noalias.c b/clang/test/CIR/CodeGen/restrict-noalias.c
index b69de97b07864..2ad1dc391be9c 100644
--- a/clang/test/CIR/CodeGen/restrict-noalias.c
+++ b/clang/test/CIR/CodeGen/restrict-noalias.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-ignored-attributes -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-ignored-attributes -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-ignored-attributes -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
void user_func(int *__restrict p);
@@ -36,3 +36,59 @@ void test_builtin(const char *__restrict fmt) {
// OGCG: define dso_local void @test_builtin(ptr noalias noundef %{{.*}})
// OGCG: call i32 (ptr, ...) @printf(ptr noundef %{{.*}})
+
+__attribute__((malloc)) void *my_malloc(unsigned long n);
+void *test_ret(unsigned long n) { return my_malloc(n); }
+
+// CIR: cir.func {{.*}} @test_ret(%{{.*}}: !u64i {llvm.noundef}
+// CIR: cir.call @my_malloc(%{{.*}}) : (!u64i {llvm.noundef}) -> (!cir.ptr<!void> {llvm.noalias{{.*}}})
+// CIR: cir.func {{.*}} @my_malloc(!u64i {llvm.noundef}) -> (!cir.ptr<!void> {llvm.noalias{{.*}}})
+
+// LLVM: define dso_local {{.*}}ptr @test_ret
+// LLVM: call noalias {{.*}}ptr @my_malloc
+// LLVM: declare noalias {{.*}}ptr @my_malloc
+
+// OGCG: define dso_local {{.*}}ptr @test_ret
+// OGCG: call noalias {{.*}}ptr @my_malloc
+// OGCG: declare noalias {{.*}}ptr @my_malloc
+
+__attribute__((malloc)) void *my_malloc_def(unsigned long n) { return 0; }
+
+// CIR: cir.func {{.*}} @my_malloc_def(%{{.*}}: !u64i {llvm.noundef}
+// CIR-SAME: -> (!cir.ptr<!void> {llvm.noalias{{.*}}})
+
+// LLVM: define dso_local noalias {{.*}}ptr @my_malloc_def
+// OGCG: define dso_local noalias {{.*}}ptr @my_malloc_def
+
+int *Mem;
+void dealloc(int *);
+__attribute__((malloc(dealloc))) int *malloc_with_dealloc(void) { return Mem; }
+__attribute__((malloc(dealloc, 1))) int *malloc_with_dealloc_idx(void) {
+ return Mem;
+}
+
+int *test_malloc_with_dealloc(void) { return malloc_with_dealloc(); }
+
+// CIR-LABEL: cir.func {{.*}} @malloc_with_dealloc
+// CIR-NOT: llvm.noalias
+// CIR-LABEL: cir.func {{.*}} @malloc_with_dealloc_idx
+// CIR-NOT: llvm.noalias
+// CIR-LABEL: cir.func {{.*}} @test_malloc_with_dealloc
+// CIR: cir.call @malloc_with_dealloc() : () -> !cir.ptr<!s32i>
+// CIR-NOT: llvm.noalias
+
+// LLVM: define dso_local {{.*}}ptr @malloc_with_dealloc()
+// LLVM-NOT: noalias
+// LLVM: define dso_local {{.*}}ptr @malloc_with_dealloc_idx()
+// LLVM-NOT: noalias
+// LLVM: define dso_local {{.*}}ptr @test_malloc_with_dealloc()
+// LLVM: call {{.*}}ptr @malloc_with_dealloc()
+// LLVM-NOT: call noalias
+
+// OGCG: define dso_local {{.*}}ptr @malloc_with_dealloc()
+// OGCG-NOT: noalias
+// OGCG: define dso_local {{.*}}ptr @malloc_with_dealloc_idx()
+// OGCG-NOT: noalias
+// OGCG: define dso_local {{.*}}ptr @test_malloc_with_dealloc()
+// OGCG: call {{.*}}ptr @malloc_with_dealloc()
+// OGCG-NOT: call noalias
``````````
</details>
https://github.com/llvm/llvm-project/pull/221817
More information about the cfe-commits
mailing list