1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals 2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC 4 5define i8 @test1(i32 %a, i32 %length) { 6; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 7; CHECK-LABEL: define {{[^@]+}}@test1 8; CHECK-SAME: (i32 [[A:%.*]], i32 [[LENGTH:%.*]]) #[[ATTR0:[0-9]+]] { 9; CHECK-NEXT: entry: 10; CHECK-NEXT: br label [[LOOP:%.*]] 11; CHECK: loop: 12; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 13; CHECK-NEXT: br label [[BACKEDGE]] 14; CHECK: backedge: 15; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1 16; CHECK-NEXT: [[CONT:%.*]] = icmp slt i32 [[IV_NEXT]], 400 17; CHECK-NEXT: br i1 [[CONT]], label [[LOOP]], label [[EXIT:%.*]] 18; CHECK: exit: 19; CHECK-NEXT: ret i8 0 20; 21entry: 22 br label %loop 23 24loop: 25 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 26 %cnd = icmp sge i32 %iv, 0 27 br i1 %cnd, label %backedge, label %exit 28 29backedge: 30 %iv.next = add nsw i32 %iv, 1 31 %cont = icmp slt i32 %iv.next, 400 32 br i1 %cont, label %loop, label %exit 33 34exit: 35 ret i8 0 36} 37 38define i8 @test2(i32 %n) { 39; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 40; CHECK-LABEL: define {{[^@]+}}@test2 41; CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR0]] { 42; CHECK-NEXT: entry: 43; CHECK-NEXT: br label [[LOOP:%.*]] 44; CHECK: loop: 45; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 46; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ [[IV2_NEXT:%.*]], [[BACKEDGE]] ] 47; CHECK-NEXT: [[CND2:%.*]] = icmp sgt i32 [[IV2]], 0 48; CHECK-NEXT: br i1 [[CND2]], label [[BACKEDGE]], label [[EXIT:%.*]] 49; CHECK: backedge: 50; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1 51; CHECK-NEXT: [[IV2_NEXT]] = sub nsw i32 [[IV2]], 1 52; CHECK-NEXT: [[CONT1:%.*]] = icmp slt i32 [[IV_NEXT]], 400 53; CHECK-NEXT: [[CONT2:%.*]] = icmp sgt i32 [[IV2_NEXT]], 0 54; CHECK-NEXT: [[CONT:%.*]] = and i1 [[CONT1]], [[CONT2]] 55; CHECK-NEXT: br i1 [[CONT]], label [[LOOP]], label [[EXIT]] 56; CHECK: exit: 57; CHECK-NEXT: ret i8 0 58; 59entry: 60 br label %loop 61 62loop: 63 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 64 %iv2 = phi i32 [%n, %entry], [%iv2.next, %backedge] 65 66 %cnd1 = icmp sge i32 %iv, 0 67 %cnd2 = icmp sgt i32 %iv2, 0 68 %cnd = and i1 %cnd1, %cnd2 69 br i1 %cnd, label %backedge, label %exit 70 71backedge: 72 %iv.next = add nsw i32 %iv, 1 73 %iv2.next = sub nsw i32 %iv2, 1 74 %cont1 = icmp slt i32 %iv.next, 400 75 %cont2 = icmp sgt i32 %iv2.next, 0 76 %cont = and i1 %cont1, %cont2 77 br i1 %cont, label %loop, label %exit 78 79exit: 80 ret i8 0 81} 82 83; Merging cont block into do block. 84define i32 @test3(i32 %i, i1 %f, i32 %n) { 85; CHECK-LABEL: define {{[^@]+}}@test3 86; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]]) { 87; CHECK-NEXT: entry: 88; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[I]], -2134 89; CHECK-NEXT: br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]] 90; CHECK: exit: 91; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[I]], -42 92; CHECK-NEXT: br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]] 93; CHECK: cont: 94; CHECK-NEXT: [[COND_3:%.*]] = icmp sgt i32 [[I]], [[N]] 95; CHECK-NEXT: br i1 [[COND_3]], label [[EXIT2]], label [[EXIT]] 96; CHECK: do: 97; CHECK-NEXT: [[COND_0:%.*]] = icmp sgt i32 [[I]], 0 98; CHECK-NEXT: [[CONSUME:%.*]] = call i32 @consume(i1 [[COND_0]]) 99; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I]], 0 100; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND]]) [ "deopt"() ] 101; CHECK-NEXT: [[COND_2:%.*]] = icmp sgt i32 [[I]], 0 102; CHECK-NEXT: br i1 [[COND_2]], label [[EXIT]], label [[CONT:%.*]] 103; CHECK: exit2: 104; CHECK-NEXT: ret i32 30 105; 106entry: 107 %c = icmp ne i32 %i, -2134 108 br i1 %c, label %do, label %exit 109 110exit: 111 %c1 = icmp ne i32 %i, -42 112 br i1 %c1, label %exit2, label %exit 113 114; Here cont is merged to do and i is any value except -2134. 115; i is not the single value: zero. 116cont: 117 %cond.3 = icmp sgt i32 %i, %n 118 br i1 %cond.3, label %exit2, label %exit 119 120do: 121 %cond.0 = icmp sgt i32 %i, 0 122 %consume = call i32 @consume(i1 %cond.0) 123 %cond = icmp eq i32 %i, 0 124 call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] 125 %cond.2 = icmp sgt i32 %i, 0 126 br i1 %cond.2, label %exit, label %cont 127 128exit2: 129; LatticeVal for: 'i32 %i' is: constantrange<-2134, 1> 130 ret i32 30 131} 132 133; FIXME: We should be able to merge cont into do. 134; FIXME: COND should be replaced with false. This will be fixed by improving LVI. 135define i32 @test4(i32 %i, i1 %f, i32 %n) { 136; CHECK-LABEL: define {{[^@]+}}@test4 137; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]]) { 138; CHECK-NEXT: entry: 139; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[I]], -2134 140; CHECK-NEXT: br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]] 141; CHECK: exit: 142; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[I]], -42 143; CHECK-NEXT: br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]] 144; CHECK: cont: 145; CHECK-NEXT: call void @dummy(i1 [[F]]) #[[ATTR2:[0-9]+]] 146; CHECK-NEXT: br label [[EXIT2]] 147; CHECK: do: 148; CHECK-NEXT: call void @dummy(i1 [[F]]) #[[ATTR2]] 149; CHECK-NEXT: [[CONSUME:%.*]] = call i32 @exit() 150; CHECK-NEXT: call void @llvm.assume(i1 noundef [[F]]) 151; CHECK-NEXT: [[COND:%.*]] = icmp eq i1 [[F]], false 152; CHECK-NEXT: br i1 [[COND]], label [[EXIT]], label [[CONT:%.*]] 153; CHECK: exit2: 154; CHECK-NEXT: ret i32 30 155; 156entry: 157 %c = icmp ne i32 %i, -2134 158 br i1 %c, label %do, label %exit 159 160exit: ; preds = %do, %cont, %exit, %entry 161 %c1 = icmp ne i32 %i, -42 162 br i1 %c1, label %exit2, label %exit 163 164cont: ; preds = %do 165 call void @dummy(i1 %f) 166 br label %exit2 167 168do: ; preds = %entry 169 call void @dummy(i1 %f) 170 %consume = call i32 @exit() 171 call void @llvm.assume(i1 %f) 172 %cond = icmp eq i1 %f, false 173 br i1 %cond, label %exit, label %cont 174 175exit2: ; preds = %cont, %exit 176 ret i32 30 177} 178 179declare i32 @exit() 180declare i32 @consume(i1) 181declare void @llvm.assume(i1) nounwind 182declare void @dummy(i1) nounwind 183declare void @llvm.experimental.guard(i1, ...) 184;. 185; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 186; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } 187; CHECK: attributes #[[ATTR2]] = { nounwind } 188;. 189;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: 190; CGSCC: {{.*}} 191; TUNIT: {{.*}} 192