246 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 52; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s3 4define void @test1(i32 %n) {5; CHECK-LABEL: define void @test1(6; CHECK-SAME: i32 [[N:%.*]]) {7; CHECK-NEXT: [[ENTRY:.*]]:8; CHECK-NEXT: br label %[[FOR_COND:.*]]9; CHECK: [[FOR_COND]]:10; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], %[[ENTRY]] ], [ [[SHR:%.*]], %[[FOR_BODY:.*]] ]11; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 112; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_END:.*]]13; CHECK: [[FOR_BODY]]:14; CHECK-NEXT: [[SHR]] = lshr i32 [[A]], 515; CHECK-NEXT: br label %[[FOR_COND]]16; CHECK: [[FOR_END]]:17; CHECK-NEXT: ret void18;19entry:20 br label %for.cond21 22for.cond: ; preds = %for.body, %entry23 %a = phi i32 [ %n, %entry ], [ %shr, %for.body ]24 %cmp = icmp sgt i32 %a, 125 br i1 %cmp, label %for.body, label %for.end26 27for.body: ; preds = %for.cond28 %shr = ashr i32 %a, 529 br label %for.cond30 31for.end: ; preds = %for.cond32 ret void33}34 35;; Negative test to show transform doesn't happen unless n > 0.36define void @test2(i32 %n) {37; CHECK-LABEL: define void @test2(38; CHECK-SAME: i32 [[N:%.*]]) {39; CHECK-NEXT: [[ENTRY:.*]]:40; CHECK-NEXT: br label %[[FOR_COND:.*]]41; CHECK: [[FOR_COND]]:42; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], %[[ENTRY]] ], [ [[SHR:%.*]], %[[FOR_BODY:.*]] ]43; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], -244; CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY]], label %[[FOR_END:.*]]45; CHECK: [[FOR_BODY]]:46; CHECK-NEXT: [[SHR]] = ashr i32 [[A]], 247; CHECK-NEXT: br label %[[FOR_COND]]48; CHECK: [[FOR_END]]:49; CHECK-NEXT: ret void50;51entry:52 br label %for.cond53 54for.cond: ; preds = %for.body, %entry55 %a = phi i32 [ %n, %entry ], [ %shr, %for.body ]56 %cmp = icmp sgt i32 %a, -257 br i1 %cmp, label %for.body, label %for.end58 59for.body: ; preds = %for.cond60 %shr = ashr i32 %a, 261 br label %for.cond62 63for.end: ; preds = %for.cond64 ret void65}66 67;; Non looping test case.68define void @test3(i32 %n) {69; CHECK-LABEL: define void @test3(70; CHECK-SAME: i32 [[N:%.*]]) {71; CHECK-NEXT: [[ENTRY:.*:]]72; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N]], 073; CHECK-NEXT: br i1 [[CMP]], label %[[BB:.*]], label %[[EXIT:.*]]74; CHECK: [[BB]]:75; CHECK-NEXT: [[SHR:%.*]] = lshr exact i32 [[N]], 476; CHECK-NEXT: br label %[[EXIT]]77; CHECK: [[EXIT]]:78; CHECK-NEXT: ret void79;80entry:81 %cmp = icmp sgt i32 %n, 082 br i1 %cmp, label %bb, label %exit83 84bb:85 %shr = ashr exact i32 %n, 486 br label %exit87 88exit:89 ret void90}91 92; looping case where loop has exactly one block93; at the point of ashr, we know that the operand is always greater than 0,94; because of the guard before it, so we can transform it to lshr.95declare void @llvm.experimental.guard(i1,...)96define void @test4(i32 %n) {97; CHECK-LABEL: define void @test4(98; CHECK-SAME: i32 [[N:%.*]]) {99; CHECK-NEXT: [[ENTRY:.*]]:100; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N]], 0101; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP:.*]], label %[[EXIT:.*]]102; CHECK: [[LOOP]]:103; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], %[[ENTRY]] ], [ [[SHR:%.*]], %[[LOOP]] ]104; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[A]], 2105; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND]]) [ "deopt"() ]106; CHECK-NEXT: [[SHR]] = lshr i32 [[A]], 1107; CHECK-NEXT: br i1 [[COND]], label %[[LOOP]], label %[[EXIT]]108; CHECK: [[EXIT]]:109; CHECK-NEXT: ret void110;111entry:112 %cmp = icmp sgt i32 %n, 0113 br i1 %cmp, label %loop, label %exit114 115loop:116 %a = phi i32 [ %n, %entry ], [ %shr, %loop ]117 %cond = icmp sgt i32 %a, 2118 call void(i1,...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]119 %shr = ashr i32 %a, 1120 br i1 %cond, label %loop, label %exit121 122exit:123 ret void124}125 126; same test as above with assume instead of guard.127declare void @llvm.assume(i1)128define void @test5(i32 %n) {129; CHECK-LABEL: define void @test5(130; CHECK-SAME: i32 [[N:%.*]]) {131; CHECK-NEXT: [[ENTRY:.*]]:132; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N]], 0133; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP:.*]], label %[[EXIT:.*]]134; CHECK: [[LOOP]]:135; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], %[[ENTRY]] ], [ [[SHR:%.*]], %[[LOOP]] ]136; CHECK-NEXT: [[COND:%.*]] = icmp samesign ugt i32 [[A]], 4137; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])138; CHECK-NEXT: [[SHR]] = lshr i32 [[A]], 1139; CHECK-NEXT: [[LOOPCOND:%.*]] = icmp samesign ugt i32 [[SHR]], 8140; CHECK-NEXT: br i1 [[LOOPCOND]], label %[[LOOP]], label %[[EXIT]]141; CHECK: [[EXIT]]:142; CHECK-NEXT: ret void143;144entry:145 %cmp = icmp sgt i32 %n, 0146 br i1 %cmp, label %loop, label %exit147 148loop:149 %a = phi i32 [ %n, %entry ], [ %shr, %loop ]150 %cond = icmp sgt i32 %a, 4151 call void @llvm.assume(i1 %cond)152 %shr = ashr i32 %a, 1153 %loopcond = icmp sgt i32 %shr, 8154 br i1 %loopcond, label %loop, label %exit155 156exit:157 ret void158}159 160; check that ashr of -1 or 0 is optimized away161define i32 @test6(i32 %f, i32 %g) {162; CHECK-LABEL: define range(i32 -1, 1) i32 @test6(163; CHECK-SAME: i32 [[F:%.*]], i32 [[G:%.*]]) {164; CHECK-NEXT: [[ENTRY:.*:]]165; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[F]], 1166; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 2167; CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP1]])168; CHECK-NEXT: ret i32 [[F]]169;170entry:171 %0 = add i32 %f, 1172 %1 = icmp ult i32 %0, 2173 tail call void @llvm.assume(i1 %1)174 %shr = ashr i32 %f, %g175 ret i32 %shr176}177 178; same test as above with different numbers179define i32 @test7(i32 %f, i32 %g) {180; CHECK-LABEL: define range(i32 -1, 1) i32 @test7(181; CHECK-SAME: i32 [[F:%.*]], i32 [[G:%.*]]) {182; CHECK-NEXT: [[ENTRY:.*:]]183; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[F]], -2184; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 6185; CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP1]])186; CHECK-NEXT: [[SUB:%.*]] = add nsw i32 [[F]], -7187; CHECK-NEXT: ret i32 [[SUB]]188;189entry:190 %0 = and i32 %f, -2191 %1 = icmp eq i32 %0, 6192 tail call void @llvm.assume(i1 %1)193 %sub = add nsw i32 %f, -7194 %shr = ashr i32 %sub, %g195 ret i32 %shr196}197 198; check that ashr of -2 or 1 is not optimized away199define i32 @test8(i32 %f, i32 %g, i1 %s) {200; CHECK-LABEL: define range(i32 -2, 2) i32 @test8(201; CHECK-SAME: i32 [[F:%.*]], i32 [[G:%.*]], i1 [[S:%.*]]) {202; CHECK-NEXT: [[ENTRY:.*:]]203; CHECK-NEXT: [[TMP0:%.*]] = ashr i32 -2, [[F]]204; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 1, [[G]]205; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[S]], i32 [[TMP0]], i32 [[TMP1]]206; CHECK-NEXT: ret i32 [[TMP2]]207;208entry:209 %0 = ashr i32 -2, %f210 %1 = ashr i32 1, %g211 %2 = select i1 %s, i32 %0, i32 %1212 ret i32 %2213}214 215define i32 @may_including_undef(i1 %c.1, i1 %c.2) {216; CHECK-LABEL: define range(i32 -1073741824, 1073741824) i32 @may_including_undef(217; CHECK-SAME: i1 [[C_1:%.*]], i1 [[C_2:%.*]]) {218; CHECK-NEXT: br i1 [[C_1]], label %[[TRUE_1:.*]], label %[[FALSE:.*]]219; CHECK: [[TRUE_1]]:220; CHECK-NEXT: br i1 [[C_2]], label %[[TRUE_2:.*]], label %[[EXIT:.*]]221; CHECK: [[TRUE_2]]:222; CHECK-NEXT: br label %[[EXIT]]223; CHECK: [[FALSE]]:224; CHECK-NEXT: br label %[[EXIT]]225; CHECK: [[EXIT]]:226; CHECK-NEXT: [[P:%.*]] = phi i32 [ 2, %[[TRUE_1]] ], [ 4, %[[TRUE_2]] ], [ undef, %[[FALSE]] ]227; CHECK-NEXT: [[R:%.*]] = ashr i32 [[P]], 1228; CHECK-NEXT: ret i32 [[R]]229;230 br i1 %c.1, label %true.1, label %false231 232true.1:233 br i1 %c.2, label %true.2, label %exit234 235true.2:236 br label %exit237 238false:239 br label %exit240 241exit:242 %p = phi i32 [ 2, %true.1 ], [ 4, %true.2], [ undef, %false ]243 %r = ashr i32 %p, 1244 ret i32 %r245}246