840 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC4; FIXME: Figure out why we need 16 iterations here.5 6declare void @deref_phi_user(ptr %a);7 8; TEST 19; take mininimum of return values10;11;.12; CHECK: @g = global i64 013;.14define ptr @test1(ptr dereferenceable(4) %0, ptr dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {15; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)16; CHECK-LABEL: define {{[^@]+}}@test117; CHECK-SAME: (ptr nofree noundef nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0:%.*]], ptr nofree noundef nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {18; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], ptr [[TMP0]], ptr [[TMP1]]19; CHECK-NEXT: ret ptr [[TMP4]]20;21 %4 = select i1 %2, ptr %0, ptr %122 ret ptr %423}24 25; TEST 226define ptr @test2(ptr dereferenceable_or_null(4) %0, ptr dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {27; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)28; CHECK-LABEL: define {{[^@]+}}@test229; CHECK-SAME: (ptr nofree noundef readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP0:%.*]], ptr nofree noundef nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0]] {30; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], ptr [[TMP0]], ptr [[TMP1]]31; CHECK-NEXT: ret ptr [[TMP4]]32;33 %4 = select i1 %2, ptr %0, ptr %134 ret ptr %435}36 37; TEST 338; GEP inbounds39define ptr @test3_1(ptr dereferenceable(8) %0) local_unnamed_addr {40; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)41; CHECK-LABEL: define {{[^@]+}}@test3_142; CHECK-SAME: (ptr nofree noundef nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {43; CHECK-NEXT: [[RET:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 144; CHECK-NEXT: ret ptr [[RET]]45;46 %ret = getelementptr inbounds i32, ptr %0, i64 147 ret ptr %ret48}49 50define ptr @test3_2(ptr dereferenceable_or_null(32) %0) local_unnamed_addr {51; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)52; CHECK-LABEL: define {{[^@]+}}@test3_253; CHECK-SAME: (ptr nofree noundef readnone dereferenceable_or_null(32) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {54; CHECK-NEXT: [[RET:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 455; CHECK-NEXT: ret ptr [[RET]]56;57 %ret = getelementptr inbounds i32, ptr %0, i64 458 ret ptr %ret59}60 61define ptr @test3_3(ptr dereferenceable(8) %0, ptr dereferenceable(16) %1, i1 %2) local_unnamed_addr {62; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)63; CHECK-LABEL: define {{[^@]+}}@test3_364; CHECK-SAME: (ptr nofree noundef nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]], ptr nofree noundef nonnull readnone dereferenceable(16) "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]]) local_unnamed_addr #[[ATTR0]] {65; CHECK-NEXT: [[RET1:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 166; CHECK-NEXT: [[RET2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 267; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP2]], ptr [[RET1]], ptr [[RET2]]68; CHECK-NEXT: ret ptr [[RET]]69;70 %ret1 = getelementptr inbounds i32, ptr %0, i64 171 %ret2 = getelementptr inbounds i32, ptr %1, i64 272 %ret = select i1 %2, ptr %ret1, ptr %ret273 ret ptr %ret74}75 76; TEST 477; Better than known in IR.78 79define dereferenceable(4) ptr @test4(ptr dereferenceable(8) %0) local_unnamed_addr {80; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)81; CHECK-LABEL: define {{[^@]+}}@test482; CHECK-SAME: (ptr nofree noundef nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {83; CHECK-NEXT: ret ptr [[TMP0]]84;85 ret ptr %086}87 88; TEST 589; loop in which dereferenceabily "grows"90define void @deref_phi_growing(ptr dereferenceable(4000) %a) {91; CHECK-LABEL: define {{[^@]+}}@deref_phi_growing92; CHECK-SAME: (ptr noundef nonnull dereferenceable(4000) [[A:%.*]]) {93; CHECK-NEXT: entry:94; CHECK-NEXT: br label [[FOR_COND:%.*]]95; CHECK: for.cond:96; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]97; CHECK-NEXT: [[A_ADDR_0:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]98; CHECK-NEXT: call void @deref_phi_user(ptr nonnull [[A_ADDR_0]])99; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[A_ADDR_0]], align 4100; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[VAL]]101; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]102; CHECK: for.cond.cleanup:103; CHECK-NEXT: br label [[FOR_END:%.*]]104; CHECK: for.body:105; CHECK-NEXT: br label [[FOR_INC]]106; CHECK: for.inc:107; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i32, ptr [[A_ADDR_0]], i64 -1108; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1109; CHECK-NEXT: br label [[FOR_COND]]110; CHECK: for.end:111; CHECK-NEXT: ret void112;113entry:114 br label %for.cond115 116for.cond: ; preds = %for.inc, %entry117 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]118 %a.addr.0 = phi ptr [ %a, %entry ], [ %incdec.ptr, %for.inc ]119 call void @deref_phi_user(ptr %a.addr.0)120 %val = load i32, ptr %a.addr.0, align 4121 %cmp = icmp slt i32 %i.0, %val122 br i1 %cmp, label %for.body, label %for.cond.cleanup123 124for.cond.cleanup: ; preds = %for.cond125 br label %for.end126 127for.body: ; preds = %for.cond128 br label %for.inc129 130for.inc: ; preds = %for.body131 %incdec.ptr = getelementptr inbounds i32, ptr %a.addr.0, i64 -1132 %inc = add nuw nsw i32 %i.0, 1133 br label %for.cond134 135for.end: ; preds = %for.cond.cleanup136 ret void137}138 139; TEST 6140; loop in which dereferenceabily "shrinks"141define void @deref_phi_shrinking(ptr dereferenceable(4000) %a) {142; CHECK-LABEL: define {{[^@]+}}@deref_phi_shrinking143; CHECK-SAME: (ptr noundef nonnull dereferenceable(4000) [[A:%.*]]) {144; CHECK-NEXT: entry:145; CHECK-NEXT: br label [[FOR_COND:%.*]]146; CHECK: for.cond:147; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]148; CHECK-NEXT: [[A_ADDR_0:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]149; CHECK-NEXT: call void @deref_phi_user(ptr nonnull [[A_ADDR_0]])150; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[A_ADDR_0]], align 4151; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[VAL]]152; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]153; CHECK: for.cond.cleanup:154; CHECK-NEXT: br label [[FOR_END:%.*]]155; CHECK: for.body:156; CHECK-NEXT: br label [[FOR_INC]]157; CHECK: for.inc:158; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i32, ptr [[A_ADDR_0]], i64 1159; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1160; CHECK-NEXT: br label [[FOR_COND]]161; CHECK: for.end:162; CHECK-NEXT: ret void163;164entry:165 br label %for.cond166 167for.cond: ; preds = %for.inc, %entry168 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]169 %a.addr.0 = phi ptr [ %a, %entry ], [ %incdec.ptr, %for.inc ]170 call void @deref_phi_user(ptr %a.addr.0)171 %val = load i32, ptr %a.addr.0, align 4172 %cmp = icmp slt i32 %i.0, %val173 br i1 %cmp, label %for.body, label %for.cond.cleanup174 175for.cond.cleanup: ; preds = %for.cond176 br label %for.end177 178for.body: ; preds = %for.cond179 br label %for.inc180 181for.inc: ; preds = %for.body182 %incdec.ptr = getelementptr inbounds i32, ptr %a.addr.0, i64 1183 %inc = add nuw nsw i32 %i.0, 1184 br label %for.cond185 186for.end: ; preds = %for.cond.cleanup187 ret void188}189 190; TEST 7191; share known infomation in must-be-executed-context192declare ptr @unkown_ptr() willreturn nounwind193declare i32 @unkown_f(ptr) willreturn nounwind194define ptr @f7_0(ptr %ptr) {195; CHECK: Function Attrs: mustprogress nounwind willreturn196; CHECK-LABEL: define {{[^@]+}}@f7_0197; CHECK-SAME: (ptr noundef nonnull returned dereferenceable(8) [[PTR:%.*]]) #[[ATTR2:[0-9]+]] {198; CHECK-NEXT: [[T:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull dereferenceable(8) [[PTR]]) #[[ATTR1:[0-9]+]]199; CHECK-NEXT: ret ptr [[PTR]]200;201 %T = tail call i32 @unkown_f(ptr dereferenceable(8) %ptr)202 ret ptr %ptr203}204 205define void @f7_1(ptr %ptr, i1 %cnd) {206; CHECK: Function Attrs: mustprogress nounwind willreturn207; CHECK-LABEL: define {{[^@]+}}@f7_1208; CHECK-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[PTR:%.*]], i1 noundef [[CND:%.*]]) #[[ATTR2]] {209; CHECK-NEXT: [[A:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]210; CHECK-NEXT: [[B:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]211; CHECK-NEXT: br i1 [[CND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]212; CHECK: if.true:213; CHECK-NEXT: [[C:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]214; CHECK-NEXT: [[D:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]215; CHECK-NEXT: [[E:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]216; CHECK-NEXT: ret void217; CHECK: if.false:218; CHECK-NEXT: ret void219;220 %A = tail call i32 @unkown_f(ptr %ptr)221 %ptr.0 = load i32, ptr %ptr222 ; deref 4 hold223; FIXME: this should be %B = tail call i32 @unkown_f(ptr nonnull dereferenceable(4) %ptr)224 %B = tail call i32 @unkown_f(ptr dereferenceable(1) %ptr)225 br i1%cnd, label %if.true, label %if.false226if.true:227 %C = tail call i32 @unkown_f(ptr %ptr)228 %D = tail call i32 @unkown_f(ptr dereferenceable(8) %ptr)229 %E = tail call i32 @unkown_f(ptr %ptr)230 ret void231if.false:232 ret void233}234 235define void @f7_2(i1 %cnd) {236; CHECK: Function Attrs: mustprogress nounwind willreturn237; CHECK-LABEL: define {{[^@]+}}@f7_2238; CHECK-SAME: (i1 noundef [[CND:%.*]]) #[[ATTR2]] {239; CHECK-NEXT: [[PTR:%.*]] = tail call nonnull align 4 dereferenceable(4) ptr @unkown_ptr() #[[ATTR1]]240; CHECK-NEXT: [[A:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]241; CHECK-NEXT: [[ARG_A_0:%.*]] = load i32, ptr [[PTR]], align 4242; CHECK-NEXT: [[B:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(4) [[PTR]]) #[[ATTR1]]243; CHECK-NEXT: br i1 [[CND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]244; CHECK: if.true:245; CHECK-NEXT: [[C:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]246; CHECK-NEXT: [[D:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]247; CHECK-NEXT: [[E:%.*]] = tail call i32 @unkown_f(ptr noundef nonnull align 4 dereferenceable(8) [[PTR]]) #[[ATTR1]]248; CHECK-NEXT: ret void249; CHECK: if.false:250; CHECK-NEXT: ret void251;252 %ptr = tail call ptr @unkown_ptr()253 %A = tail call i32 @unkown_f(ptr %ptr)254 %arg_a.0 = load i32, ptr %ptr255 ; deref 4 hold256 %B = tail call i32 @unkown_f(ptr dereferenceable(1) %ptr)257 br i1%cnd, label %if.true, label %if.false258if.true:259 %C = tail call i32 @unkown_f(ptr %ptr)260 %D = tail call i32 @unkown_f(ptr dereferenceable(8) %ptr)261 %E = tail call i32 @unkown_f(ptr %ptr)262 ret void263if.false:264 ret void265}266 267define ptr @f7_3() {268; CHECK: Function Attrs: mustprogress nounwind willreturn269; CHECK-LABEL: define {{[^@]+}}@f7_3270; CHECK-SAME: () #[[ATTR2]] {271; CHECK-NEXT: [[PTR:%.*]] = tail call noundef nonnull align 16 dereferenceable(4) ptr @unkown_ptr() #[[ATTR1]]272; CHECK-NEXT: store i32 10, ptr [[PTR]], align 16273; CHECK-NEXT: ret ptr [[PTR]]274;275 %ptr = tail call ptr @unkown_ptr()276 store i32 10, ptr %ptr, align 16277 ret ptr %ptr278}279 280; FIXME: This should have a return dereferenceable(8) but we need to make sure it will work in loops as well.281define ptr @test_for_minus_index(ptr %p) {282; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)283; CHECK-LABEL: define {{[^@]+}}@test_for_minus_index284; CHECK-SAME: (ptr nofree nonnull writeonly align 4 "no-capture-maybe-returned" [[P:%.*]]) #[[ATTR3:[0-9]+]] {285; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 -2286; CHECK-NEXT: store i32 1, ptr [[Q]], align 4287; CHECK-NEXT: ret ptr [[Q]]288;289 %q = getelementptr inbounds i32, ptr %p, i32 -2290 store i32 1, ptr %q291 ret ptr %q292}293 294define void @deref_or_null_and_nonnull(ptr dereferenceable_or_null(100) %0) {295; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)296; CHECK-LABEL: define {{[^@]+}}@deref_or_null_and_nonnull297; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(100) [[TMP0:%.*]]) #[[ATTR3]] {298; CHECK-NEXT: store i32 1, ptr [[TMP0]], align 4299; CHECK-NEXT: ret void300;301 store i32 1, ptr %0302 ret void303}304 305; TEST 8306; Use Constant range in deereferenceable307; void g(int *p, long long int *range){308; int r = *range ; // [10, 99]309; fill_range(p, *range);310; }311 312; FIXME: %ptr should be dereferenceable(31)313define void @test8(ptr %ptr) #0 {314; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)315; CHECK-LABEL: define {{[^@]+}}@test8316; CHECK-SAME: (ptr nofree nonnull writeonly captures(none) dereferenceable(21) [[PTR:%.*]]) #[[ATTR3]] {317; CHECK-NEXT: br label [[TMP1:%.*]]318; CHECK: 1:319; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]320; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[I_0]] to i64321; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[TMP2]]322; CHECK-NEXT: store i8 32, ptr [[TMP3]], align 1323; CHECK-NEXT: [[TMP4]] = add nsw i32 [[I_0]], 1324; CHECK-NEXT: br label [[TMP5]]325; CHECK: 5:326; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30327; CHECK-NEXT: br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]328; CHECK: 7:329; CHECK-NEXT: ret void330;331 br label %13321: ; preds = %5, %0333 %i.0 = phi i32 [ 20, %0 ], [ %4, %5 ]334 %2 = sext i32 %i.0 to i64335 %3 = getelementptr inbounds i8, ptr %ptr, i64 %2336 store i8 32, ptr %3, align 1337 %4 = add nsw i32 %i.0, 1338 br label %53395: ; preds = %1340 %6 = icmp slt i32 %4, 30341 br i1 %6, label %1, label %7342 3437: ; preds = %5344 ret void345}346 347; 8.2 (negative case)348define void @test8_neg(i32 %i, ptr %ptr) #0 {349; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)350; CHECK-LABEL: define {{[^@]+}}@test8_neg351; CHECK-SAME: (i32 [[I:%.*]], ptr nofree nonnull writeonly captures(none) [[PTR:%.*]]) #[[ATTR3]] {352; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[I]] to i64353; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[TMP1]]354; CHECK-NEXT: store i8 65, ptr [[TMP2]], align 1355; CHECK-NEXT: ret void356;357 %1 = sext i32 %i to i64358 %2 = getelementptr inbounds i8, ptr %ptr, i64 %1359 store i8 65, ptr %2, align 1360 ret void361}362 363; void fill_range(int* p, long long int start){364; for(long long int i = start;i<start+10;i++){365; // If p[i] is inbounds, p is dereferenceable(40) at least.366; p[i] = i;367; }368; }369 370; NOTE: %p should not be dereferenceable371define internal void @fill_range_not_inbounds(ptr %p, i64 %start){372; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)373; CHECK-LABEL: define {{[^@]+}}@fill_range_not_inbounds374; CHECK-SAME: (ptr nofree writeonly captures(none) [[P:%.*]], i64 [[START:%.*]]) #[[ATTR3]] {375; CHECK-NEXT: entry:376; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9377; CHECK-NEXT: br label [[FOR_BODY:%.*]]378; CHECK: for.cond.cleanup:379; CHECK-NEXT: ret void380; CHECK: for.body:381; CHECK-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]382; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32383; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, ptr [[P]], i64 [[I_06]]384; CHECK-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4385; CHECK-NEXT: [[INC]] = add nsw i64 [[I_06]], 1386; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]387; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]388;389entry:390 %0 = add nsw i64 %start, 9391 br label %for.body392 393for.cond.cleanup: ; preds = %for.body394 ret void395 396for.body: ; preds = %entry, %for.body397 %i.06 = phi i64 [ %start, %entry ], [ %inc, %for.body ]398 %conv = trunc i64 %i.06 to i32399 %arrayidx = getelementptr i32, ptr %p, i64 %i.06400 store i32 %conv, ptr %arrayidx, align 4401 %inc = add nsw i64 %i.06, 1402 %cmp = icmp slt i64 %i.06, %0403 br i1 %cmp, label %for.body, label %for.cond.cleanup404}405 406; FIXME: %p should be dereferenceable(40)407define internal void @fill_range_inbounds(ptr %p, i64 %start){408; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)409; CHECK-LABEL: define {{[^@]+}}@fill_range_inbounds410; CHECK-SAME: (ptr nofree writeonly captures(none) [[P:%.*]], i64 [[START:%.*]]) #[[ATTR3]] {411; CHECK-NEXT: entry:412; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9413; CHECK-NEXT: br label [[FOR_BODY:%.*]]414; CHECK: for.cond.cleanup:415; CHECK-NEXT: ret void416; CHECK: for.body:417; CHECK-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]418; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32419; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[I_06]]420; CHECK-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4421; CHECK-NEXT: [[INC]] = add nsw i64 [[I_06]], 1422; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]423; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]424;425entry:426 %0 = add nsw i64 %start, 9427 br label %for.body428 429for.cond.cleanup: ; preds = %for.body430 ret void431 432for.body: ; preds = %entry, %for.body433 %i.06 = phi i64 [ %start, %entry ], [ %inc, %for.body ]434 %conv = trunc i64 %i.06 to i32435 %arrayidx = getelementptr inbounds i32, ptr %p, i64 %i.06436 store i32 %conv, ptr %arrayidx, align 4437 %inc = add nsw i64 %i.06, 1438 %cmp = icmp slt i64 %i.06, %0439 br i1 %cmp, label %for.body, label %for.cond.cleanup440}441 442define void @call_fill_range(ptr nocapture %p, ptr nocapture readonly %range) {443; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)444; TUNIT-LABEL: define {{[^@]+}}@call_fill_range445; TUNIT-SAME: (ptr nofree writeonly captures(none) [[P:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[RANGE:%.*]]) #[[ATTR4:[0-9]+]] {446; TUNIT-NEXT: entry:447; TUNIT-NEXT: [[TMP0:%.*]] = load i64, ptr [[RANGE]], align 8, !range [[RNG0:![0-9]+]]448; TUNIT-NEXT: tail call void @fill_range_inbounds(ptr nofree writeonly captures(none) [[P]], i64 [[TMP0]]) #[[ATTR7:[0-9]+]]449; TUNIT-NEXT: tail call void @fill_range_not_inbounds(ptr nofree writeonly captures(none) [[P]], i64 [[TMP0]]) #[[ATTR7]]450; TUNIT-NEXT: ret void451;452; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)453; CGSCC-LABEL: define {{[^@]+}}@call_fill_range454; CGSCC-SAME: (ptr nofree writeonly captures(none) [[P:%.*]], ptr nofree noundef nonnull readonly align 8 captures(none) dereferenceable(8) [[RANGE:%.*]]) #[[ATTR4:[0-9]+]] {455; CGSCC-NEXT: entry:456; CGSCC-NEXT: [[TMP0:%.*]] = load i64, ptr [[RANGE]], align 8, !range [[RNG0:![0-9]+]]457; CGSCC-NEXT: tail call void @fill_range_inbounds(ptr nofree writeonly captures(none) [[P]], i64 [[TMP0]]) #[[ATTR7:[0-9]+]]458; CGSCC-NEXT: tail call void @fill_range_not_inbounds(ptr nofree writeonly captures(none) [[P]], i64 [[TMP0]]) #[[ATTR7]]459; CGSCC-NEXT: ret void460;461entry:462 %0 = load i64, ptr %range, align 8, !range !0463 tail call void @fill_range_inbounds(ptr %p, i64 %0)464 tail call void @fill_range_not_inbounds(ptr %p, i64 %0)465 ret void466}467 468declare void @use0() willreturn nounwind469declare void @use1(ptr) willreturn nounwind470declare void @use2(ptr, ptr) willreturn nounwind471declare void @use3(ptr, ptr, ptr) willreturn nounwind472 473; simple path test474; if(..)475; fun2(dereferenceable(8) %a, dereferenceable(8) %b)476; else477; fun2(dereferenceable(4) %a, %b)478; We can say that %a is dereferenceable(4) but %b is not.479define void @simple-path(ptr %a, ptr %b, i8 %c) {480; CHECK: Function Attrs: mustprogress nounwind willreturn481; CHECK-LABEL: define {{[^@]+}}@simple-path482; CHECK-SAME: (ptr nonnull dereferenceable(4) [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR2]] {483; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0484; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]485; CHECK: if.then:486; CHECK-NEXT: tail call void @use2(ptr nonnull dereferenceable(8) [[A]], ptr nonnull dereferenceable(8) [[B]]) #[[ATTR1]]487; CHECK-NEXT: ret void488; CHECK: if.else:489; CHECK-NEXT: tail call void @use2(ptr nonnull dereferenceable(4) [[A]], ptr [[B]]) #[[ATTR1]]490; CHECK-NEXT: ret void491;492 %cmp = icmp eq i8 %c, 0493 br i1 %cmp, label %if.then, label %if.else494if.then:495 tail call void @use2(ptr dereferenceable(8) %a, ptr dereferenceable(8) %b)496 ret void497if.else:498 tail call void @use2(ptr dereferenceable(4) %a, ptr %b)499 ret void500}501 502; More complex test503; {504; fun1(dereferenceable(4) %a)505; if(..)506; ... (willreturn & nounwind)507; fun1(dereferenceable(12) %a)508; else509; ... (willreturn & nounwind)510; fun1(dereferenceable(16) %a)511; fun1(dereferenceable(8) %a)512; }513; %a is dereferenceable(12)514define void @complex-path(ptr %a, ptr %b, i8 %c) {515; CHECK: Function Attrs: mustprogress nounwind willreturn516; CHECK-LABEL: define {{[^@]+}}@complex-path517; CHECK-SAME: (ptr noundef nonnull dereferenceable(12) [[A:%.*]], ptr nofree readnone captures(none) [[B:%.*]], i8 [[C:%.*]]) #[[ATTR2]] {518; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0519; CHECK-NEXT: tail call void @use1(ptr noundef nonnull dereferenceable(12) [[A]]) #[[ATTR1]]520; CHECK-NEXT: br i1 [[CMP]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]521; CHECK: cont.then:522; CHECK-NEXT: tail call void @use1(ptr noundef nonnull dereferenceable(12) [[A]]) #[[ATTR1]]523; CHECK-NEXT: br label [[CONT2:%.*]]524; CHECK: cont.else:525; CHECK-NEXT: tail call void @use1(ptr noundef nonnull dereferenceable(16) [[A]]) #[[ATTR1]]526; CHECK-NEXT: br label [[CONT2]]527; CHECK: cont2:528; CHECK-NEXT: tail call void @use1(ptr noundef nonnull dereferenceable(12) [[A]]) #[[ATTR1]]529; CHECK-NEXT: ret void530;531 %cmp = icmp eq i8 %c, 0532 tail call void @use1(ptr dereferenceable(4) %a)533 br i1 %cmp, label %cont.then, label %cont.else534cont.then:535 tail call void @use1(ptr dereferenceable(12) %a)536 br label %cont2537cont.else:538 tail call void @use1(ptr dereferenceable(16) %a)539 br label %cont2540cont2:541 tail call void @use1(ptr dereferenceable(8) %a)542 ret void543}544 545; void rec-branch-1(int a, int b, int c, int *ptr) {546; if (a) {547; if (b)548; *ptr = 1;549; else550; *ptr = 2;551; } else {552; if (c)553; *ptr = 3;554; else555; *ptr = 4;556; }557; }558define dso_local void @rec-branch-1(i32 %a, i32 %b, i32 %c, ptr %ptr) {559; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)560; CHECK-LABEL: define {{[^@]+}}@rec-branch-1561; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(4) [[PTR:%.*]]) #[[ATTR3]] {562; CHECK-NEXT: entry:563; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0564; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]565; CHECK: if.then:566; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0567; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]568; CHECK: if.then2:569; CHECK-NEXT: store i32 1, ptr [[PTR]], align 4570; CHECK-NEXT: br label [[IF_END8:%.*]]571; CHECK: if.else:572; CHECK-NEXT: store i32 2, ptr [[PTR]], align 4573; CHECK-NEXT: br label [[IF_END8]]574; CHECK: if.else3:575; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0576; CHECK-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]577; CHECK: if.then5:578; CHECK-NEXT: store i32 3, ptr [[PTR]], align 4579; CHECK-NEXT: br label [[IF_END8]]580; CHECK: if.else6:581; CHECK-NEXT: store i32 4, ptr [[PTR]], align 4582; CHECK-NEXT: br label [[IF_END8]]583; CHECK: if.end8:584; CHECK-NEXT: ret void585;586entry:587 %tobool = icmp eq i32 %a, 0588 br i1 %tobool, label %if.else3, label %if.then589 590if.then: ; preds = %entry591 %tobool1 = icmp eq i32 %b, 0592 br i1 %tobool1, label %if.else, label %if.then2593 594if.then2: ; preds = %if.then595 store i32 1, ptr %ptr, align 4596 br label %if.end8597 598if.else: ; preds = %if.then599 store i32 2, ptr %ptr, align 4600 br label %if.end8601 602if.else3: ; preds = %entry603 %tobool4 = icmp eq i32 %c, 0604 br i1 %tobool4, label %if.else6, label %if.then5605 606if.then5: ; preds = %if.else3607 store i32 3, ptr %ptr, align 4608 br label %if.end8609 610if.else6: ; preds = %if.else3611 store i32 4, ptr %ptr, align 4612 br label %if.end8613 614if.end8: ; preds = %if.then5, %if.else6, %if.then2, %if.else615 ret void616}617 618; void rec-branch-2(int a, int b, int c, int *ptr) {619; if (a) {620; if (b)621; *ptr = 1;622; else623; *ptr = 2;624; } else {625; if (c)626; *ptr = 3;627; else628; rec-branch-2(1, 1, 1, ptr);629; }630; }631define dso_local void @rec-branch-2(i32 %a, i32 %b, i32 %c, ptr %ptr) {632; CHECK: Function Attrs: nofree nosync nounwind memory(argmem: write)633; CHECK-LABEL: define {{[^@]+}}@rec-branch-2634; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(4) [[PTR:%.*]]) #[[ATTR5:[0-9]+]] {635; CHECK-NEXT: entry:636; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0637; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]638; CHECK: if.then:639; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0640; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]641; CHECK: if.then2:642; CHECK-NEXT: store i32 1, ptr [[PTR]], align 4643; CHECK-NEXT: br label [[IF_END8:%.*]]644; CHECK: if.else:645; CHECK-NEXT: store i32 2, ptr [[PTR]], align 4646; CHECK-NEXT: br label [[IF_END8]]647; CHECK: if.else3:648; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0649; CHECK-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]650; CHECK: if.then5:651; CHECK-NEXT: store i32 3, ptr [[PTR]], align 4652; CHECK-NEXT: br label [[IF_END8]]653; CHECK: if.else6:654; CHECK-NEXT: tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, ptr nofree nonnull writeonly align 4 captures(none) dereferenceable(4) [[PTR]]) #[[ATTR8:[0-9]+]]655; CHECK-NEXT: br label [[IF_END8]]656; CHECK: if.end8:657; CHECK-NEXT: ret void658;659entry:660 %tobool = icmp eq i32 %a, 0661 br i1 %tobool, label %if.else3, label %if.then662 663if.then: ; preds = %entry664 %tobool1 = icmp eq i32 %b, 0665 br i1 %tobool1, label %if.else, label %if.then2666 667if.then2: ; preds = %if.then668 store i32 1, ptr %ptr, align 4669 br label %if.end8670 671if.else: ; preds = %if.then672 store i32 2, ptr %ptr, align 4673 br label %if.end8674 675if.else3: ; preds = %entry676 %tobool4 = icmp eq i32 %c, 0677 br i1 %tobool4, label %if.else6, label %if.then5678 679if.then5: ; preds = %if.else3680 store i32 3, ptr %ptr, align 4681 br label %if.end8682 683if.else6: ; preds = %if.else3684 tail call void @rec-branch-2(i32 1, i32 1, i32 1, ptr %ptr)685 br label %if.end8686 687if.end8: ; preds = %if.then5, %if.else6, %if.then2, %if.else688 ret void689}690 691declare void @unknown()692define void @nonnull_assume_pos(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {693; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos694; ATTRIBUTOR-SAME: (ptr nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], ptr nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], ptr nocapture nofree nonnull readnone [[ARG3:%.*]], ptr nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]])695; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) #6 [ "nonnull"(ptr undef), "dereferenceable"(ptr undef, i64 1), "dereferenceable"(ptr undef, i64 2), "dereferenceable"(ptr undef, i64 101), "dereferenceable_or_null"(ptr undef, i64 31), "dereferenceable_or_null"(ptr undef, i64 42) ]696; ATTRIBUTOR-NEXT: call void @unknown()697; ATTRIBUTOR-NEXT: ret void698;699; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_pos700; CHECK-SAME: (ptr nofree nonnull readnone captures(none) dereferenceable(101) [[ARG1:%.*]], ptr nofree readnone captures(none) dereferenceable_or_null(31) [[ARG2:%.*]], ptr nofree nonnull readnone captures(none) [[ARG3:%.*]], ptr nofree readnone captures(none) dereferenceable_or_null(42) [[ARG4:%.*]]) {701; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR9:[0-9]+]] [ "nonnull"(ptr [[ARG3]]), "dereferenceable"(ptr [[ARG1]], i64 1), "dereferenceable"(ptr [[ARG1]], i64 2), "dereferenceable"(ptr [[ARG1]], i64 101), "dereferenceable_or_null"(ptr [[ARG2]], i64 31), "dereferenceable_or_null"(ptr [[ARG4]], i64 42) ]702; CHECK-NEXT: call void @unknown()703; CHECK-NEXT: ret void704;705 call void @llvm.assume(i1 true) [ "nonnull"(ptr %arg3), "dereferenceable"(ptr %arg1, i64 1), "dereferenceable"(ptr %arg1, i64 2), "dereferenceable"(ptr %arg1, i64 101), "dereferenceable_or_null"(ptr %arg2, i64 31), "dereferenceable_or_null"(ptr %arg4, i64 42)]706 call void @unknown()707 ret void708}709define void @nonnull_assume_neg(ptr %arg1, ptr %arg2, ptr %arg3) {710; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg711; ATTRIBUTOR-SAME: (ptr nocapture nofree readnone [[ARG1:%.*]], ptr nocapture nofree readnone [[ARG2:%.*]], ptr nocapture nofree readnone [[ARG3:%.*]])712; ATTRIBUTOR-NEXT: call void @unknown()713; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr undef, i64 101), "dereferenceable"(ptr undef, i64 -2), "dereferenceable_or_null"(ptr undef, i64 31) ]714; ATTRIBUTOR-NEXT: ret void715;716; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg717; CHECK-SAME: (ptr nofree readnone captures(none) [[ARG1:%.*]], ptr nofree readnone captures(none) [[ARG2:%.*]], ptr nofree readnone captures(none) [[ARG3:%.*]]) {718; CHECK-NEXT: call void @unknown()719; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "dereferenceable"(ptr [[ARG1]], i64 101), "dereferenceable"(ptr [[ARG2]], i64 -2), "dereferenceable_or_null"(ptr [[ARG3]], i64 31) ]720; CHECK-NEXT: ret void721;722 call void @unknown()723 call void @llvm.assume(i1 true) ["dereferenceable"(ptr %arg1, i64 101), "dereferenceable"(ptr %arg2, i64 -2), "dereferenceable_or_null"(ptr %arg3, i64 31)]724 ret void725}726define void @nonnull_assume_call(ptr %arg1, ptr %arg2, ptr %arg3, ptr %arg4) {727; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call728; ATTRIBUTOR-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]])729; ATTRIBUTOR-NEXT: call void @unknown()730; ATTRIBUTOR-NEXT: [[P:%.*]] = call nonnull dereferenceable(101) ptr @unkown_ptr()731; ATTRIBUTOR-NEXT: call void @unknown_use32(ptr nonnull dereferenceable(101) [[P]])732; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(42) [[ARG4]])733; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull [[ARG3]])734; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(31) [[ARG2]])735; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(2) [[ARG1]])736; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(ptr [[ARG3]]), "dereferenceable"(ptr [[ARG1]], i64 1), "dereferenceable"(ptr [[ARG1]], i64 2), "dereferenceable"(ptr [[P]], i64 101), "dereferenceable_or_null"(ptr [[ARG2]], i64 31), "dereferenceable_or_null"(ptr [[ARG4]], i64 42) ]737; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(2) [[ARG1]])738; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(31) [[ARG2]])739; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull [[ARG3]])740; ATTRIBUTOR-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(42) [[ARG4]])741; ATTRIBUTOR-NEXT: call void @unknown_use32(ptr nonnull dereferenceable(101) [[P]])742; ATTRIBUTOR-NEXT: call void @unknown()743; ATTRIBUTOR-NEXT: ret void744;745; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call746; CHECK-SAME: (ptr [[ARG1:%.*]], ptr [[ARG2:%.*]], ptr [[ARG3:%.*]], ptr [[ARG4:%.*]]) {747; CHECK-NEXT: call void @unknown()748; CHECK-NEXT: [[P:%.*]] = call nonnull dereferenceable(101) ptr @unkown_ptr() #[[ATTR10:[0-9]+]]749; CHECK-NEXT: call void @unknown_use32(ptr nonnull dereferenceable(101) [[P]]) #[[ATTR10]]750; CHECK-NEXT: call void @unknown_use8(ptr dereferenceable_or_null(42) [[ARG4]]) #[[ATTR10]]751; CHECK-NEXT: call void @unknown_use8(ptr nonnull [[ARG3]]) #[[ATTR10]]752; CHECK-NEXT: call void @unknown_use8(ptr dereferenceable_or_null(31) [[ARG2]]) #[[ATTR10]]753; CHECK-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(2) [[ARG1]]) #[[ATTR10]]754; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nonnull"(ptr [[ARG3]]), "dereferenceable"(ptr [[ARG1]], i64 1), "dereferenceable"(ptr [[ARG1]], i64 2), "dereferenceable"(ptr [[P]], i64 101), "dereferenceable_or_null"(ptr [[ARG2]], i64 31), "dereferenceable_or_null"(ptr [[ARG4]], i64 42) ]755; CHECK-NEXT: call void @unknown_use8(ptr nonnull dereferenceable(2) [[ARG1]]) #[[ATTR10]]756; CHECK-NEXT: call void @unknown_use8(ptr dereferenceable_or_null(31) [[ARG2]]) #[[ATTR10]]757; CHECK-NEXT: call void @unknown_use8(ptr nonnull [[ARG3]]) #[[ATTR10]]758; CHECK-NEXT: call void @unknown_use8(ptr dereferenceable_or_null(42) [[ARG4]]) #[[ATTR10]]759; CHECK-NEXT: call void @unknown_use32(ptr nonnull dereferenceable(101) [[P]]) #[[ATTR10]]760; CHECK-NEXT: call void @unknown()761; CHECK-NEXT: ret void762;763 call void @unknown()764 %p = call ptr @unkown_ptr()765 call void @unknown_use32(ptr %p)766 call void @unknown_use8(ptr %arg4)767 call void @unknown_use8(ptr %arg3)768 call void @unknown_use8(ptr %arg2)769 call void @unknown_use8(ptr %arg1)770 call void @llvm.assume(i1 true) [ "nonnull"(ptr %arg3), "dereferenceable"(ptr %arg1, i64 1), "dereferenceable"(ptr %arg1, i64 2), "dereferenceable"(ptr %p, i64 101), "dereferenceable_or_null"(ptr %arg2, i64 31), "dereferenceable_or_null"(ptr %arg4, i64 42)]771 call void @unknown_use8(ptr %arg1)772 call void @unknown_use8(ptr %arg2)773 call void @unknown_use8(ptr %arg3)774 call void @unknown_use8(ptr %arg4)775 call void @unknown_use32(ptr %p)776 call void @unknown()777 ret void778}779declare void @unknown_use8(ptr) willreturn nounwind780declare void @unknown_use32(ptr) willreturn nounwind781declare void @llvm.assume(i1)782 783@g = global i64 0784define void @max_offset(i1 %c) {785; CHECK: Function Attrs: mustprogress nounwind willreturn786; CHECK-LABEL: define {{[^@]+}}@max_offset787; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR2]] {788; CHECK-NEXT: entry:789; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]790; CHECK: t:791; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr @g, i64 2792; CHECK-NEXT: br label [[F]]793; CHECK: f:794; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[GEP]], [[T]] ], [ @g, [[ENTRY:%.*]] ]795; CHECK-NEXT: call void @unknown_use8(ptr noundef align 2 dereferenceable_or_null(6) [[PHI]]) #[[ATTR1]]796; CHECK-NEXT: ret void797;798entry:799 br i1 %c, label %t, label %f800t:801 %gep = getelementptr i8, ptr @g, i64 2802 br label %f803f:804 %phi = phi ptr [%gep, %t], [@g, %entry]805 call void @unknown_use8(ptr %phi)806 ret void807}808 809!0 = !{i64 10, i64 100}810 811;.812; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }813; TUNIT: attributes #[[ATTR1]] = { nounwind willreturn }814; TUNIT: attributes #[[ATTR2]] = { mustprogress nounwind willreturn }815; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }816; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }817; TUNIT: attributes #[[ATTR5]] = { nofree nosync nounwind memory(argmem: write) }818; TUNIT: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }819; TUNIT: attributes #[[ATTR7]] = { nofree nosync nounwind willreturn memory(write) }820; TUNIT: attributes #[[ATTR8]] = { nofree nosync nounwind memory(write) }821; TUNIT: attributes #[[ATTR9]] = { nofree willreturn memory(write) }822; TUNIT: attributes #[[ATTR10]] = { nounwind }823;.824; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }825; CGSCC: attributes #[[ATTR1]] = { nounwind willreturn }826; CGSCC: attributes #[[ATTR2]] = { mustprogress nounwind willreturn }827; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }828; CGSCC: attributes #[[ATTR4]] = { mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) }829; CGSCC: attributes #[[ATTR5]] = { nofree nosync nounwind memory(argmem: write) }830; CGSCC: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }831; CGSCC: attributes #[[ATTR7]] = { nofree nounwind willreturn memory(write) }832; CGSCC: attributes #[[ATTR8]] = { nofree nosync nounwind memory(write) }833; CGSCC: attributes #[[ATTR9]] = { nofree willreturn memory(write) }834; CGSCC: attributes #[[ATTR10]] = { nounwind }835;.836; TUNIT: [[RNG0]] = !{i64 10, i64 100}837;.838; CGSCC: [[RNG0]] = !{i64 10, i64 100}839;.840