1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=gvn -S | FileCheck %s 3 4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:1" 5target triple = "x86_64-unknown-linux-gnu" 6 7declare void @llvm.memset.p0.i8(ptr, i8, i32, i1) 8declare void @foo(ptr) 9 10define i8 @test(i1 %cmp) { 11; CHECK-LABEL: @test( 12; CHECK-NEXT: entry: 13; CHECK-NEXT: [[P:%.*]] = alloca i8 14; CHECK-NEXT: store i8 5, ptr [[P]] 15; CHECK-NEXT: br label [[HEADER:%.*]] 16; CHECK: header: 17; CHECK-NEXT: [[V:%.*]] = phi i8 [ 5, [[ENTRY:%.*]] ], [ -5, [[ALIVE:%.*]] ] 18; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[I_INC:%.*]], [[ALIVE]] ] 19; CHECK-NEXT: br i1 [[CMP:%.*]], label [[ALIVE]], label [[DEAD:%.*]] 20; CHECK: dead: 21; CHECK-NEXT: call void @foo(ptr [[P]]) 22; CHECK-NEXT: [[I_1:%.*]] = add i8 [[I]], [[V]] 23; CHECK-NEXT: br label [[ALIVE]] 24; CHECK: alive: 25; CHECK-NEXT: [[I_2:%.*]] = phi i8 [ [[I]], [[HEADER]] ], [ [[I_1]], [[DEAD]] ] 26; CHECK-NEXT: store i8 -5, ptr [[P]] 27; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 1 [[P]], i8 0, i32 1, i1 false) 28; CHECK-NEXT: [[I_INC]] = add i8 [[I_2]], 1 29; CHECK-NEXT: [[CMP_LOOP:%.*]] = icmp ugt i8 [[I_INC]], 100 30; CHECK-NEXT: br i1 [[CMP_LOOP]], label [[EXIT:%.*]], label [[HEADER]] 31; CHECK: exit: 32; CHECK-NEXT: ret i8 0 33; 34 35entry: 36 %p = alloca i8 37 store i8 5, ptr %p 38 br label %header 39header: 40 %i = phi i8 [0, %entry], [%i.inc, %backedge] 41 br i1 %cmp, label %alive, label %dead 42dead: 43 call void @foo(ptr %p) 44 %v = load i8, ptr %p, !invariant.load !1 45 %i.1 = add i8 %i, %v 46 br label %alive 47alive: 48 %i.2 = phi i8 [%i, %header], [%i.1, %dead] 49 store i8 -5, ptr %p 50 br label %backedge 51backedge: 52 call void @llvm.memset.p0.i8(ptr align 1 %p, i8 0, i32 1, i1 false) 53 %i.inc = add i8 %i.2, 1 54 %cmp.loop = icmp ugt i8 %i.inc, 100 55 br i1 %cmp.loop, label %exit, label %header 56exit: 57 %res = load i8, ptr %p 58 ret i8 %res 59} 60 61; Check that first two loads are not optimized out while the one marked with 62; invariant.load reuses %res1 63define i8 @test2(i1 %cmp, ptr %p) { 64; CHECK-LABEL: @test2( 65; CHECK-NEXT: entry: 66; CHECK-NEXT: [[RES1:%.*]] = load i8, ptr [[P:%.*]], align 1 67; CHECK-NEXT: call void @foo(ptr [[P]]) 68; CHECK-NEXT: br i1 [[CMP:%.*]], label [[B2:%.*]], label [[B1:%.*]] 69; CHECK: b1: 70; CHECK-NEXT: [[RES2:%.*]] = load i8, ptr [[P]] 71; CHECK-NEXT: [[RES3:%.*]] = add i8 [[RES1]], [[RES2]] 72; CHECK-NEXT: br label [[ALIVE:%.*]] 73; CHECK: b2: 74; CHECK-NEXT: [[RES_DEAD:%.*]] = add i8 [[RES1]], [[RES1]] 75; CHECK-NEXT: br label [[ALIVE]] 76; CHECK: alive: 77; CHECK-NEXT: [[RES_PHI:%.*]] = phi i8 [ [[RES3]], [[B1]] ], [ [[RES_DEAD]], [[B2]] ] 78; CHECK-NEXT: ret i8 [[RES_PHI]] 79; 80 81entry: 82 %res1 = load i8, ptr %p 83 call void @foo(ptr %p) 84 br i1 %cmp, label %b2, label %b1 85b1: 86 %res2 = load i8, ptr %p 87 %res3 = add i8 %res1, %res2 88 br label %alive 89b2: 90 %v = load i8, ptr %p, !invariant.load !1 91 %res.dead = add i8 %v, %res1 92 br label %alive 93alive: 94 %res.phi = phi i8 [%res3, %b1], [%res.dead, %b2] 95 ret i8 %res.phi 96} 97 98; This is essentially the same test case as the above one but with %b1 and %b2 99; swapped in "br i1 %cmp, label %b1, label %b2" instruction. That helps us to 100; ensure that results doesn't depend on visiting order. 101define i8 @test3(i1 %cmp, ptr %p) { 102; CHECK-LABEL: @test3( 103; CHECK-NEXT: entry: 104; CHECK-NEXT: [[RES1:%.*]] = load i8, ptr [[P:%.*]], align 1 105; CHECK-NEXT: call void @foo(ptr [[P]]) 106; CHECK-NEXT: br i1 [[CMP:%.*]], label [[B1:%.*]], label [[B2:%.*]] 107; CHECK: b1: 108; CHECK-NEXT: [[RES2:%.*]] = load i8, ptr [[P]] 109; CHECK-NEXT: [[RES3:%.*]] = add i8 [[RES1]], [[RES2]] 110; CHECK-NEXT: br label [[ALIVE:%.*]] 111; CHECK: b2: 112; CHECK-NEXT: [[RES_DEAD:%.*]] = add i8 [[RES1]], [[RES1]] 113; CHECK-NEXT: br label [[ALIVE]] 114; CHECK: alive: 115; CHECK-NEXT: [[RES_PHI:%.*]] = phi i8 [ [[RES3]], [[B1]] ], [ [[RES_DEAD]], [[B2]] ] 116; CHECK-NEXT: ret i8 [[RES_PHI]] 117; 118entry: 119 %res1 = load i8, ptr %p 120 call void @foo(ptr %p) 121 br i1 %cmp, label %b1, label %b2 122b1: 123 %res2 = load i8, ptr %p 124 %res3 = add i8 %res1, %res2 125 br label %alive 126b2: 127 %v = load i8, ptr %p, !invariant.load !1 128 %res.dead = add i8 %v, %res1 129 br label %alive 130alive: 131 %res.phi = phi i8 [%res3, %b1], [%res.dead, %b2] 132 ret i8 %res.phi 133} 134 135 136; This is reduced test case catching regression in the first version of the 137; fix for invariant loads (https://reviews.llvm.org/D64405). 138define void @test4() { 139; CHECK-LABEL: @test4( 140; CHECK-NEXT: entry: 141; CHECK-NEXT: [[TMP0:%.*]] = load float, ptr inttoptr (i64 8 to ptr), align 4 142; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], [[TMP0]] 143; CHECK-NEXT: br label [[FUSION_LOOP_HEADER_DIM_1_PREHEADER:%.*]] 144; CHECK: fusion.loop_header.dim.1.preheader: 145; CHECK-NEXT: [[TMP2:%.*]] = phi float [ [[TMP0]], [[ENTRY:%.*]] ], [ [[DOTPRE:%.*]], [[FUSION_LOOP_HEADER_DIM_1_PREHEADER]] ] 146; CHECK-NEXT: [[FUSION_INVAR_ADDRESS_DIM_0_03:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[INVAR_INC3:%.*]], [[FUSION_LOOP_HEADER_DIM_1_PREHEADER]] ] 147; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 [[FUSION_INVAR_ADDRESS_DIM_0_03]], i64 0, i64 2 148; CHECK-NEXT: [[TMP4:%.*]] = fmul float [[TMP2]], [[TMP2]] 149; CHECK-NEXT: [[INVAR_INC3]] = add nuw nsw i64 [[FUSION_INVAR_ADDRESS_DIM_0_03]], 1 150; CHECK-NEXT: [[DOTPHI_TRANS_INSERT:%.*]] = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 [[INVAR_INC3]], i64 0, i64 2 151; CHECK-NEXT: [[DOTPRE]] = load float, ptr [[DOTPHI_TRANS_INSERT]], align 4, !invariant.load !0 152; CHECK-NEXT: br label [[FUSION_LOOP_HEADER_DIM_1_PREHEADER]] 153; 154entry: 155 %0 = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 0, i64 0, i64 2 156 %1 = load float, ptr %0, align 4 157 %2 = fmul float %1, %1 158 br label %fusion.loop_header.dim.1.preheader 159 160fusion.loop_header.dim.1.preheader: ; preds = %fusion.loop_header.dim.1.preheader, %entry 161 %fusion.invar_address.dim.0.03 = phi i64 [ 0, %entry ], [ %invar.inc3, %fusion.loop_header.dim.1.preheader ] 162 %3 = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 %fusion.invar_address.dim.0.03, i64 0, i64 2 163 %4 = load float, ptr %3, align 4, !invariant.load !1 164 %5 = fmul float %4, %4 165 %6 = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 %fusion.invar_address.dim.0.03, i64 0, i64 2 166 %7 = load float, ptr %6, align 4, !invariant.load !1 167 %8 = fmul float %7, %7 168 %invar.inc3 = add nuw nsw i64 %fusion.invar_address.dim.0.03, 1 169 br label %fusion.loop_header.dim.1.preheader 170} 171 172!1 = !{} 173