[llvm] [WIP] Consider datalayout sentinel pointer value for isKnownNonZero check (PR #91769)

via llvm-commits llvm-commits at lists.llvm.org
Fri May 10 10:08:07 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Rana Pratap Reddy (ranapratap55)

<details>
<summary>Changes</summary>

Updated isKnownNonZero method to consider data layout sentinel pointer value. Related PR #<!-- -->83109. 

---

Patch is 368.59 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/91769.diff


16 Files Affected:

- (modified) llvm/lib/Analysis/ValueTracking.cpp (+9) 
- (added) llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll (+56) 
- (added) llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll (+122) 
- (added) llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll (+321) 
- (added) llvm/test/Transforms/Attributor/nocapture-2-dl-sentinel.ll (+892) 
- (added) llvm/test/Transforms/Attributor/nofree-dl-sentinel.ll (+516) 
- (added) llvm/test/Transforms/Attributor/read_write_returned_arguments_scc-dl-sentinel.ll (+336) 
- (added) llvm/test/Transforms/Attributor/returned-dl-sentinel.ll (+1421) 
- (added) llvm/test/Transforms/Attributor/value-simplify-dl-sentinel.ll (+1732) 
- (added) llvm/test/Transforms/InstCombine/alloca-cast-debuginfo-dl-sentinel.ll (+88) 
- (added) llvm/test/Transforms/InstCombine/alloca-in-non-alloca-as-sentinel.ll (+65) 
- (added) llvm/test/Transforms/InstCombine/assume-dl-sentinel.ll (+944) 
- (added) llvm/test/Transforms/InstCombine/assume-icmp-null-select-dl-sentinel.ll (+37) 
- (added) llvm/test/Transforms/InstSimplify/compare-dl-sentinel.ll (+3270) 
- (added) llvm/test/Transforms/InstSimplify/icmp-dl-sentinel.ll (+414) 
- (added) llvm/test/Transforms/InstSimplify/null-ptr-is-valid-dl-sentinel.ll (+23) 


``````````diff
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 375385aca7a39..51ad01219c6e2 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3098,6 +3098,15 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
   // Check for pointer simplifications.
 
   if (PointerType *PtrTy = dyn_cast<PointerType>(Ty)) {
+    const DataLayout &DL = Q.DL;
+    if (DL.isSentinelValueDefined() && PtrTy) {
+      unsigned AddrSpace = PtrTy->getPointerAddressSpace();
+
+      if (DL.getSentinelPointerValue(AddrSpace) == 0)
+        return false;
+      return true;
+    }
+
     // A byval, inalloca may not be null in a non-default addres space. A
     // nonnull argument is assumed never 0.
     if (const Argument *A = dyn_cast<Argument>(V)) {
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
new file mode 100755
index 0000000000000..1f6ee8bbc348a
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/array-dl-sentinel.ll
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+;
+; FIXME: The GEP + BC + GEP solution we create is not great but correct.
+
+declare void @use(ptr nocapture readonly %arg)
+
+define void @caller() {
+; TUNIT-LABEL: define {{[^@]+}}@caller() {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[LEFT:%.*]] = alloca [3 x i32], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[LEFT]], align 4
+; TUNIT-NEXT:    [[LEFT_B4:%.*]] = getelementptr i8, ptr [[LEFT]], i64 4
+; TUNIT-NEXT:    [[TMP1:%.*]] = load i32, ptr [[LEFT_B4]], align 4
+; TUNIT-NEXT:    [[LEFT_B8:%.*]] = getelementptr i8, ptr [[LEFT]], i64 8
+; TUNIT-NEXT:    [[TMP2:%.*]] = load i32, ptr [[LEFT_B8]], align 4
+; TUNIT-NEXT:    call void @callee(i32 [[TMP0]], i32 [[TMP1]], i32 [[TMP2]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@caller() {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    call void @callee(i32 undef, i32 undef, i32 undef)
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %left = alloca [3 x i32], align 4
+  call void @callee(ptr %left)
+  ret void
+}
+
+define internal void @callee(ptr noalias %arg) {
+; CHECK: Function Attrs: memory(readwrite, argmem: none)
+; CHECK-LABEL: define {{[^@]+}}@callee
+; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ARG_PRIV:%.*]] = alloca [3 x i32], align 4, addrspace(5)
+; CHECK-NEXT:    store i32 [[TMP0]], ptr addrspace(5) [[ARG_PRIV]], align 4
+; CHECK-NEXT:    [[ARG_PRIV_B4:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 4
+; CHECK-NEXT:    store i32 [[TMP1]], ptr addrspace(5) [[ARG_PRIV_B4]], align 4
+; CHECK-NEXT:    [[ARG_PRIV_B8:%.*]] = getelementptr i8, ptr addrspace(5) [[ARG_PRIV]], i64 8
+; CHECK-NEXT:    store i32 [[TMP2]], ptr addrspace(5) [[ARG_PRIV_B8]], align 4
+; CHECK-NEXT:    [[TMP3:%.*]] = addrspacecast ptr addrspace(5) [[ARG_PRIV]] to ptr
+; CHECK-NEXT:    call void @use(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(12) [[TMP3]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  call void @use(ptr %arg)
+  ret void
+}
+;.
+; TUNIT: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
+;.
+; CGSCC: attributes #[[ATTR0]] = { memory(readwrite, argmem: none) }
+;.
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
new file mode 100755
index 0000000000000..b93017bd58986
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads-dl-sentinel.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+;
+;    #include <pthread.h>
+;
+;    ptr GlobalVPtr;
+;
+;    static ptr foo(ptr arg) { return arg; }
+;    static ptr bar(ptr arg) { return arg; }
+;
+;    int main() {
+;      pthread_t thread;
+;      pthread_create(&thread, NULL, foo, NULL);
+;      pthread_create(&thread, NULL, bar, &GlobalVPtr);
+;      return 0;
+;    }
+;
+; Verify the constant values NULL and &GlobalVPtr are propagated into foo and
+; bar, respectively.
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
+%union.pthread_attr_t = type { i64, [48 x i8] }
+
+ at GlobalVPtr = common dso_local global ptr null, align 8
+
+; FIXME: nocapture & noalias for @GlobalVPtr in %call1
+; FIXME: nocapture & noalias for %alloc2 in %call3
+
+;.
+; CHECK: @GlobalVPtr = common dso_local global ptr null, align 8
+;.
+define dso_local i32 @main() {
+; TUNIT-LABEL: define {{[^@]+}}@main() {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[ALLOC11:%.*]] = alloca i8, i32 0, align 8
+; TUNIT-NEXT:    [[ALLOC22:%.*]] = alloca i8, i32 0, align 8
+; TUNIT-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
+; TUNIT-NEXT:    [[CALL:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @foo, ptr nofree readnone align 4294967296 undef)
+; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @bar, ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) undef)
+; TUNIT-NEXT:    [[CALL2:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @baz, ptr noalias nocapture nofree noundef nonnull readnone align 8 dereferenceable(1) [[ALLOC11]])
+; TUNIT-NEXT:    [[CALL3:%.*]] = call i32 @pthread_create(ptr noundef nonnull align 8 dereferenceable(8) [[THREAD]], ptr noundef align 4294967296 null, ptr noundef nonnull @buz, ptr noalias nofree noundef nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[ALLOC22]])
+; TUNIT-NEXT:    ret i32 0
+;
+; CGSCC-LABEL: define {{[^@]+}}@main() {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[ALLOC1:%.*]] = alloca i8, align 8
+; CGSCC-NEXT:    [[ALLOC2:%.*]] = alloca i8, align 8
+; CGSCC-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
+; CGSCC-NEXT:    unreachable
+;
+entry:
+  %alloc1 = alloca i8, align 8
+  %alloc2 = alloca i8, align 8
+  %thread = alloca i64, align 8
+  %call = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @foo, ptr null)
+  %call1 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @bar, ptr @GlobalVPtr)
+  %call2 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @baz, ptr nocapture %alloc1)
+  %call3 = call i32 @pthread_create(ptr nonnull %thread, ptr null, ptr nonnull @buz, ptr %alloc2)
+  ret i32 0
+}
+
+declare !callback !0 dso_local i32 @pthread_create(ptr, ptr, ptr, ptr)
+
+define internal ptr @foo(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@foo
+; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 4294967296 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    unreachable
+;
+entry:
+  ret ptr %arg
+}
+
+define internal ptr @bar(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@bar
+; CHECK-SAME: (ptr noalias nocapture nofree nonnull readnone align 8 dereferenceable(8) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr @GlobalVPtr
+;
+entry:
+  ret ptr %arg
+}
+
+define internal ptr @baz(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@baz
+; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[ARG]]
+;
+entry:
+  ret ptr %arg
+}
+
+define internal ptr @buz(ptr %arg) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define {{[^@]+}}@buz
+; CHECK-SAME: (ptr noalias nofree noundef nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret ptr [[ARG]]
+;
+entry:
+  ret ptr %arg
+}
+
+!1 = !{i64 2, i64 3, i1 false}
+!0 = !{!1}
+;.
+; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+;.
+; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+;.
+; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; TUNIT: [[META1]] = !{i64 2, i64 3, i1 false}
+;.
+; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
+; CGSCC: [[META1]] = !{i64 2, i64 3, i1 false}
+;.
diff --git a/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll b/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
new file mode 100755
index 0000000000000..1e66ba25f166a
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/callbacks-dl-sentinel.ll
@@ -0,0 +1,321 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-z0:1-z2:neg1-z3:neg1-z5:neg1-S128"
+
+; Test 0
+;
+; Make sure we propagate information from the caller to the callback callee but
+; only for arguments that are mapped through the callback metadata. Here, the
+; first two arguments of the call and the callback callee do not correspond to
+; each other but argument 3-5 of the transitive call site in the caller match
+; arguments 2-4 of the callback callee. Here we should see information and value
+; transfer in both directions.
+
+define void @t0_caller(ptr %a) {
+; TUNIT-LABEL: define {{[^@]+}}@t0_caller
+; TUNIT-SAME: (ptr nonnull align 256 [[A:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
+; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
+; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t0_caller
+; CGSCC-SAME: (ptr nonnull align 256 [[A:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
+; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
+; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr noundef align 4294967296 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %b = alloca i32, align 32
+  %c = alloca ptr, align 64
+  %ptr = alloca i32, align 128
+  store i32 42, ptr %b, align 4
+  store ptr %b, ptr %c, align 8
+  call void (ptr, ptr, ptr, ...) @t0_callback_broker(ptr null, ptr %ptr, ptr @t0_callback_callee, ptr %a, i64 99, ptr %c)
+  ret void
+}
+
+; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
+; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
+define internal void @t0_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
+;
+; TUNIT-LABEL: define {{[^@]+}}@t0_callback_callee
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; TUNIT-NEXT:    tail call void @t0_check(ptr nonnull align 256 [[A]], i64 noundef 99, ptr nonnull align 32 [[TMP0]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t0_callback_callee
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; CGSCC-NEXT:    tail call void @t0_check(ptr nonnull align 256 [[A]], i64 noundef 99, ptr nonnull [[TMP0]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %ptr_val = load i32, ptr %ptr, align 8
+  store i32 %ptr_val, ptr %is_not_null
+  %0 = load ptr, ptr %c, align 8
+  tail call void @t0_check(ptr %a, i64 %b, ptr %0)
+  ret void
+}
+
+declare void @t0_check(ptr align 256, i64, ptr)
+
+declare !callback !0 void @t0_callback_broker(ptr, ptr, ptr, ...)
+
+; Test 1
+;
+; Similar to test 0 but with some additional annotations (noalias/nocapute) to make sure
+; we deduce and propagate noalias and others properly.
+
+define void @t1_caller(ptr noalias %a) {
+;
+; TUNIT-LABEL: define {{[^@]+}}@t1_caller
+; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
+; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
+; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t1_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 undef, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC-LABEL: define {{[^@]+}}@t1_caller
+; CGSCC-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[B:%.*]] = alloca i32, align 32
+; CGSCC-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; CGSCC-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; CGSCC-NEXT:    store i32 42, ptr [[B]], align 32
+; CGSCC-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; CGSCC-NEXT:    call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr noundef align 4294967296 null, ptr noalias nocapture noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr nocapture noundef nonnull @t1_callback_callee, ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %b = alloca i32, align 32
+  %c = alloca ptr, align 64
+  %ptr = alloca i32, align 128
+  store i32 42, ptr %b, align 4
+  store ptr %b, ptr %c, align 8
+  call void (ptr, ptr, ptr, ...) @t1_callback_broker(ptr null, ptr %ptr, ptr @t1_callback_callee, ptr %a, i64 99, ptr %c)
+  ret void
+}
+
+; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
+; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
+define internal void @t1_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
+;
+; TUNIT: Function Attrs: nosync
+; TUNIT-LABEL: define {{[^@]+}}@t1_callback_callee
+; TUNIT-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; TUNIT-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; TUNIT-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; TUNIT-NEXT:    tail call void @t1_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull align 32 [[TMP0]])
+; TUNIT-NEXT:    ret void
+;
+; CGSCC: Function Attrs: nosync
+; CGSCC-LABEL: define {{[^@]+}}@t1_callback_callee
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nocapture nofree noundef nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], ptr nocapture nonnull align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 64 dereferenceable(8) [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    [[PTR_VAL:%.*]] = load i32, ptr [[PTR]], align 8
+; CGSCC-NEXT:    store i32 [[PTR_VAL]], ptr [[IS_NOT_NULL]], align 4
+; CGSCC-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[C]], align 64
+; CGSCC-NEXT:    tail call void @t1_check(ptr nocapture nonnull align 256 [[A]], i64 noundef 99, ptr nocapture nonnull [[TMP0]])
+; CGSCC-NEXT:    ret void
+;
+entry:
+  %ptr_val = load i32, ptr %ptr, align 8
+  store i32 %ptr_val, ptr %is_not_null
+  %0 = load ptr, ptr %c, align 8
+  tail call void @t1_check(ptr %a, i64 %b, ptr %0)
+  ret void
+}
+
+declare void @t1_check(ptr nocapture align 256, i64, ptr nocapture) nosync
+
+declare !callback !0 void @t1_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
+
+; Test 2
+;
+; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved.
+
+define void @t2_caller(ptr noalias %a) {
+; TUNIT-LABEL: define {{[^@]+}}@t2_caller
+; TUNIT-SAME: (ptr noalias nocapture nonnull align 256 [[A:%.*]]) {
+; TUNIT-NEXT:  entry:
+; TUNIT-NEXT:    [[B:%.*]] = alloca i32, align 32
+; TUNIT-NEXT:    [[C:%.*]] = alloca ptr, align 64
+; TUNIT-NEXT:    [[PTR:%.*]] = alloca i32, align 128
+; TUNIT-NEXT:    store i32 42, ptr [[B]], align 32
+; TUNIT-NEXT:    store ptr [[B]], ptr [[C]], align 64
+; TUNIT-NEXT:    call void (ptr, ptr, ptr, ...) @t2_callback_broker(ptr ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/91769


More information about the llvm-commits mailing list