1; RUN: opt < %s -debugify -gvn -S | FileCheck %s 2target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 3 4@a = common global [100 x i64] zeroinitializer, align 16 5@b = common global [100 x i64] zeroinitializer, align 16 6@g1 = common global i64 0, align 8 7@g2 = common global i64 0, align 8 8@g3 = common global i64 0, align 8 9declare i64 @goo(...) local_unnamed_addr #1 10 11define void @test1(i64 %a, i64 %b, i64 %c, i64 %d) { 12entry: 13 %mul = mul nsw i64 %b, %a 14 store i64 %mul, i64* @g1, align 8 15 %t0 = load i64, i64* @g2, align 8 16 %cmp = icmp sgt i64 %t0, 3 17 br i1 %cmp, label %if.then, label %if.end 18 19if.then: ; preds = %entry 20 %mul2 = mul nsw i64 %d, %c 21 store i64 %mul2, i64* @g2, align 8 22 br label %if.end 23 24; Check phi-translate works and mul is removed. 25; CHECK-LABEL: @test1( 26; CHECK: if.end: 27; CHECK: %[[MULPHI:.*]] = phi i64 [ {{.*}}, %if.then ], [ %mul, %entry ] 28; CHECK-NOT: = mul 29; CHECK: store i64 %[[MULPHI]], i64* @g3, align 8 30if.end: ; preds = %if.then, %entry 31 %b.addr.0 = phi i64 [ %d, %if.then ], [ %b, %entry ] 32 %a.addr.0 = phi i64 [ %c, %if.then ], [ %a, %entry ] 33 %mul3 = mul nsw i64 %a.addr.0, %b.addr.0 34 store i64 %mul3, i64* @g3, align 8 35 ret void 36} 37 38define void @test2(i64 %i) { 39entry: 40 %arrayidx = getelementptr inbounds [100 x i64], [100 x i64]* @a, i64 0, i64 %i 41 %t0 = load i64, i64* %arrayidx, align 8 42 %arrayidx1 = getelementptr inbounds [100 x i64], [100 x i64]* @b, i64 0, i64 %i 43 %t1 = load i64, i64* %arrayidx1, align 8 44 %mul = mul nsw i64 %t1, %t0 45 store i64 %mul, i64* @g1, align 8 46 %cmp = icmp sgt i64 %mul, 3 47 br i1 %cmp, label %if.then, label %if.end 48 49; Check phi-translate works for the phi generated by loadpre. A new mul will be 50; inserted in if.then block. 51; CHECK-LABEL: @test2( 52; CHECK: if.then: 53; CHECK: %[[MUL_THEN:.*]] = mul 54; CHECK: br label %if.end 55if.then: ; preds = %entry 56 %call = tail call i64 (...) @goo() #2 57 store i64 %call, i64* @g2, align 8 58 br label %if.end 59 60; CHECK: if.end: 61; CHECK: %[[MULPHI:.*]] = phi i64 [ %[[MUL_THEN]], %if.then ], [ %mul, %entry ] 62; CHECK-NOT: = mul 63; CHECK: store i64 %[[MULPHI]], i64* @g3, align 8 64if.end: ; preds = %if.then, %entry 65 %i.addr.0 = phi i64 [ 3, %if.then ], [ %i, %entry ] 66 %arrayidx3 = getelementptr inbounds [100 x i64], [100 x i64]* @a, i64 0, i64 %i.addr.0 67 %t2 = load i64, i64* %arrayidx3, align 8 68 %arrayidx4 = getelementptr inbounds [100 x i64], [100 x i64]* @b, i64 0, i64 %i.addr.0 69 %t3 = load i64, i64* %arrayidx4, align 8 70 %mul5 = mul nsw i64 %t3, %t2 71 store i64 %mul5, i64* @g3, align 8 72 ret void 73} 74 75; Check phi-translate doesn't go through backedge, which may lead to incorrect 76; pre transformation. 77; CHECK: for.end: 78; CHECK-NOT: %{{.*pre-phi}} = phi 79; CHECK: ret void 80define void @test3(i64 %N, i64* nocapture readonly %a) { 81entry: 82 br label %for.cond 83 84for.cond: ; preds = %for.body, %entry 85 %i.0 = phi i64 [ 0, %entry ], [ %add, %for.body ] 86 %add = add nuw nsw i64 %i.0, 1 87 %arrayidx = getelementptr inbounds i64, i64* %a, i64 %add 88 %tmp0 = load i64, i64* %arrayidx, align 8 89 %cmp = icmp slt i64 %i.0, %N 90 br i1 %cmp, label %for.body, label %for.end 91 92for.body: ; preds = %for.cond 93 %call = tail call i64 (...) @goo() #2 94 %add1 = sub nsw i64 0, %call 95 %tobool = icmp eq i64 %tmp0, %add1 96 br i1 %tobool, label %for.cond, label %for.end 97 98for.end: ; preds = %for.body, %for.cond 99 %i.0.lcssa = phi i64 [ %i.0, %for.body ], [ %i.0, %for.cond ] 100 %arrayidx2 = getelementptr inbounds i64, i64* %a, i64 %i.0.lcssa 101 %tmp1 = load i64, i64* %arrayidx2, align 8 102 store i64 %tmp1, i64* @g1, align 8 103 ret void 104} 105 106; It is incorrect to use the value of %andres in last loop iteration 107; to do pre. 108; CHECK-LABEL: @test4( 109; CHECK: for.body: 110; CHECK-NOT: %andres.pre-phi = phi i32 111; CHECK: br i1 %tobool1 112 113define i32 @test4(i32 %cond, i32 %SectionAttrs.0231.ph, i32 *%AttrFlag) { 114for.body.preheader: 115 %t514 = load volatile i32, i32* %AttrFlag 116 br label %for.body 117 118for.body: 119 %t320 = phi i32 [ %t334, %bb343 ], [ %t514, %for.body.preheader ] 120 %andres = and i32 %t320, %SectionAttrs.0231.ph 121 %tobool1 = icmp eq i32 %andres, 0 122 br i1 %tobool1, label %bb343, label %critedge.loopexit 123 124bb343: 125 %t334 = load volatile i32, i32* %AttrFlag 126 %tobool2 = icmp eq i32 %cond, 0 127 br i1 %tobool2, label %critedge.loopexit, label %for.body 128 129critedge.loopexit: 130 unreachable 131} 132 133; Check sub expression will be pre transformed. 134; CHECK-LABEL: @test5( 135; CHECK: entry: 136; CHECK: %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast 137; CHECK: br i1 %cmp 138; CHECK: if.then2: 139; CHECK: %[[PTRTOINT:.*]] = ptrtoint i32* %add.ptr to i64 140; CHECK: %[[SUB:.*]] = sub i64 %sub.ptr.lhs.cast, %[[PTRTOINT]] 141; CHECK: br label %if.end3 142; CHECK: if.end3: 143; CHECK: %[[PREPHI:.*]] = phi i64 [ %sub.ptr.sub, %if.else ], [ %[[SUB]], %if.then2 ], [ %sub.ptr.sub, %entry ] 144; CHECK: call void @llvm.dbg.value(metadata i32* %p.0, metadata [[var_p0:![0-9]+]], metadata !DIExpression()) 145; CHECK: call void @llvm.dbg.value(metadata i64 %sub.ptr.rhs.cast5.pre-phi, metadata [[var_sub_ptr:![0-9]+]], metadata !DIExpression()) 146; CHECK: %[[DIV:.*]] = ashr exact i64 %[[PREPHI]], 2 147; CHECK: ret i64 %[[DIV]] 148 149declare void @bar(...) local_unnamed_addr #1 150 151; Function Attrs: nounwind uwtable 152define i64 @test5(i32* %start, i32* %e, i32 %n1, i32 %n2) local_unnamed_addr #0 { 153entry: 154 %sub.ptr.lhs.cast = ptrtoint i32* %e to i64 155 %sub.ptr.rhs.cast = ptrtoint i32* %start to i64 156 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast 157 %cmp = icmp sgt i64 %sub.ptr.sub, 4000 158 br i1 %cmp, label %if.then, label %if.end3 159 160if.then: ; preds = %entry 161 %cmp1 = icmp sgt i32 %n1, %n2 162 br i1 %cmp1, label %if.then2, label %if.else 163 164if.then2: ; preds = %if.then 165 %add.ptr = getelementptr inbounds i32, i32* %start, i64 800 166 br label %if.end3 167 168if.else: ; preds = %if.then 169 tail call void (...) @bar() #2 170 br label %if.end3 171 172if.end3: ; preds = %if.then2, %if.else, %entry 173 %p.0 = phi i32* [ %add.ptr, %if.then2 ], [ %start, %if.else ], [ %start, %entry ] 174 %sub.ptr.rhs.cast5 = ptrtoint i32* %p.0 to i64 175 %sub.ptr.sub6 = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast5 176 %sub.ptr.div7 = ashr exact i64 %sub.ptr.sub6, 2 177 ret i64 %sub.ptr.div7 178} 179 180; Here the load from arrayidx1 is partially redundant, but its value is 181; available in if.then. Check that we correctly phi-translate to the phi that 182; the load has been replaced with. 183; CHECK-LABEL: @test6 184define void @test6(i32* %ptr) { 185; CHECK: entry: 186; CHECK: %[[PREGEP:.*]] = getelementptr inbounds i32, i32* %ptr, i64 1 187; CHECK: %[[PRE:.*]] = load i32, i32* %[[PREGEP]] 188entry: 189 br label %while 190 191; CHECK: while: 192; CHECK: %[[PHI1:.*]] = phi i32 [ %[[PRE]], %entry ], [ %[[PHI2:.*]], %if.end ] 193; CHECK-NOT: load i32, i32* %arrayidx1 194; CHECK: %[[LOAD:.*]] = load i32, i32* %arrayidx2 195while: 196 %i = phi i64 [ 1, %entry ], [ %i.next, %if.end ] 197 %arrayidx1 = getelementptr inbounds i32, i32* %ptr, i64 %i 198 %0 = load i32, i32* %arrayidx1, align 4 199 %i.next = add nuw nsw i64 %i, 1 200 %arrayidx2 = getelementptr inbounds i32, i32* %ptr, i64 %i.next 201 %1 = load i32, i32* %arrayidx2, align 4 202 %cmp = icmp sgt i32 %0, %1 203 br i1 %cmp, label %if.then, label %if.end 204 205if.then: 206 store i32 %1, i32* %arrayidx1, align 4 207 store i32 %0, i32* %arrayidx2, align 4 208 br label %if.end 209 210; CHECK: if.then: 211; CHECK: %[[PHI2]] = phi i32 [ %[[PHI1]], %if.then ], [ %[[LOAD]], %while ] 212if.end: 213 br i1 undef, label %while.end, label %while 214 215while.end: 216 ret void 217} 218 219; CHECK: [[var_p0]] = !DILocalVariable 220; CHECK: [[var_sub_ptr]] = !DILocalVariable 221