105 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature2; RUN: opt -passes=inline -S < %s | FileCheck --check-prefixes=CHECK,NO_ASSUME %s3; RUN: opt -passes=inline -S --enable-knowledge-retention < %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME4 5; The callee guarantees that the pointer argument is nonnull and dereferenceable.6; That information should transfer to the caller.7 8define i32 @callee(ptr dereferenceable(32) %t1) {9; CHECK-LABEL: define {{[^@]+}}@callee10; CHECK-SAME: (ptr dereferenceable(32) [[T1:%.*]]) {11; CHECK-NEXT: [[T2:%.*]] = load i32, ptr [[T1]], align 412; CHECK-NEXT: ret i32 [[T2]]13;14 %t2 = load i32, ptr %t115 ret i32 %t216}17 18define i32 @callee2(ptr dereferenceable(32) %t1, i32 noundef %t2) {19; CHECK-LABEL: define {{[^@]+}}@callee220; CHECK-SAME: (ptr dereferenceable(32) [[T1:%.*]], i32 noundef [[T2:%.*]]) {21; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[T1]], align 422; CHECK-NEXT: ret i32 [[V]]23;24 %v = load i32, ptr %t125 ret i32 %v26}27 28; FIXME: All dereferenceability information is lost.29; The caller argument could be known nonnull and dereferenceable(32).30 31define i32 @caller1(ptr %t1, i32 %t2) {32; NO_ASSUME-LABEL: define {{[^@]+}}@caller133; NO_ASSUME-SAME: (ptr [[T1:%.*]], i32 [[T2:%.*]]) {34; NO_ASSUME-NEXT: [[V_I:%.*]] = load i32, ptr [[T1]], align 435; NO_ASSUME-NEXT: ret i32 [[V_I]]36;37; USE_ASSUME-LABEL: define {{[^@]+}}@caller138; USE_ASSUME-SAME: (ptr [[T1:%.*]], i32 [[T2:%.*]]) {39; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[T1]], i64 32), "noundef"(i32 [[T2]]) ]40; USE_ASSUME-NEXT: [[V_I:%.*]] = load i32, ptr [[T1]], align 441; USE_ASSUME-NEXT: ret i32 [[V_I]]42;43 %v = tail call i32 @callee2(ptr dereferenceable(32) %t1, i32 noundef %t2)44 ret i32 %v45}46 47; The caller argument is nonnull, but that can be explicit.48; The dereferenceable amount could be increased.49 50define i32 @caller2(ptr dereferenceable(31) %t1) {51; NO_ASSUME-LABEL: define {{[^@]+}}@caller252; NO_ASSUME-SAME: (ptr dereferenceable(31) [[T1:%.*]])53; NO_ASSUME-NEXT: [[T2_I:%.*]] = load i32, ptr [[T1]]54; NO_ASSUME-NEXT: ret i32 [[T2_I]]55;56; USE_ASSUME-LABEL: define {{[^@]+}}@caller257; USE_ASSUME-SAME: (ptr dereferenceable(31) [[T1:%.*]])58; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[T1]], i64 32) ]59; USE_ASSUME-NEXT: [[T2_I:%.*]] = load i32, ptr [[T1]]60; USE_ASSUME-NEXT: ret i32 [[T2_I]]61;62 %t2 = tail call i32 @callee(ptr dereferenceable(32) %t1)63 ret i32 %t264}65 66; The caller argument is nonnull, but that can be explicit.67; Make sure that we don't propagate a smaller dereferenceable amount.68 69define i32 @caller3(ptr dereferenceable(33) %t1) {70; CHECK-LABEL: define {{[^@]+}}@caller371; CHECK-SAME: (ptr dereferenceable(33) [[T1:%.*]])72; CHECK-NEXT: [[T2_I:%.*]] = load i32, ptr [[T1]]73; CHECK-NEXT: ret i32 [[T2_I]]74;75 %t2 = tail call i32 @callee(ptr dereferenceable(32) %t1)76 ret i32 %t277}78 79; Make sure that we don't propagate a pointer-only attribute to a vector of pointers.80 81declare void @helper4(<4 x ptr> %ptr)82 83define void @callee4(ptr readonly %ptr, <4 x i64> %idx) {84; CHECK-LABEL: define {{[^@]+}}@callee485; CHECK-SAME: (ptr readonly [[PTR:%.*]], <4 x i64> [[IDX:%.*]]) {86; CHECK-NEXT: [[PTRS:%.*]] = getelementptr inbounds i8, ptr [[PTR]], <4 x i64> [[IDX]]87; CHECK-NEXT: call void @helper4(<4 x ptr> [[PTRS]])88; CHECK-NEXT: ret void89;90 %ptrs = getelementptr inbounds i8, ptr %ptr, <4 x i64> %idx91 call void @helper4(<4 x ptr> %ptrs)92 ret void93}94 95define void @caller4(ptr readonly %ptr, <4 x i64> %idx) {96; CHECK-LABEL: define {{[^@]+}}@caller497; CHECK-SAME: (ptr readonly [[PTR:%.*]], <4 x i64> [[IDX:%.*]]) {98; CHECK-NEXT: [[PTRS_I:%.*]] = getelementptr inbounds i8, ptr [[PTR]], <4 x i64> [[IDX]]99; CHECK-NEXT: call void @helper4(<4 x ptr> [[PTRS_I]])100; CHECK-NEXT: ret void101;102 call void @callee4(ptr readonly %ptr, <4 x i64> %idx)103 ret void104}105