
These should not really have uselists, and it's not worth the compile time of looking at all uses of trivial constants. The main observable change of this is it no longer adds align attributes on constant null uses, but those are not useful. Some of these cases should potentially be more aggressive and not look at any Constant users.
322 lines
19 KiB
LLVM
322 lines
19 KiB
LLVM
; 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-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 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 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr align 256 [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@t0_caller
|
|
; CGSCC-SAME: (ptr 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 null, ptr noundef nonnull align 128 dereferenceable(4) [[PTR]], ptr noundef nonnull @t0_callback_callee, ptr align 256 [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 align 256 [[A]], i64 noundef 99, ptr align 32 [[TMP0]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@t0_callback_callee
|
|
; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 align 256 [[A]], i64 noundef 99, ptr [[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 align 256 captures(none) [[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 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t1_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@t1_caller
|
|
; CGSCC-SAME: (ptr noalias align 256 captures(none) [[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 null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t1_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nosync
|
|
; CGSCC-LABEL: define {{[^@]+}}@t1_callback_callee
|
|
; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[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 align 256 captures(none) [[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 noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t2_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@t2_caller
|
|
; CGSCC-SAME: (ptr noalias align 256 captures(none) [[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, ...) @t2_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t2_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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, ...) @t2_callback_broker(ptr null, ptr %ptr, ptr @t2_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.
|
|
;
|
|
; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
|
|
define internal void @t2_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
|
|
;
|
|
; TUNIT-LABEL: define {{[^@]+}}@t2_callback_callee
|
|
; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 @t2_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@t2_callback_callee
|
|
; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 @t2_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[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 @t2_check(ptr %a, i64 %b, ptr %0)
|
|
ret void
|
|
}
|
|
|
|
declare void @t2_check(ptr nocapture align 256, i64, ptr nocapture)
|
|
|
|
declare !callback !0 void @t2_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
|
|
|
|
; Test 3
|
|
;
|
|
; Basically test 2 with the casted callback callee used twice.
|
|
|
|
define void @t3_caller(ptr noalias %a) {
|
|
; TUNIT-LABEL: define {{[^@]+}}@t3_caller
|
|
; TUNIT-SAME: (ptr noalias align 256 captures(none) [[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, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
|
|
; TUNIT-NEXT: call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 undef, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@t3_caller
|
|
; CGSCC-SAME: (ptr noalias align 256 captures(none) [[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, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) dereferenceable(8) [[C]])
|
|
; CGSCC-NEXT: call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr noundef null, ptr noalias noundef nonnull align 128 captures(none) dereferenceable(4) [[PTR]], ptr noundef nonnull captures(none) @t3_callback_callee, ptr align 256 captures(none) [[A]], i64 noundef 99, ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_callback_callee, ptr %a, i64 99, ptr %c)
|
|
call void (ptr, ptr, ptr, ...) @t3_callback_broker(ptr null, ptr %ptr, ptr @t3_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.
|
|
;
|
|
; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
|
|
define internal void @t3_callback_callee(ptr %is_not_null, ptr %ptr, ptr %a, i64 %b, ptr %c) {
|
|
;
|
|
; TUNIT-LABEL: define {{[^@]+}}@t3_callback_callee
|
|
; TUNIT-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 @t3_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr align 32 captures(none) [[TMP0]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@t3_callback_callee
|
|
; CGSCC-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[IS_NOT_NULL:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(4) [[PTR:%.*]], ptr align 256 captures(none) [[A:%.*]], i64 [[B:%.*]], ptr noalias nofree noundef nonnull readonly align 64 captures(none) 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 @t3_check(ptr align 256 captures(none) [[A]], i64 noundef 99, ptr captures(none) [[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 @t3_check(ptr %a, i64 %b, ptr %0)
|
|
ret void
|
|
}
|
|
|
|
declare void @t3_check(ptr nocapture align 256, i64, ptr nocapture)
|
|
|
|
declare !callback !0 void @t3_callback_broker(ptr nocapture , ptr nocapture , ptr nocapture, ...)
|
|
|
|
!0 = !{!1}
|
|
!1 = !{i64 2, i64 -1, i64 -1, i1 true}
|
|
;.
|
|
; TUNIT: attributes #[[ATTR0]] = { nosync }
|
|
;.
|
|
; CGSCC: attributes #[[ATTR0]] = { nosync }
|
|
;.
|
|
; TUNIT: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
|
|
; TUNIT: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
|
|
;.
|
|
; CGSCC: [[META0:![0-9]+]] = !{[[META1:![0-9]+]]}
|
|
; CGSCC: [[META1]] = !{i64 2, i64 -1, i64 -1, i1 true}
|
|
;.
|
|
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
|
|
; CHECK: {{.*}}
|