https://github.com/tommat01 updated https://github.com/llvm/llvm-project/pull/218681
>From cdc20f801857b11d0a45bfeda1ab00933caf5431 Mon Sep 17 00:00:00 2001 From: Tomas Matheson <[email protected]> Date: Mon, 24 Aug 2026 11:07:35 +0100 Subject: [PATCH] [Transforms] Infer attributes for posix_memalign posix_memalign writes the allocated pointer through its first argument but does not retain the address of that output slot. Model the contract with noundef, nounwind, willreturn, captures(none), writeonly, and arg/inaccessible/errno memory effects. The missing capture information caused Attributor to treat an alloca passed to posix_memalign as escaped, preventing noalias inference at a later callback call site. Test both the inferred declaration attributes and the OpenMP callback-lifetime case that exposed the missing model. --- llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 8 +++ .../Transforms/InferFunctionAttrs/annotate.ll | 3 +- .../OpenMP/callback-capture-posix-memalign.ll | 63 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/OpenMP/callback-capture-posix-memalign.ll diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index 0afcc9df40070..fd5ebc1c7d37a 100644 --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -534,6 +534,14 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F, Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); break; + case LibFunc_posix_memalign: + Changed |= setRetAndArgsNoUndef(F); + Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); + Changed |= setOnlyAccessesInaccessibleMemOrArgMemOrErrnoMem(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyWritesMemory(F, 0); + break; case LibFunc_aligned_alloc: Changed |= setAlignedAllocParam(F, 0); Changed |= setAllocSize(F, 1, std::nullopt); diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll index 44b76640cf97f..d0c29faee8257 100644 --- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll +++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll @@ -817,7 +817,7 @@ declare void @perror(ptr) ; CHECK: declare noalias noundef ptr @popen(ptr noundef readonly captures(none), ptr noundef readonly captures(none)) [[NOFREE_NOUNWIND]] declare ptr @popen(ptr, ptr) -; CHECK: declare i32 @posix_memalign(ptr, i64, i64) [[NOFREE]] +; CHECK: declare noundef i32 @posix_memalign(ptr noundef writeonly captures(none), i64 noundef, i64 noundef) [[INACCESSIBLEMEMORARGMEMORERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]] declare i32 @posix_memalign(ptr, i64, i64) ; CHECK: declare double @pow(double, double) [[ERRNOMEMONLY_NOFREE_NOSYNC_NOUNWIND_WILLRETURN]] @@ -1250,6 +1250,7 @@ declare void @memset_pattern16(ptr, ptr, i64) ; CHECK-DAG: attributes [[INACCESSIBLEMEMORARGMEMORERRNOMEMONLY_NOUNWIND_WILLRETURN_ALLOCKIND_REALLOC_ALLOCSIZE1_FAMILY_MALLOC]] = { mustprogress nounwind willreturn allockind("realloc") allocsize(1) memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: write) "alloc-family"="malloc" } ; CHECK-DAG: attributes [[INACCESSIBLEMEMORARGMEMORERRNOMEMONLY_NOUNWIND_WILLRETURN_ALLOCKIND_REALLOC_ALLOCSIZE12_FAMILY_MALLOC]] = { mustprogress nounwind willreturn allockind("realloc") allocsize(1,2) memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: write) "alloc-family"="malloc" } ; CHECK-DAG: attributes [[INACCESSIBLEMEMORARGMEMORERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN_FAMILY_MALLOC]] = { mustprogress nofree nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: write) "alloc-family"="malloc" } +; CHECK-DAG: attributes [[INACCESSIBLEMEMORARGMEMORERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN]] = { mustprogress nofree nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite, errnomem: write) } ; CHECK-DAG: attributes [[NOFREE_COLD_NORETURN_NOUNWIND]] = { cold nofree noreturn nounwind } ; CHECK-DAG: attributes [[NOFREE_COLD_NORETURN]] = { cold nofree noreturn } ; CHECK-DAG: attributes [[COLD_NORETURN]] = { cold noreturn } diff --git a/llvm/test/Transforms/OpenMP/callback-capture-posix-memalign.ll b/llvm/test/Transforms/OpenMP/callback-capture-posix-memalign.ll new file mode 100644 index 0000000000000..710852959b302 --- /dev/null +++ b/llvm/test/Transforms/OpenMP/callback-capture-posix-memalign.ll @@ -0,0 +1,63 @@ +; RUN: opt -passes='inferattrs,openmp-opt,function(loop-mssa(licm))' -S < %s | FileCheck %s + +target triple = "aarch64-unknown-linux-gnu" + +; posix_memalign writes through its output slot but does not capture the slot. +; That earlier use must not prevent the callback capture from becoming noalias +; or the load from being hoisted across an unknown call. +; CHECK: call i32 @posix_memalign(ptr writeonly captures(none) %slot, i64 64, i64 %size) +; CHECK-LABEL: define internal void @outlined( +; CHECK-SAME: ptr noalias readonly align 8 captures(none) dereferenceable(8) %capture) +; CHECK: call void @opaque() +; CHECK-NEXT: [[VALUES:%.*]] = load ptr, ptr %capture, align 8 +; CHECK: loop: +; CHECK-NOT: load ptr, ptr %capture +; CHECK: if.then: +; CHECK-NEXT: [[ELEMENT:%.*]] = getelementptr double, ptr [[VALUES]], i64 [[I:%.*]] + +define i32 @run(i64 %size) { +entry: + %slot = alloca ptr, align 8 + %status = call i32 @posix_memalign(ptr %slot, i64 64, i64 %size) + call void (ptr, i32, ptr, ...) @__kmpc_fork_call( + ptr null, i32 1, ptr @outlined, ptr %slot) + ret i32 %status +} + +define internal void @outlined( + ptr %global_tid, ptr %bound_tid, + ptr align 8 dereferenceable(8) %capture) { +entry: + call void @opaque() + br label %loop + +loop: + %i = phi i64 [ 0, %entry ], [ %next, %latch ] + %enabled = icmp eq i64 %i, 7 + br i1 %enabled, label %if.then, label %latch + +if.then: + %values = load ptr, ptr %capture, align 8 + %element = getelementptr double, ptr %values, i64 %i + %value = load double, ptr %element, align 8 + call void @use(double %value) + br label %latch + +latch: + %next = add nuw nsw i64 %i, 1 + %done = icmp eq i64 %next, 64 + br i1 %done, label %exit, label %loop + +exit: + ret void +} + +declare i32 @posix_memalign(ptr, i64, i64) +declare !callback !0 void @__kmpc_fork_call(ptr, i32, ptr, ...) +declare void @opaque() +declare void @use(double) memory(none) + +!0 = !{!1} +!1 = !{i64 2, i64 -1, i64 -1, i1 true} +!llvm.module.flags = !{!2} +!2 = !{i32 7, !"openmp", i32 51} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
