When we simplify at least one operand in the Attributor simplification we can use the InstSimplify to work on the simplified operands. This allows us to avoid duplication of the logic. Depends on D106189 Differential Revision: https://reviews.llvm.org/D106190
1198 lines
65 KiB
LLVM
1198 lines
65 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
|
|
; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
|
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
|
|
; FIXME: Figure out why we need 16 iterations here.
|
|
|
|
declare void @deref_phi_user(i32* %a);
|
|
|
|
; TEST 1
|
|
; take mininimum of return values
|
|
;
|
|
define i32* @test1(i32* dereferenceable(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
|
|
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test1
|
|
; IS__TUNIT____-SAME: (i32* nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
|
|
; IS__TUNIT____-NEXT: [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
|
|
; IS__TUNIT____-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
|
|
; IS__TUNIT____-NEXT: ret i32* [[TMP5]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test1
|
|
; IS__CGSCC____-SAME: (i32* nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
|
|
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
|
|
; IS__CGSCC____-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
|
|
; IS__CGSCC____-NEXT: ret i32* [[TMP5]]
|
|
;
|
|
%4 = bitcast double* %1 to i32*
|
|
%5 = select i1 %2, i32* %0, i32* %4
|
|
ret i32* %5
|
|
}
|
|
|
|
; TEST 2
|
|
define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
|
|
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test2
|
|
; IS__TUNIT____-SAME: (i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__TUNIT____-NEXT: [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
|
|
; IS__TUNIT____-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
|
|
; IS__TUNIT____-NEXT: ret i32* [[TMP5]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test2
|
|
; IS__CGSCC____-SAME: (i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
|
|
; IS__CGSCC____-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
|
|
; IS__CGSCC____-NEXT: ret i32* [[TMP5]]
|
|
;
|
|
%4 = bitcast double* %1 to i32*
|
|
%5 = select i1 %2, i32* %0, i32* %4
|
|
ret i32* %5
|
|
}
|
|
|
|
; TEST 3
|
|
; GEP inbounds
|
|
define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr {
|
|
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test3_1
|
|
; IS__TUNIT____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__TUNIT____-NEXT: [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
|
|
; IS__TUNIT____-NEXT: ret i32* [[RET]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test3_1
|
|
; IS__CGSCC____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__CGSCC____-NEXT: [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
|
|
; IS__CGSCC____-NEXT: ret i32* [[RET]]
|
|
;
|
|
%ret = getelementptr inbounds i32, i32* %0, i64 1
|
|
ret i32* %ret
|
|
}
|
|
|
|
define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr {
|
|
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test3_2
|
|
; IS__TUNIT____-SAME: (i32* nofree readnone dereferenceable_or_null(32) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__TUNIT____-NEXT: [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 4
|
|
; IS__TUNIT____-NEXT: ret i32* [[RET]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test3_2
|
|
; IS__CGSCC____-SAME: (i32* nofree readnone dereferenceable_or_null(32) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__CGSCC____-NEXT: [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 4
|
|
; IS__CGSCC____-NEXT: ret i32* [[RET]]
|
|
;
|
|
%ret = getelementptr inbounds i32, i32* %0, i64 4
|
|
ret i32* %ret
|
|
}
|
|
|
|
define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr {
|
|
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test3_3
|
|
; IS__TUNIT____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]], i32* nofree nonnull readnone dereferenceable(16) "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__TUNIT____-NEXT: [[RET1:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
|
|
; IS__TUNIT____-NEXT: [[RET2:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i64 2
|
|
; IS__TUNIT____-NEXT: [[RET:%.*]] = select i1 [[TMP2]], i32* [[RET1]], i32* [[RET2]]
|
|
; IS__TUNIT____-NEXT: ret i32* [[RET]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test3_3
|
|
; IS__CGSCC____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]], i32* nofree nonnull readnone dereferenceable(16) "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__CGSCC____-NEXT: [[RET1:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
|
|
; IS__CGSCC____-NEXT: [[RET2:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i64 2
|
|
; IS__CGSCC____-NEXT: [[RET:%.*]] = select i1 [[TMP2]], i32* [[RET1]], i32* [[RET2]]
|
|
; IS__CGSCC____-NEXT: ret i32* [[RET]]
|
|
;
|
|
%ret1 = getelementptr inbounds i32, i32* %0, i64 1
|
|
%ret2 = getelementptr inbounds i32, i32* %1, i64 2
|
|
%ret = select i1 %2, i32* %ret1, i32* %ret2
|
|
ret i32* %ret
|
|
}
|
|
|
|
; TEST 4
|
|
; Better than known in IR.
|
|
|
|
define dereferenceable(4) i32* @test4(i32* dereferenceable(8) %0) local_unnamed_addr {
|
|
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test4
|
|
; IS__TUNIT____-SAME: (i32* nofree nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__TUNIT____-NEXT: ret i32* [[TMP0]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test4
|
|
; IS__CGSCC____-SAME: (i32* nofree nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
|
|
; IS__CGSCC____-NEXT: ret i32* [[TMP0]]
|
|
;
|
|
ret i32* %0
|
|
}
|
|
|
|
; TEST 5
|
|
; loop in which dereferenceabily "grows"
|
|
define void @deref_phi_growing(i32* dereferenceable(4000) %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@deref_phi_growing
|
|
; CHECK-SAME: (i32* nonnull dereferenceable(4000) [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
|
|
; CHECK-NEXT: [[A_ADDR_0:%.*]] = phi i32* [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]
|
|
; CHECK-NEXT: call void @deref_phi_user(i32* nonnull dereferenceable(4000) [[A_ADDR_0]])
|
|
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[A_ADDR_0]], align 4
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[TMP]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: br label [[FOR_END:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: br label [[FOR_INC]]
|
|
; CHECK: for.inc:
|
|
; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i32, i32* [[A_ADDR_0]], i64 -1
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1
|
|
; CHECK-NEXT: br label [[FOR_COND]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond: ; preds = %for.inc, %entry
|
|
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
|
|
%a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ]
|
|
call void @deref_phi_user(i32* %a.addr.0)
|
|
%tmp = load i32, i32* %a.addr.0, align 4
|
|
%cmp = icmp slt i32 %i.0, %tmp
|
|
br i1 %cmp, label %for.body, label %for.cond.cleanup
|
|
|
|
for.cond.cleanup: ; preds = %for.cond
|
|
br label %for.end
|
|
|
|
for.body: ; preds = %for.cond
|
|
br label %for.inc
|
|
|
|
for.inc: ; preds = %for.body
|
|
%incdec.ptr = getelementptr inbounds i32, i32* %a.addr.0, i64 -1
|
|
%inc = add nuw nsw i32 %i.0, 1
|
|
br label %for.cond
|
|
|
|
for.end: ; preds = %for.cond.cleanup
|
|
ret void
|
|
}
|
|
|
|
; TEST 6
|
|
; loop in which dereferenceabily "shrinks"
|
|
define void @deref_phi_shrinking(i32* dereferenceable(4000) %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@deref_phi_shrinking
|
|
; CHECK-SAME: (i32* nonnull dereferenceable(4000) [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
|
|
; CHECK-NEXT: [[A_ADDR_0:%.*]] = phi i32* [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]
|
|
; CHECK-NEXT: call void @deref_phi_user(i32* nonnull [[A_ADDR_0]])
|
|
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[A_ADDR_0]], align 4
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[TMP]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: br label [[FOR_END:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: br label [[FOR_INC]]
|
|
; CHECK: for.inc:
|
|
; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i32, i32* [[A_ADDR_0]], i64 1
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1
|
|
; CHECK-NEXT: br label [[FOR_COND]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond: ; preds = %for.inc, %entry
|
|
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
|
|
%a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ]
|
|
call void @deref_phi_user(i32* %a.addr.0)
|
|
%tmp = load i32, i32* %a.addr.0, align 4
|
|
%cmp = icmp slt i32 %i.0, %tmp
|
|
br i1 %cmp, label %for.body, label %for.cond.cleanup
|
|
|
|
for.cond.cleanup: ; preds = %for.cond
|
|
br label %for.end
|
|
|
|
for.body: ; preds = %for.cond
|
|
br label %for.inc
|
|
|
|
for.inc: ; preds = %for.body
|
|
%incdec.ptr = getelementptr inbounds i32, i32* %a.addr.0, i64 1
|
|
%inc = add nuw nsw i32 %i.0, 1
|
|
br label %for.cond
|
|
|
|
for.end: ; preds = %for.cond.cleanup
|
|
ret void
|
|
}
|
|
|
|
; TEST 7
|
|
; share known infomation in must-be-executed-context
|
|
declare i32* @unkown_ptr() willreturn nounwind
|
|
declare i32 @unkown_f(i32*) willreturn nounwind
|
|
define i32* @f7_0(i32* %ptr) {
|
|
; CHECK: Function Attrs: nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@f7_0
|
|
; CHECK-SAME: (i32* noundef nonnull returned dereferenceable(8) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] {
|
|
; CHECK-NEXT: [[T:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull dereferenceable(8) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: ret i32* [[PTR]]
|
|
;
|
|
%T = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
|
|
ret i32* %ptr
|
|
}
|
|
|
|
define void @f7_1(i32* %ptr, i1 %c) {
|
|
; CHECK: Function Attrs: nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@f7_1
|
|
; CHECK-SAME: (i32* noundef nonnull align 4 dereferenceable(4) [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: [[A:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: [[B:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[C:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: [[D:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: [[E:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%A = tail call i32 @unkown_f(i32* %ptr)
|
|
%ptr.0 = load i32, i32* %ptr
|
|
; deref 4 hold
|
|
; FIXME: this should be %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr)
|
|
%B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
|
|
br i1%c, label %if.true, label %if.false
|
|
if.true:
|
|
%C = tail call i32 @unkown_f(i32* %ptr)
|
|
%D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
|
|
%E = tail call i32 @unkown_f(i32* %ptr)
|
|
ret void
|
|
if.false:
|
|
ret void
|
|
}
|
|
|
|
define void @f7_2(i1 %c) {
|
|
; CHECK: Function Attrs: nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@f7_2
|
|
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: [[PTR:%.*]] = tail call nonnull align 4 dereferenceable(4) i32* @unkown_ptr() #[[ATTR1]]
|
|
; CHECK-NEXT: [[A:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: [[ARG_A_0:%.*]] = load i32, i32* [[PTR]], align 4
|
|
; CHECK-NEXT: [[B:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[C:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: [[D:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: [[E:%.*]] = tail call i32 @unkown_f(i32* noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%ptr = tail call i32* @unkown_ptr()
|
|
%A = tail call i32 @unkown_f(i32* %ptr)
|
|
%arg_a.0 = load i32, i32* %ptr
|
|
; deref 4 hold
|
|
%B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
|
|
br i1%c, label %if.true, label %if.false
|
|
if.true:
|
|
%C = tail call i32 @unkown_f(i32* %ptr)
|
|
%D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
|
|
%E = tail call i32 @unkown_f(i32* %ptr)
|
|
ret void
|
|
if.false:
|
|
ret void
|
|
}
|
|
|
|
define i32* @f7_3() {
|
|
; CHECK: Function Attrs: nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@f7_3
|
|
; CHECK-SAME: () #[[ATTR1]] {
|
|
; CHECK-NEXT: [[PTR:%.*]] = tail call noundef nonnull align 16 dereferenceable(4) i32* @unkown_ptr() #[[ATTR1]]
|
|
; CHECK-NEXT: store i32 10, i32* [[PTR]], align 16
|
|
; CHECK-NEXT: ret i32* [[PTR]]
|
|
;
|
|
%ptr = tail call i32* @unkown_ptr()
|
|
store i32 10, i32* %ptr, align 16
|
|
ret i32* %ptr
|
|
}
|
|
|
|
; FIXME: This should have a return dereferenceable(8) but we need to make sure it will work in loops as well.
|
|
define i32* @test_for_minus_index(i32* %p) {
|
|
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_for_minus_index
|
|
; IS__TUNIT____-SAME: (i32* nofree nonnull writeonly align 4 "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR2:[0-9]+]] {
|
|
; IS__TUNIT____-NEXT: [[Q:%.*]] = getelementptr inbounds i32, i32* [[P]], i32 -2
|
|
; IS__TUNIT____-NEXT: store i32 1, i32* [[Q]], align 4
|
|
; IS__TUNIT____-NEXT: ret i32* [[Q]]
|
|
;
|
|
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_for_minus_index
|
|
; IS__CGSCC____-SAME: (i32* nofree nonnull writeonly align 4 "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR2:[0-9]+]] {
|
|
; IS__CGSCC____-NEXT: [[Q:%.*]] = getelementptr inbounds i32, i32* [[P]], i32 -2
|
|
; IS__CGSCC____-NEXT: store i32 1, i32* [[Q]], align 4
|
|
; IS__CGSCC____-NEXT: ret i32* [[Q]]
|
|
;
|
|
%q = getelementptr inbounds i32, i32* %p, i32 -2
|
|
store i32 1, i32* %q
|
|
ret i32* %q
|
|
}
|
|
|
|
define void @deref_or_null_and_nonnull(i32* dereferenceable_or_null(100) %0) {
|
|
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@deref_or_null_and_nonnull
|
|
; IS__TUNIT____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(100) [[TMP0:%.*]]) #[[ATTR2]] {
|
|
; IS__TUNIT____-NEXT: store i32 1, i32* [[TMP0]], align 4
|
|
; IS__TUNIT____-NEXT: ret void
|
|
;
|
|
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@deref_or_null_and_nonnull
|
|
; IS__CGSCC____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(100) [[TMP0:%.*]]) #[[ATTR2]] {
|
|
; IS__CGSCC____-NEXT: store i32 1, i32* [[TMP0]], align 4
|
|
; IS__CGSCC____-NEXT: ret void
|
|
;
|
|
store i32 1, i32* %0
|
|
ret void
|
|
}
|
|
|
|
; TEST 8
|
|
; Use Constant range in deereferenceable
|
|
; void g(int *p, long long int *range){
|
|
; int r = *range ; // [10, 99]
|
|
; fill_range(p, *range);
|
|
; }
|
|
|
|
; FIXME: %ptr should be dereferenceable(31)
|
|
define void @test8(i8* %ptr) #0 {
|
|
; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
|
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test8
|
|
; IS__TUNIT_OPM-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; IS__TUNIT_OPM-NEXT: br label [[TMP1:%.*]]
|
|
; IS__TUNIT_OPM: 1:
|
|
; IS__TUNIT_OPM-NEXT: [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
|
|
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = sext i32 [[I_0]] to i64
|
|
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
|
|
; IS__TUNIT_OPM-NEXT: store i8 32, i8* [[TMP3]], align 1
|
|
; IS__TUNIT_OPM-NEXT: [[TMP4]] = add nsw i32 [[I_0]], 1
|
|
; IS__TUNIT_OPM-NEXT: br label [[TMP5]]
|
|
; IS__TUNIT_OPM: 5:
|
|
; IS__TUNIT_OPM-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
|
|
; IS__TUNIT_OPM-NEXT: br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
|
|
; IS__TUNIT_OPM: 7:
|
|
; IS__TUNIT_OPM-NEXT: ret void
|
|
;
|
|
; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test8
|
|
; IS__TUNIT_NPM-SAME: (i8* nocapture nofree nonnull writeonly dereferenceable(21) [[PTR:%.*]]) #[[ATTR2]] {
|
|
; IS__TUNIT_NPM-NEXT: br label [[TMP1:%.*]]
|
|
; IS__TUNIT_NPM: 1:
|
|
; IS__TUNIT_NPM-NEXT: [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
|
|
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = sext i32 [[I_0]] to i64
|
|
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
|
|
; IS__TUNIT_NPM-NEXT: store i8 32, i8* [[TMP3]], align 1
|
|
; IS__TUNIT_NPM-NEXT: [[TMP4]] = add nsw i32 [[I_0]], 1
|
|
; IS__TUNIT_NPM-NEXT: br label [[TMP5]]
|
|
; IS__TUNIT_NPM: 5:
|
|
; IS__TUNIT_NPM-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
|
|
; IS__TUNIT_NPM-NEXT: br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
|
|
; IS__TUNIT_NPM: 7:
|
|
; IS__TUNIT_NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind writeonly
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test8
|
|
; IS__CGSCC_OPM-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; IS__CGSCC_OPM-NEXT: br label [[TMP1:%.*]]
|
|
; IS__CGSCC_OPM: 1:
|
|
; IS__CGSCC_OPM-NEXT: [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
|
|
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = sext i32 [[I_0]] to i64
|
|
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
|
|
; IS__CGSCC_OPM-NEXT: store i8 32, i8* [[TMP3]], align 1
|
|
; IS__CGSCC_OPM-NEXT: [[TMP4]] = add nsw i32 [[I_0]], 1
|
|
; IS__CGSCC_OPM-NEXT: br label [[TMP5]]
|
|
; IS__CGSCC_OPM: 5:
|
|
; IS__CGSCC_OPM-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
|
|
; IS__CGSCC_OPM-NEXT: br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
|
|
; IS__CGSCC_OPM: 7:
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test8
|
|
; IS__CGSCC_NPM-SAME: (i8* nocapture nofree nonnull writeonly dereferenceable(21) [[PTR:%.*]]) #[[ATTR2]] {
|
|
; IS__CGSCC_NPM-NEXT: br label [[TMP1:%.*]]
|
|
; IS__CGSCC_NPM: 1:
|
|
; IS__CGSCC_NPM-NEXT: [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
|
|
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = sext i32 [[I_0]] to i64
|
|
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
|
|
; IS__CGSCC_NPM-NEXT: store i8 32, i8* [[TMP3]], align 1
|
|
; IS__CGSCC_NPM-NEXT: [[TMP4]] = add nsw i32 [[I_0]], 1
|
|
; IS__CGSCC_NPM-NEXT: br label [[TMP5]]
|
|
; IS__CGSCC_NPM: 5:
|
|
; IS__CGSCC_NPM-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
|
|
; IS__CGSCC_NPM-NEXT: br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
|
|
; IS__CGSCC_NPM: 7:
|
|
; IS__CGSCC_NPM-NEXT: ret void
|
|
;
|
|
br label %1
|
|
1: ; preds = %5, %0
|
|
%i.0 = phi i32 [ 20, %0 ], [ %4, %5 ]
|
|
%2 = sext i32 %i.0 to i64
|
|
%3 = getelementptr inbounds i8, i8* %ptr, i64 %2
|
|
store i8 32, i8* %3, align 1
|
|
%4 = add nsw i32 %i.0, 1
|
|
br label %5
|
|
5: ; preds = %1
|
|
%6 = icmp slt i32 %4, 30
|
|
br i1 %6, label %1, label %7
|
|
|
|
7: ; preds = %5
|
|
ret void
|
|
}
|
|
|
|
; 8.2 (negative case)
|
|
define void @test8_neg(i32 %i, i8* %ptr) #0 {
|
|
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@test8_neg
|
|
; IS__TUNIT____-SAME: (i32 [[I:%.*]], i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) #[[ATTR2]] {
|
|
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = sext i32 [[I]] to i64
|
|
; IS__TUNIT____-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP1]]
|
|
; IS__TUNIT____-NEXT: store i8 65, i8* [[TMP2]], align 1
|
|
; IS__TUNIT____-NEXT: ret void
|
|
;
|
|
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@test8_neg
|
|
; IS__CGSCC____-SAME: (i32 [[I:%.*]], i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) #[[ATTR2]] {
|
|
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = sext i32 [[I]] to i64
|
|
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP1]]
|
|
; IS__CGSCC____-NEXT: store i8 65, i8* [[TMP2]], align 1
|
|
; IS__CGSCC____-NEXT: ret void
|
|
;
|
|
%1 = sext i32 %i to i64
|
|
%2 = getelementptr inbounds i8, i8* %ptr, i64 %1
|
|
store i8 65, i8* %2, align 1
|
|
ret void
|
|
}
|
|
|
|
; void fill_range(int* p, long long int start){
|
|
; for(long long int i = start;i<start+10;i++){
|
|
; // If p[i] is inbounds, p is dereferenceable(40) at least.
|
|
; p[i] = i;
|
|
; }
|
|
; }
|
|
|
|
; NOTE: %p should not be dereferenceable
|
|
define internal void @fill_range_not_inbounds(i32* %p, i64 %start){
|
|
; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
|
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
|
|
; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR3]] {
|
|
; IS__TUNIT_OPM-NEXT: entry:
|
|
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__TUNIT_OPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__TUNIT_OPM: for.cond.cleanup:
|
|
; IS__TUNIT_OPM-NEXT: ret void
|
|
; IS__TUNIT_OPM: for.body:
|
|
; IS__TUNIT_OPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__TUNIT_OPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__TUNIT_OPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__TUNIT_OPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__TUNIT_OPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__TUNIT_OPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__TUNIT_OPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
|
|
; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR2]] {
|
|
; IS__TUNIT_NPM-NEXT: entry:
|
|
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__TUNIT_NPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__TUNIT_NPM: for.cond.cleanup:
|
|
; IS__TUNIT_NPM-NEXT: ret void
|
|
; IS__TUNIT_NPM: for.body:
|
|
; IS__TUNIT_NPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__TUNIT_NPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__TUNIT_NPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__TUNIT_NPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__TUNIT_NPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__TUNIT_NPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__TUNIT_NPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind writeonly
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
|
|
; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR3]] {
|
|
; IS__CGSCC_OPM-NEXT: entry:
|
|
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__CGSCC_OPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__CGSCC_OPM: for.cond.cleanup:
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
; IS__CGSCC_OPM: for.body:
|
|
; IS__CGSCC_OPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__CGSCC_OPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__CGSCC_OPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__CGSCC_OPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__CGSCC_OPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__CGSCC_OPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__CGSCC_OPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
|
|
; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR2]] {
|
|
; IS__CGSCC_NPM-NEXT: entry:
|
|
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__CGSCC_NPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__CGSCC_NPM: for.cond.cleanup:
|
|
; IS__CGSCC_NPM-NEXT: ret void
|
|
; IS__CGSCC_NPM: for.body:
|
|
; IS__CGSCC_NPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__CGSCC_NPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__CGSCC_NPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__CGSCC_NPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__CGSCC_NPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__CGSCC_NPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__CGSCC_NPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
entry:
|
|
%0 = add nsw i64 %start, 9
|
|
br label %for.body
|
|
|
|
for.cond.cleanup: ; preds = %for.body
|
|
ret void
|
|
|
|
for.body: ; preds = %entry, %for.body
|
|
%i.06 = phi i64 [ %start, %entry ], [ %inc, %for.body ]
|
|
%conv = trunc i64 %i.06 to i32
|
|
%arrayidx = getelementptr i32, i32* %p, i64 %i.06
|
|
store i32 %conv, i32* %arrayidx, align 4
|
|
%inc = add nsw i64 %i.06, 1
|
|
%cmp = icmp slt i64 %i.06, %0
|
|
br i1 %cmp, label %for.body, label %for.cond.cleanup
|
|
}
|
|
|
|
; FIXME: %p should be dereferenceable(40)
|
|
define internal void @fill_range_inbounds(i32* %p, i64 %start){
|
|
; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
|
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fill_range_inbounds
|
|
; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR3]] {
|
|
; IS__TUNIT_OPM-NEXT: entry:
|
|
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__TUNIT_OPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__TUNIT_OPM: for.cond.cleanup:
|
|
; IS__TUNIT_OPM-NEXT: ret void
|
|
; IS__TUNIT_OPM: for.body:
|
|
; IS__TUNIT_OPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__TUNIT_OPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__TUNIT_OPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__TUNIT_OPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__TUNIT_OPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__TUNIT_OPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__TUNIT_OPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fill_range_inbounds
|
|
; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR2]] {
|
|
; IS__TUNIT_NPM-NEXT: entry:
|
|
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__TUNIT_NPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__TUNIT_NPM: for.cond.cleanup:
|
|
; IS__TUNIT_NPM-NEXT: ret void
|
|
; IS__TUNIT_NPM: for.body:
|
|
; IS__TUNIT_NPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__TUNIT_NPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__TUNIT_NPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__TUNIT_NPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__TUNIT_NPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__TUNIT_NPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__TUNIT_NPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind writeonly
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fill_range_inbounds
|
|
; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR3]] {
|
|
; IS__CGSCC_OPM-NEXT: entry:
|
|
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__CGSCC_OPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__CGSCC_OPM: for.cond.cleanup:
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
; IS__CGSCC_OPM: for.body:
|
|
; IS__CGSCC_OPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__CGSCC_OPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__CGSCC_OPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__CGSCC_OPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__CGSCC_OPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__CGSCC_OPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__CGSCC_OPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fill_range_inbounds
|
|
; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) #[[ATTR2]] {
|
|
; IS__CGSCC_NPM-NEXT: entry:
|
|
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
|
|
; IS__CGSCC_NPM-NEXT: br label [[FOR_BODY:%.*]]
|
|
; IS__CGSCC_NPM: for.cond.cleanup:
|
|
; IS__CGSCC_NPM-NEXT: ret void
|
|
; IS__CGSCC_NPM: for.body:
|
|
; IS__CGSCC_NPM-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
|
|
; IS__CGSCC_NPM-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
|
|
; IS__CGSCC_NPM-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
|
|
; IS__CGSCC_NPM-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
|
|
; IS__CGSCC_NPM-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
|
|
; IS__CGSCC_NPM-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
|
|
; IS__CGSCC_NPM-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
|
|
;
|
|
entry:
|
|
%0 = add nsw i64 %start, 9
|
|
br label %for.body
|
|
|
|
for.cond.cleanup: ; preds = %for.body
|
|
ret void
|
|
|
|
for.body: ; preds = %entry, %for.body
|
|
%i.06 = phi i64 [ %start, %entry ], [ %inc, %for.body ]
|
|
%conv = trunc i64 %i.06 to i32
|
|
%arrayidx = getelementptr inbounds i32, i32* %p, i64 %i.06
|
|
store i32 %conv, i32* %arrayidx, align 4
|
|
%inc = add nsw i64 %i.06, 1
|
|
%cmp = icmp slt i64 %i.06, %0
|
|
br i1 %cmp, label %for.body, label %for.cond.cleanup
|
|
}
|
|
|
|
define void @call_fill_range(i32* nocapture %p, i64* nocapture readonly %range) {
|
|
; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind
|
|
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@call_fill_range
|
|
; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; IS__TUNIT_OPM-NEXT: entry:
|
|
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, !range [[RNG0:![0-9]+]]
|
|
; IS__TUNIT_OPM-NEXT: tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR6:[0-9]+]]
|
|
; IS__TUNIT_OPM-NEXT: tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR6]]
|
|
; IS__TUNIT_OPM-NEXT: ret void
|
|
;
|
|
; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn
|
|
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@call_fill_range
|
|
; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; IS__TUNIT_NPM-NEXT: entry:
|
|
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, !range [[RNG0:![0-9]+]]
|
|
; IS__TUNIT_NPM-NEXT: tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR6:[0-9]+]]
|
|
; IS__TUNIT_NPM-NEXT: tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR6]]
|
|
; IS__TUNIT_NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@call_fill_range
|
|
; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; IS__CGSCC_OPM-NEXT: entry:
|
|
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, !range [[RNG0:![0-9]+]]
|
|
; IS__CGSCC_OPM-NEXT: tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR7:[0-9]+]]
|
|
; IS__CGSCC_OPM-NEXT: tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR7]]
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
|
|
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@call_fill_range
|
|
; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; IS__CGSCC_NPM-NEXT: entry:
|
|
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, !range [[RNG0:![0-9]+]]
|
|
; IS__CGSCC_NPM-NEXT: tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR6:[0-9]+]]
|
|
; IS__CGSCC_NPM-NEXT: tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) #[[ATTR6]]
|
|
; IS__CGSCC_NPM-NEXT: ret void
|
|
;
|
|
entry:
|
|
%0 = load i64, i64* %range, align 8, !range !0
|
|
tail call void @fill_range_inbounds(i32* %p, i64 %0)
|
|
tail call void @fill_range_not_inbounds(i32* %p, i64 %0)
|
|
ret void
|
|
}
|
|
|
|
declare void @use0() willreturn nounwind
|
|
declare void @use1(i8*) willreturn nounwind
|
|
declare void @use2(i8*, i8*) willreturn nounwind
|
|
declare void @use3(i8*, i8*, i8*) willreturn nounwind
|
|
|
|
; simple path test
|
|
; if(..)
|
|
; fun2(dereferenceable(8) %a, dereferenceable(8) %b)
|
|
; else
|
|
; fun2(dereferenceable(4) %a, %b)
|
|
; We can say that %a is dereferenceable(4) but %b is not.
|
|
define void @simple-path(i8* %a, i8 * %b, i8 %c) {
|
|
; CHECK: Function Attrs: nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@simple-path
|
|
; CHECK-SAME: (i8* nonnull dereferenceable(4) [[A:%.*]], i8* [[B:%.*]], i8 [[C:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
; CHECK: if.then:
|
|
; CHECK-NEXT: tail call void @use2(i8* nonnull dereferenceable(8) [[A]], i8* nonnull dereferenceable(8) [[B]]) #[[ATTR1]]
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: if.else:
|
|
; CHECK-NEXT: tail call void @use2(i8* nonnull dereferenceable(4) [[A]], i8* [[B]]) #[[ATTR1]]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cmp = icmp eq i8 %c, 0
|
|
br i1 %cmp, label %if.then, label %if.else
|
|
if.then:
|
|
tail call void @use2(i8* dereferenceable(8) %a, i8* dereferenceable(8) %b)
|
|
ret void
|
|
if.else:
|
|
tail call void @use2(i8* dereferenceable(4) %a, i8* %b)
|
|
ret void
|
|
}
|
|
|
|
; More complex test
|
|
; {
|
|
; fun1(dereferenceable(4) %a)
|
|
; if(..)
|
|
; ... (willreturn & nounwind)
|
|
; fun1(dereferenceable(12) %a)
|
|
; else
|
|
; ... (willreturn & nounwind)
|
|
; fun1(dereferenceable(16) %a)
|
|
; fun1(dereferenceable(8) %a)
|
|
; }
|
|
; %a is dereferenceable(12)
|
|
define void @complex-path(i8* %a, i8* %b, i8 %c) {
|
|
; CHECK: Function Attrs: nounwind willreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@complex-path
|
|
; CHECK-SAME: (i8* noundef nonnull dereferenceable(12) [[A:%.*]], i8* nocapture nofree readnone [[B:%.*]], i8 [[C:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
|
|
; CHECK-NEXT: tail call void @use1(i8* noundef nonnull dereferenceable(12) [[A]]) #[[ATTR1]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]
|
|
; CHECK: cont.then:
|
|
; CHECK-NEXT: tail call void @use1(i8* noundef nonnull dereferenceable(12) [[A]]) #[[ATTR1]]
|
|
; CHECK-NEXT: br label [[CONT2:%.*]]
|
|
; CHECK: cont.else:
|
|
; CHECK-NEXT: tail call void @use1(i8* noundef nonnull dereferenceable(16) [[A]]) #[[ATTR1]]
|
|
; CHECK-NEXT: br label [[CONT2]]
|
|
; CHECK: cont2:
|
|
; CHECK-NEXT: tail call void @use1(i8* noundef nonnull dereferenceable(12) [[A]]) #[[ATTR1]]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%cmp = icmp eq i8 %c, 0
|
|
tail call void @use1(i8* dereferenceable(4) %a)
|
|
br i1 %cmp, label %cont.then, label %cont.else
|
|
cont.then:
|
|
tail call void @use1(i8* dereferenceable(12) %a)
|
|
br label %cont2
|
|
cont.else:
|
|
tail call void @use1(i8* dereferenceable(16) %a)
|
|
br label %cont2
|
|
cont2:
|
|
tail call void @use1(i8* dereferenceable(8) %a)
|
|
ret void
|
|
}
|
|
|
|
; void rec-branch-1(int a, int b, int c, int *ptr) {
|
|
; if (a) {
|
|
; if (b)
|
|
; *ptr = 1;
|
|
; else
|
|
; *ptr = 2;
|
|
; } else {
|
|
; if (c)
|
|
; *ptr = 3;
|
|
; else
|
|
; *ptr = 4;
|
|
; }
|
|
; }
|
|
;
|
|
; FIXME: %ptr should be dereferenceable(4)
|
|
define dso_local void @rec-branch-1(i32 %a, i32 %b, i32 %c, i32* %ptr) {
|
|
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@rec-branch-1
|
|
; IS__TUNIT____-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) #[[ATTR2]] {
|
|
; IS__TUNIT____-NEXT: entry:
|
|
; IS__TUNIT____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
|
|
; IS__TUNIT____-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
|
|
; IS__TUNIT____: if.then:
|
|
; IS__TUNIT____-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
|
|
; IS__TUNIT____-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
|
|
; IS__TUNIT____: if.then2:
|
|
; IS__TUNIT____-NEXT: store i32 1, i32* [[PTR]], align 4
|
|
; IS__TUNIT____-NEXT: br label [[IF_END8:%.*]]
|
|
; IS__TUNIT____: if.else:
|
|
; IS__TUNIT____-NEXT: store i32 2, i32* [[PTR]], align 4
|
|
; IS__TUNIT____-NEXT: br label [[IF_END8]]
|
|
; IS__TUNIT____: if.else3:
|
|
; IS__TUNIT____-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
|
|
; IS__TUNIT____-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
|
|
; IS__TUNIT____: if.then5:
|
|
; IS__TUNIT____-NEXT: store i32 3, i32* [[PTR]], align 4
|
|
; IS__TUNIT____-NEXT: br label [[IF_END8]]
|
|
; IS__TUNIT____: if.else6:
|
|
; IS__TUNIT____-NEXT: store i32 4, i32* [[PTR]], align 4
|
|
; IS__TUNIT____-NEXT: br label [[IF_END8]]
|
|
; IS__TUNIT____: if.end8:
|
|
; IS__TUNIT____-NEXT: ret void
|
|
;
|
|
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@rec-branch-1
|
|
; IS__CGSCC____-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) #[[ATTR2]] {
|
|
; IS__CGSCC____-NEXT: entry:
|
|
; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
|
|
; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
|
|
; IS__CGSCC____: if.then:
|
|
; IS__CGSCC____-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
|
|
; IS__CGSCC____-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
|
|
; IS__CGSCC____: if.then2:
|
|
; IS__CGSCC____-NEXT: store i32 1, i32* [[PTR]], align 4
|
|
; IS__CGSCC____-NEXT: br label [[IF_END8:%.*]]
|
|
; IS__CGSCC____: if.else:
|
|
; IS__CGSCC____-NEXT: store i32 2, i32* [[PTR]], align 4
|
|
; IS__CGSCC____-NEXT: br label [[IF_END8]]
|
|
; IS__CGSCC____: if.else3:
|
|
; IS__CGSCC____-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
|
|
; IS__CGSCC____-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
|
|
; IS__CGSCC____: if.then5:
|
|
; IS__CGSCC____-NEXT: store i32 3, i32* [[PTR]], align 4
|
|
; IS__CGSCC____-NEXT: br label [[IF_END8]]
|
|
; IS__CGSCC____: if.else6:
|
|
; IS__CGSCC____-NEXT: store i32 4, i32* [[PTR]], align 4
|
|
; IS__CGSCC____-NEXT: br label [[IF_END8]]
|
|
; IS__CGSCC____: if.end8:
|
|
; IS__CGSCC____-NEXT: ret void
|
|
;
|
|
entry:
|
|
%tobool = icmp eq i32 %a, 0
|
|
br i1 %tobool, label %if.else3, label %if.then
|
|
|
|
if.then: ; preds = %entry
|
|
%tobool1 = icmp eq i32 %b, 0
|
|
br i1 %tobool1, label %if.else, label %if.then2
|
|
|
|
if.then2: ; preds = %if.then
|
|
store i32 1, i32* %ptr, align 4
|
|
br label %if.end8
|
|
|
|
if.else: ; preds = %if.then
|
|
store i32 2, i32* %ptr, align 4
|
|
br label %if.end8
|
|
|
|
if.else3: ; preds = %entry
|
|
%tobool4 = icmp eq i32 %c, 0
|
|
br i1 %tobool4, label %if.else6, label %if.then5
|
|
|
|
if.then5: ; preds = %if.else3
|
|
store i32 3, i32* %ptr, align 4
|
|
br label %if.end8
|
|
|
|
if.else6: ; preds = %if.else3
|
|
store i32 4, i32* %ptr, align 4
|
|
br label %if.end8
|
|
|
|
if.end8: ; preds = %if.then5, %if.else6, %if.then2, %if.else
|
|
ret void
|
|
}
|
|
|
|
; void rec-branch-2(int a, int b, int c, int *ptr) {
|
|
; if (a) {
|
|
; if (b)
|
|
; *ptr = 1;
|
|
; else
|
|
; *ptr = 2;
|
|
; } else {
|
|
; if (c)
|
|
; *ptr = 3;
|
|
; else
|
|
; rec-branch-2(1, 1, 1, ptr);
|
|
; }
|
|
; }
|
|
; FIXME: %ptr should be dereferenceable(4)
|
|
define dso_local void @rec-branch-2(i32 %a, i32 %b, i32 %c, i32* %ptr) {
|
|
; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
|
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@rec-branch-2
|
|
; IS__TUNIT_OPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) #[[ATTR3]] {
|
|
; IS__TUNIT_OPM-NEXT: entry:
|
|
; IS__TUNIT_OPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
|
|
; IS__TUNIT_OPM-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
|
|
; IS__TUNIT_OPM: if.then:
|
|
; IS__TUNIT_OPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
|
|
; IS__TUNIT_OPM-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
|
|
; IS__TUNIT_OPM: if.then2:
|
|
; IS__TUNIT_OPM-NEXT: store i32 1, i32* [[PTR]], align 4
|
|
; IS__TUNIT_OPM-NEXT: br label [[IF_END8:%.*]]
|
|
; IS__TUNIT_OPM: if.else:
|
|
; IS__TUNIT_OPM-NEXT: store i32 2, i32* [[PTR]], align 4
|
|
; IS__TUNIT_OPM-NEXT: br label [[IF_END8]]
|
|
; IS__TUNIT_OPM: if.else3:
|
|
; IS__TUNIT_OPM-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
|
|
; IS__TUNIT_OPM-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
|
|
; IS__TUNIT_OPM: if.then5:
|
|
; IS__TUNIT_OPM-NEXT: store i32 3, i32* [[PTR]], align 4
|
|
; IS__TUNIT_OPM-NEXT: br label [[IF_END8]]
|
|
; IS__TUNIT_OPM: if.else6:
|
|
; IS__TUNIT_OPM-NEXT: tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, i32* nocapture nofree writeonly [[PTR]]) #[[ATTR6]]
|
|
; IS__TUNIT_OPM-NEXT: br label [[IF_END8]]
|
|
; IS__TUNIT_OPM: if.end8:
|
|
; IS__TUNIT_OPM-NEXT: ret void
|
|
;
|
|
; IS________NPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
|
; IS________NPM-LABEL: define {{[^@]+}}@rec-branch-2
|
|
; IS________NPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; IS________NPM-NEXT: entry:
|
|
; IS________NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
|
|
; IS________NPM-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
|
|
; IS________NPM: if.then:
|
|
; IS________NPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
|
|
; IS________NPM-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
|
|
; IS________NPM: if.then2:
|
|
; IS________NPM-NEXT: store i32 1, i32* [[PTR]], align 4
|
|
; IS________NPM-NEXT: br label [[IF_END8:%.*]]
|
|
; IS________NPM: if.else:
|
|
; IS________NPM-NEXT: store i32 2, i32* [[PTR]], align 4
|
|
; IS________NPM-NEXT: br label [[IF_END8]]
|
|
; IS________NPM: if.else3:
|
|
; IS________NPM-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
|
|
; IS________NPM-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
|
|
; IS________NPM: if.then5:
|
|
; IS________NPM-NEXT: store i32 3, i32* [[PTR]], align 4
|
|
; IS________NPM-NEXT: br label [[IF_END8]]
|
|
; IS________NPM: if.else6:
|
|
; IS________NPM-NEXT: tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, i32* nocapture nofree writeonly [[PTR]]) #[[ATTR7:[0-9]+]]
|
|
; IS________NPM-NEXT: br label [[IF_END8]]
|
|
; IS________NPM: if.end8:
|
|
; IS________NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@rec-branch-2
|
|
; IS__CGSCC_OPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) #[[ATTR5:[0-9]+]] {
|
|
; IS__CGSCC_OPM-NEXT: entry:
|
|
; IS__CGSCC_OPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
|
|
; IS__CGSCC_OPM-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
|
|
; IS__CGSCC_OPM: if.then:
|
|
; IS__CGSCC_OPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
|
|
; IS__CGSCC_OPM-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
|
|
; IS__CGSCC_OPM: if.then2:
|
|
; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[PTR]], align 4
|
|
; IS__CGSCC_OPM-NEXT: br label [[IF_END8:%.*]]
|
|
; IS__CGSCC_OPM: if.else:
|
|
; IS__CGSCC_OPM-NEXT: store i32 2, i32* [[PTR]], align 4
|
|
; IS__CGSCC_OPM-NEXT: br label [[IF_END8]]
|
|
; IS__CGSCC_OPM: if.else3:
|
|
; IS__CGSCC_OPM-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
|
|
; IS__CGSCC_OPM-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
|
|
; IS__CGSCC_OPM: if.then5:
|
|
; IS__CGSCC_OPM-NEXT: store i32 3, i32* [[PTR]], align 4
|
|
; IS__CGSCC_OPM-NEXT: br label [[IF_END8]]
|
|
; IS__CGSCC_OPM: if.else6:
|
|
; IS__CGSCC_OPM-NEXT: tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, i32* nocapture nofree writeonly [[PTR]]) #[[ATTR8:[0-9]+]]
|
|
; IS__CGSCC_OPM-NEXT: br label [[IF_END8]]
|
|
; IS__CGSCC_OPM: if.end8:
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
;
|
|
entry:
|
|
%tobool = icmp eq i32 %a, 0
|
|
br i1 %tobool, label %if.else3, label %if.then
|
|
|
|
if.then: ; preds = %entry
|
|
%tobool1 = icmp eq i32 %b, 0
|
|
br i1 %tobool1, label %if.else, label %if.then2
|
|
|
|
if.then2: ; preds = %if.then
|
|
store i32 1, i32* %ptr, align 4
|
|
br label %if.end8
|
|
|
|
if.else: ; preds = %if.then
|
|
store i32 2, i32* %ptr, align 4
|
|
br label %if.end8
|
|
|
|
if.else3: ; preds = %entry
|
|
%tobool4 = icmp eq i32 %c, 0
|
|
br i1 %tobool4, label %if.else6, label %if.then5
|
|
|
|
if.then5: ; preds = %if.else3
|
|
store i32 3, i32* %ptr, align 4
|
|
br label %if.end8
|
|
|
|
if.else6: ; preds = %if.else3
|
|
tail call void @rec-branch-2(i32 1, i32 1, i32 1, i32* %ptr)
|
|
br label %if.end8
|
|
|
|
if.end8: ; preds = %if.then5, %if.else6, %if.then2, %if.else
|
|
ret void
|
|
}
|
|
|
|
declare void @unknown()
|
|
define void @nonnull_assume_pos(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos
|
|
; ATTRIBUTOR-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]])
|
|
; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) #6 [ "nonnull"(i8* undef), "dereferenceable"(i8* undef, i64 1), "dereferenceable"(i8* undef, i64 2), "dereferenceable"(i8* undef, i64 101), "dereferenceable_or_null"(i8* undef, i64 31), "dereferenceable_or_null"(i8* undef, i64 42) ]
|
|
; ATTRIBUTOR-NEXT: call void @unknown()
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
|
|
; IS__TUNIT_OPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]]) {
|
|
; IS__TUNIT_OPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR7:[0-9]+]] [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown()
|
|
; IS__TUNIT_OPM-NEXT: ret void
|
|
;
|
|
; IS________NPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
|
|
; IS________NPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]]) {
|
|
; IS________NPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR8:[0-9]+]] [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
|
|
; IS________NPM-NEXT: call void @unknown()
|
|
; IS________NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
|
|
; IS__CGSCC_OPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]]) {
|
|
; IS__CGSCC_OPM-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR9:[0-9]+]] [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown()
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
;
|
|
call void @llvm.assume(i1 true) [ "nonnull"(i8* %arg3), "dereferenceable"(i8* %arg1, i64 1), "dereferenceable"(i8* %arg1, i64 2), "dereferenceable"(i8* %arg1, i64 101), "dereferenceable_or_null"(i8* %arg2, i64 31), "dereferenceable_or_null"(i8* %arg4, i64 42)]
|
|
call void @unknown()
|
|
ret void
|
|
}
|
|
define void @nonnull_assume_neg(i8* %arg1, i8* %arg2, i8* %arg3) {
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg
|
|
; ATTRIBUTOR-SAME: (i8* nocapture nofree readnone [[ARG1:%.*]], i8* nocapture nofree readnone [[ARG2:%.*]], i8* nocapture nofree readnone [[ARG3:%.*]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown()
|
|
; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i8* undef, i64 101), "dereferenceable"(i8* undef, i64 -2), "dereferenceable_or_null"(i8* undef, i64 31) ]
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
|
|
; CHECK-SAME: (i8* nocapture nofree readnone [[ARG1:%.*]], i8* nocapture nofree readnone [[ARG2:%.*]], i8* nocapture nofree readnone [[ARG3:%.*]]) {
|
|
; CHECK-NEXT: call void @unknown()
|
|
; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable"(i8* [[ARG2]], i64 -2), "dereferenceable_or_null"(i8* [[ARG3]], i64 31) ]
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void @unknown()
|
|
call void @llvm.assume(i1 true) ["dereferenceable"(i8* %arg1, i64 101), "dereferenceable"(i8* %arg2, i64 -2), "dereferenceable_or_null"(i8* %arg3, i64 31)]
|
|
ret void
|
|
}
|
|
define void @nonnull_assume_call(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
|
|
; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call
|
|
; ATTRIBUTOR-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown()
|
|
; ATTRIBUTOR-NEXT: [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr()
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(42) [[ARG4]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(31) [[ARG2]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]])
|
|
; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(31) [[ARG2]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(42) [[ARG4]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]])
|
|
; ATTRIBUTOR-NEXT: call void @unknown()
|
|
; ATTRIBUTOR-NEXT: ret void
|
|
;
|
|
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@nonnull_assume_call
|
|
; IS__TUNIT_OPM-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown()
|
|
; IS__TUNIT_OPM-NEXT: [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr() #[[ATTR8:[0-9]+]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @llvm.assume(i1 noundef true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) #[[ATTR8]]
|
|
; IS__TUNIT_OPM-NEXT: call void @unknown()
|
|
; IS__TUNIT_OPM-NEXT: ret void
|
|
;
|
|
; IS________NPM-LABEL: define {{[^@]+}}@nonnull_assume_call
|
|
; IS________NPM-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
|
|
; IS________NPM-NEXT: call void @unknown()
|
|
; IS________NPM-NEXT: [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr() #[[ATTR9:[0-9]+]]
|
|
; IS________NPM-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @llvm.assume(i1 noundef true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) #[[ATTR9]]
|
|
; IS________NPM-NEXT: call void @unknown()
|
|
; IS________NPM-NEXT: ret void
|
|
;
|
|
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@nonnull_assume_call
|
|
; IS__CGSCC_OPM-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown()
|
|
; IS__CGSCC_OPM-NEXT: [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr() #[[ATTR10:[0-9]+]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @llvm.assume(i1 noundef true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) #[[ATTR10]]
|
|
; IS__CGSCC_OPM-NEXT: call void @unknown()
|
|
; IS__CGSCC_OPM-NEXT: ret void
|
|
;
|
|
call void @unknown()
|
|
%p = call i32* @unkown_ptr()
|
|
call void @unknown_use32(i32* %p)
|
|
call void @unknown_use8(i8* %arg4)
|
|
call void @unknown_use8(i8* %arg3)
|
|
call void @unknown_use8(i8* %arg2)
|
|
call void @unknown_use8(i8* %arg1)
|
|
call void @llvm.assume(i1 true) [ "nonnull"(i8* %arg3), "dereferenceable"(i8* %arg1, i64 1), "dereferenceable"(i8* %arg1, i64 2), "dereferenceable"(i32* %p, i64 101), "dereferenceable_or_null"(i8* %arg2, i64 31), "dereferenceable_or_null"(i8* %arg4, i64 42)]
|
|
call void @unknown_use8(i8* %arg1)
|
|
call void @unknown_use8(i8* %arg2)
|
|
call void @unknown_use8(i8* %arg3)
|
|
call void @unknown_use8(i8* %arg4)
|
|
call void @unknown_use32(i32* %p)
|
|
call void @unknown()
|
|
ret void
|
|
}
|
|
declare void @unknown_use8(i8*) willreturn nounwind
|
|
declare void @unknown_use32(i32*) willreturn nounwind
|
|
declare void @llvm.assume(i1)
|
|
|
|
!0 = !{i64 10, i64 100}
|
|
|
|
;.
|
|
; IS__TUNIT_OPM: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR1]] = { nounwind willreturn }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR2]] = { argmemonly nofree nosync nounwind willreturn writeonly }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR3]] = { argmemonly nofree nosync nounwind writeonly }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR4]] = { argmemonly nofree nosync nounwind }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR5:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR6]] = { nofree nosync nounwind writeonly }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR7]] = { willreturn }
|
|
; IS__TUNIT_OPM: attributes #[[ATTR8]] = { nounwind }
|
|
;.
|
|
; IS__TUNIT_NPM: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR1]] = { nounwind willreturn }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR2]] = { argmemonly nofree nosync nounwind willreturn writeonly }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR3]] = { argmemonly nofree nosync nounwind willreturn }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR4]] = { argmemonly nofree nosync nounwind writeonly }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR5:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR6]] = { nofree nosync nounwind willreturn writeonly }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR7]] = { nofree nosync nounwind writeonly }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR8]] = { willreturn }
|
|
; IS__TUNIT_NPM: attributes #[[ATTR9]] = { nounwind }
|
|
;.
|
|
; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nounwind willreturn }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR2]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR3]] = { argmemonly nofree norecurse nosync nounwind writeonly }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR4]] = { argmemonly nofree norecurse nosync nounwind }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR5]] = { argmemonly nofree nosync nounwind writeonly }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR6:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR7]] = { nosync nounwind writeonly }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR8]] = { nofree nosync nounwind writeonly }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR9]] = { willreturn }
|
|
; IS__CGSCC_OPM: attributes #[[ATTR10]] = { nounwind }
|
|
;.
|
|
; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nounwind willreturn }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR2]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR3]] = { argmemonly nofree norecurse nosync nounwind willreturn }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR4]] = { argmemonly nofree nosync nounwind writeonly }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR5:[0-9]+]] = { inaccessiblememonly nofree nosync nounwind willreturn }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR6]] = { nosync nounwind willreturn writeonly }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nofree nosync nounwind writeonly }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR8]] = { willreturn }
|
|
; IS__CGSCC_NPM: attributes #[[ATTR9]] = { nounwind }
|
|
;.
|
|
; CHECK: [[META0:![0-9]+]] = !{i64 10, i64 100}
|
|
;.
|