diff options
Diffstat (limited to 'llvm/test/Transforms/GVNHoist')
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-call.ll | 28 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-convergent.ll | 93 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-md.ll | 98 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-mssa.ll | 69 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-pr20242.ll | 74 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-pr22005.ll | 30 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-pr28606.ll | 50 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-pr28933.ll | 21 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist-recursive-geps.ll | 103 | ||||
| -rw-r--r-- | llvm/test/Transforms/GVNHoist/hoist.ll | 713 |
10 files changed, 1279 insertions, 0 deletions
diff --git a/llvm/test/Transforms/GVNHoist/hoist-call.ll b/llvm/test/Transforms/GVNHoist/hoist-call.ll new file mode 100644 index 00000000000..50378f7d822 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-call.ll @@ -0,0 +1,28 @@ +; RUN: opt -S -gvn-hoist < %s | FileCheck %s + +; Check that the call and fcmp are hoisted. +; CHECK-LABEL: define void @fun( +; CHECK: call float +; CHECK: fcmp oeq +; CHECK-NOT: call float +; CHECK-NOT: fcmp oeq + +define void @fun(float %__b) minsize { +entry: + br label %if.then + +if.then: ; preds = %entry + br i1 undef, label %if.then8, label %lor.lhs.false + +lor.lhs.false: ; preds = %if.then + %0 = call float @llvm.fabs.f32(float %__b) #2 + %cmpinf7 = fcmp oeq float %0, 0x7FF0000000000000 + unreachable + +if.then8: ; preds = %if.then + %1 = call float @llvm.fabs.f32(float %__b) #2 + %cmpinf10 = fcmp oeq float %1, 0x7FF0000000000000 + ret void +} + +declare float @llvm.fabs.f32(float) diff --git a/llvm/test/Transforms/GVNHoist/hoist-convergent.ll b/llvm/test/Transforms/GVNHoist/hoist-convergent.ll new file mode 100644 index 00000000000..73d923c9014 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-convergent.ll @@ -0,0 +1,93 @@ +; RUN: opt -gvn-hoist -S < %s | FileCheck %s + +; Check that convergent calls are not hoisted. +; +; CHECK-LABEL: @no_convergent_func_hoisting( +; CHECK: if.then: +; CHECK: call float @convergent_func( + +; CHECK: if.else: +; CHECK: call float @convergent_func( +define float @no_convergent_func_hoisting(float %d, float %min, float %max, float %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: + %sub1 = fsub float %max, %a + %mul2 = call float @convergent_func(float %sub1, float %div) + br label %if.end + +if.else: + %sub5 = fsub float %max, %a + %mul6 = call float @convergent_func(float %sub5, float %div) + br label %if.end + +if.end: + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %add = fadd float %tmax.0, 10.0 + ret float %add +} + +; The call site is convergent but the declaration is not. +; CHECK-LABEL: @no_convergent_call_hoisting( + +; CHECK: if.then: +; CHECK: call float @func( + +; CHECK: if.else: +; CHECK: call float @func( +define float @no_convergent_call_hoisting(float %d, float %min, float %max, float %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: + %sub1 = fsub float %max, %a + %mul2 = call float @func(float %sub1, float %div) #0 + br label %if.end + +if.else: + %sub5 = fsub float %max, %a + %mul6 = call float @func(float %sub5, float %div) #0 + br label %if.end + +if.end: + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %add = fadd float %tmax.0, 10.0 + ret float %add +} + +; The call site is convergent but the declaration is not. +; CHECK-LABEL: @call_hoisting( +; CHECK: call float @func( +; CHECK-NOT: call float @func( +define float @call_hoisting(float %d, float %min, float %max, float %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: + %sub1 = fsub float %max, %a + %mul2 = call float @func(float %sub1, float %div) + br label %if.end + +if.else: + %sub5 = fsub float %max, %a + %mul6 = call float @func(float %sub5, float %div) + br label %if.end + +if.end: + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %add = fadd float %tmax.0, 10.0 + ret float %add +} + +declare float @convergent_func(float, float) #0 +declare float @func(float, float) #1 + +attributes #0 = { nounwind readnone convergent } +attributes #1 = { nounwind readnone } diff --git a/llvm/test/Transforms/GVNHoist/hoist-md.ll b/llvm/test/Transforms/GVNHoist/hoist-md.ll new file mode 100644 index 00000000000..902bbb7b269 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-md.ll @@ -0,0 +1,98 @@ +; RUN: opt -S -gvn-hoist < %s | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @test1(i1 %b, i32* %x) { +entry: + br i1 %b, label %if.then, label %if.else + +if.then: ; preds = %entry + store i32 2, i32* %x, align 4, !tbaa !1 + br label %if.end + +if.else: ; preds = %entry + store i32 2, i32* %x, align 4, !tbaa !5 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} +; CHECK-LABEL: define void @test1( +; CHECK: store i32 2, i32* %x, align 4 +; CHECK-NEXT: br i1 %b + +define void @test2(i1 %b, i32* %x) { +entry: + br i1 %b, label %if.then, label %if.else + +if.then: ; preds = %entry + %gep1 = getelementptr inbounds i32, i32* %x, i64 1 + store i32 2, i32* %gep1, align 4, !tbaa !1 + br label %if.end + +if.else: ; preds = %entry + %gep2 = getelementptr inbounds i32, i32* %x, i64 1 + store i32 2, i32* %gep2, align 4, !tbaa !5 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} +; CHECK-LABEL: define void @test2( +; CHECK: %[[gep:.*]] = getelementptr inbounds i32, i32* %x, i64 1 +; CHECK: store i32 2, i32* %[[gep]], align 4 +; CHECK-NEXT: br i1 %b + +define void @test3(i1 %b, i32* %x) { +entry: + br i1 %b, label %if.then, label %if.else + +if.then: ; preds = %entry + %gep1 = getelementptr inbounds i32, i32* %x, i64 1 + store i32 2, i32* %gep1, align 4, !tbaa !1 + br label %if.end + +if.else: ; preds = %entry + %gep2 = getelementptr i32, i32* %x, i64 1 + store i32 2, i32* %gep2, align 4, !tbaa !5 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} +; CHECK-LABEL: define void @test3( +; CHECK: %[[gep:.*]] = getelementptr i32, i32* %x, i64 1 +; CHECK: store i32 2, i32* %[[gep]], align 4 +; CHECK-NEXT: br i1 %b + +!1 = !{!2, !2, i64 0} +!2 = !{!"int", !3, i64 0} +!3 = !{!"omnipotent char", !4, i64 0} +!4 = !{!"Simple C++ TBAA"} +!5 = !{!6, !6, i64 0} +!6 = !{!"_ZTS1e", !3, i64 0} + +define i32 @test4(i1 %b, i32* %y) { +entry: + br i1 %b, label %if.then, label %if.end + +if.then: ; preds = %entry + %0 = load i32, i32* %y, align 4, !range !7 + br label %return + +if.end: ; preds = %entry + %1 = load i32, i32* %y, align 4, !range !8 + br label %return + +return: ; preds = %if.end, %if.then + %retval.0 = phi i32 [ %0, %if.then ], [ %1, %if.end ] + ret i32 %retval.0 +} +; CHECK-LABEL: define i32 @test4( +; CHECK: %[[load:.*]] = load i32, i32* %y, align 4, !range ![[range_md:.*]] +; CHECK: %[[phi:.*]] = phi i32 [ %[[load]], %{{.*}} ], [ %[[load]], %{{.*}} ] +; CHECK: ret i32 %[[phi]] + +!7 = !{i32 0, i32 2} +!8 = !{i32 3, i32 4} +; CHECK: ![[range_md]] = !{i32 0, i32 2, i32 3, i32 4} diff --git a/llvm/test/Transforms/GVNHoist/hoist-mssa.ll b/llvm/test/Transforms/GVNHoist/hoist-mssa.ll new file mode 100644 index 00000000000..b1a46b828d6 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-mssa.ll @@ -0,0 +1,69 @@ +; RUN: opt -S -gvn-hoist < %s | FileCheck %s + +; Check that store hoisting works: there should be only one store left. +; CHECK-LABEL: @getopt +; CHECK: store i32 +; CHECK-NOT: store i32 + +@optind = external global i32, align 4 + +define void @getopt() { +bb: + br label %bb1 + +bb1: ; preds = %bb + br i1 undef, label %bb2, label %bb3 + +bb2: ; preds = %bb1 + br label %bb13 + +bb3: ; preds = %bb1 + br i1 undef, label %bb4, label %bb9 + +bb4: ; preds = %bb3 + %tmp = load i32, i32* @optind, align 4 + br i1 undef, label %bb5, label %bb7 + +bb5: ; preds = %bb4 + %tmp6 = add nsw i32 %tmp, 1 + store i32 %tmp6, i32* @optind, align 4 + br label %bb12 + +bb7: ; preds = %bb4 + %tmp8 = add nsw i32 %tmp, 1 + store i32 %tmp8, i32* @optind, align 4 + br label %bb13 + +bb9: ; preds = %bb3 + %tmp10 = load i32, i32* @optind, align 4 + %tmp11 = add nsw i32 %tmp10, 1 + store i32 %tmp11, i32* @optind, align 4 + br label %bb12 + +bb12: ; preds = %bb9, %bb5 + br label %bb13 + +bb13: ; preds = %bb12, %bb7, %bb2 + ret void +} + +@GlobalVar = internal global float 1.000000e+00 + +; Check that we hoist stores and remove the MSSA phi node. +; CHECK-LABEL: @hoistStoresUpdateMSSA +; CHECK: store float +; CHECK-NOT: store float +define float @hoistStoresUpdateMSSA(float %d) { +entry: + store float 0.000000e+00, float* @GlobalVar + %cmp = fcmp oge float %d, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.end + +if.then: + store float 0.000000e+00, float* @GlobalVar + br label %if.end + +if.end: + %tmp = load float, float* @GlobalVar, align 4 + ret float %tmp +} diff --git a/llvm/test/Transforms/GVNHoist/hoist-pr20242.ll b/llvm/test/Transforms/GVNHoist/hoist-pr20242.ll new file mode 100644 index 00000000000..b91f18a5cd6 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-pr20242.ll @@ -0,0 +1,74 @@ +; RUN: opt -gvn-hoist -S < %s | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Check that all "or" expressions are hoisted. +; CHECK-LABEL: @encode +; CHECK: or i32 +; CHECK-NOT: or i32 + +define i8* @encode(i8* %p, i32 %v) { +entry: + %p.addr = alloca i8*, align 8 + %v.addr = alloca i32, align 4 + store i8* %p, i8** %p.addr, align 8 + store i32 %v, i32* %v.addr, align 4 + %0 = load i32, i32* %v.addr, align 4 + %cmp = icmp ult i32 %0, 23 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %1 = load i32, i32* %v.addr, align 4 + %or = or i32 %1, 128 + %conv = trunc i32 %or to i8 + %2 = load i8*, i8** %p.addr, align 8 + %incdec.ptr = getelementptr inbounds i8, i8* %2, i32 1 + store i8* %incdec.ptr, i8** %p.addr, align 8 + store i8 %conv, i8* %2, align 1 + br label %if.end15 + +if.else: ; preds = %entry + %3 = load i32, i32* %v.addr, align 4 + %cmp1 = icmp ult i32 %3, 42 + br i1 %cmp1, label %if.then3, label %if.else9 + +if.then3: ; preds = %if.else + %4 = load i32, i32* %v.addr, align 4 + %or4 = or i32 %4, 128 + %conv5 = trunc i32 %or4 to i8 + %5 = load i8*, i8** %p.addr, align 8 + %incdec.ptr6 = getelementptr inbounds i8, i8* %5, i32 1 + store i8* %incdec.ptr6, i8** %p.addr, align 8 + store i8 %conv5, i8* %5, align 1 + %6 = load i32, i32* %v.addr, align 4 + %conv7 = trunc i32 %6 to i8 + %7 = load i8*, i8** %p.addr, align 8 + %incdec.ptr8 = getelementptr inbounds i8, i8* %7, i32 1 + store i8* %incdec.ptr8, i8** %p.addr, align 8 + store i8 %conv7, i8* %7, align 1 + br label %if.end + +if.else9: ; preds = %if.else + %8 = load i32, i32* %v.addr, align 4 + %or10 = or i32 %8, 128 + %conv11 = trunc i32 %or10 to i8 + %9 = load i8*, i8** %p.addr, align 8 + %incdec.ptr12 = getelementptr inbounds i8, i8* %9, i32 1 + store i8* %incdec.ptr12, i8** %p.addr, align 8 + store i8 %conv11, i8* %9, align 1 + %10 = load i32, i32* %v.addr, align 4 + %shr = lshr i32 %10, 7 + %conv13 = trunc i32 %shr to i8 + %11 = load i8*, i8** %p.addr, align 8 + %incdec.ptr14 = getelementptr inbounds i8, i8* %11, i32 1 + store i8* %incdec.ptr14, i8** %p.addr, align 8 + store i8 %conv13, i8* %11, align 1 + br label %if.end + +if.end: ; preds = %if.else9, %if.then3 + br label %if.end15 + +if.end15: ; preds = %if.end, %if.then + %12 = load i8*, i8** %p.addr, align 8 + ret i8* %12 +} diff --git a/llvm/test/Transforms/GVNHoist/hoist-pr22005.ll b/llvm/test/Transforms/GVNHoist/hoist-pr22005.ll new file mode 100644 index 00000000000..9299f4f48e5 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-pr22005.ll @@ -0,0 +1,30 @@ +; RUN: opt -gvn-hoist -S < %s | FileCheck %s +target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Check that all "sub" expressions are hoisted. +; CHECK-LABEL: @fun +; CHECK: sub i64 +; CHECK-NOT: sub i64 + +define i64 @fun(i8* %out, i8* %end) { + %1 = icmp ult i8* %out, %end + br i1 %1, label %2, label %6 + +; <label>:2 ; preds = %0 + %3 = ptrtoint i8* %end to i64 + %4 = ptrtoint i8* %out to i64 + %5 = sub i64 %3, %4 + br label %10 + +; <label>:6 ; preds = %0 + %7 = ptrtoint i8* %out to i64 + %8 = ptrtoint i8* %end to i64 + %9 = sub i64 %8, %7 + br label %10 + +; <label>:10 ; preds = %6, %2 + %.in = phi i64 [ %5, %2 ], [ %9, %6 ] + %11 = add i64 %.in, 257 + ret i64 %11 +} diff --git a/llvm/test/Transforms/GVNHoist/hoist-pr28606.ll b/llvm/test/Transforms/GVNHoist/hoist-pr28606.ll new file mode 100644 index 00000000000..2c588283ea9 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-pr28606.ll @@ -0,0 +1,50 @@ +; RUN: opt -gvn-hoist -S < %s | FileCheck %s + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc18.0.0" + +%struct.S = type { i8* } + +declare void @f(<{ %struct.S }>* inalloca) + + +; Check that we don't clone the %x alloca and insert it in the live range of +; %argmem, which would break the inalloca contract. +; +; CHECK-LABEL: @test +; CHECK: alloca i8 +; CHECK: stacksave +; CHECK: alloca inalloca +; CHECK-NOT: alloca i8 + +; Check that store instructions are hoisted. +; CHECK: store i8 +; CHECK-NOT: store i8 +; CHECK: stackrestore + +define void @test(i1 %b) { +entry: + %x = alloca i8 + %inalloca.save = call i8* @llvm.stacksave() + %argmem = alloca inalloca <{ %struct.S }>, align 4 + %0 = getelementptr inbounds <{ %struct.S }>, <{ %struct.S }>* %argmem, i32 0, i32 0 + br i1 %b, label %true, label %false + +true: + %p = getelementptr inbounds %struct.S, %struct.S* %0, i32 0, i32 0 + store i8* %x, i8** %p, align 4 + br label %exit + +false: + %p2 = getelementptr inbounds %struct.S, %struct.S* %0, i32 0, i32 0 + store i8* %x, i8** %p2, align 4 + br label %exit + +exit: + call void @f(<{ %struct.S }>* inalloca %argmem) + call void @llvm.stackrestore(i8* %inalloca.save) + ret void +} + +declare i8* @llvm.stacksave() +declare void @llvm.stackrestore(i8*) diff --git a/llvm/test/Transforms/GVNHoist/hoist-pr28933.ll b/llvm/test/Transforms/GVNHoist/hoist-pr28933.ll new file mode 100644 index 00000000000..95df3f220f2 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-pr28933.ll @@ -0,0 +1,21 @@ +; RUN: opt -S -gvn-hoist -verify-memoryssa < %s | FileCheck %s + +; Check that we end up with one load and one store, in the right order +; CHECK-LABEL: define void @test_it( +; CHECK: store +; CHECK-NEXT: load +; CHECK-NOT: store +; CHECK-NOT: load + +%rec894.0.1.2.3.12 = type { i16 } + +@a = external global %rec894.0.1.2.3.12 + +define void @test_it() { +bb2: + store i16 undef, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1 + %_tmp61 = load i16, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1 + store i16 undef, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1 + %_tmp92 = load i16, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1 + ret void +} diff --git a/llvm/test/Transforms/GVNHoist/hoist-recursive-geps.ll b/llvm/test/Transforms/GVNHoist/hoist-recursive-geps.ll new file mode 100644 index 00000000000..76bc7c26e81 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist-recursive-geps.ll @@ -0,0 +1,103 @@ +; RUN: opt -gvn-hoist -S < %s | FileCheck %s + +; Check that recursive GEPs are hoisted. +; CHECK-LABEL: @fun +; CHECK: fdiv +; CHECK: load +; CHECK: load +; CHECK: load +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK: fsub +; CHECK: fmul +; CHECK-NOT: fsub +; CHECK-NOT: fmul + +%0 = type { double, double, double } +%1 = type { double, double, double } +%2 = type { %3, %1, %1 } +%3 = type { i32 (...)**, %4, %10*, %11, %11, %11, %11, %11, %11, %11, %11, %11 } +%4 = type { %5 } +%5 = type { %6 } +%6 = type { %7 } +%7 = type { %8 } +%8 = type { %9 } +%9 = type { i64, i64, i8* } +%10 = type <{ i32 (...)**, i32, [4 x i8] }> +%11 = type { [4 x [4 x double]] } +%12 = type <{ %1, %0, i32, [4 x i8] }> +%13 = type { %1, %0, %12, %3*, %14* } +%14 = type opaque + +@d = external global %0, align 8 +@p = external global %1, align 8 + +define zeroext i1 @fun(%2*, %12* dereferenceable(56), double*, %13*) { + %5 = alloca %2*, align 8 + %6 = alloca %12*, align 8 + %7 = alloca double*, align 8 + %8 = alloca %13*, align 8 + %9 = alloca double, align 8 + %10 = alloca double, align 8 + %11 = alloca double, align 8 + %12 = alloca double, align 8 + %13 = alloca double, align 8 + %14 = alloca double, align 8 + %15 = alloca double, align 8 + store %2* %0, %2** %5, align 8 + store %12* %1, %12** %6, align 8 + store double* %2, double** %7, align 8 + store %13* %3, %13** %8, align 8 + %16 = load %2*, %2** %5, align 8 + %17 = load double, double* getelementptr inbounds (%0, %0* @d, i32 0, i32 0), align 8 + %18 = fdiv double 1.000000e+00, %17 + store double %18, double* %15, align 8 + %19 = load double, double* %15, align 8 + %20 = fcmp oge double %19, 0.000000e+00 + br i1 %20, label %21, label %36 + +; <label>:21: ; preds = %4 + %22 = getelementptr inbounds %2, %2* %16, i32 0, i32 1 + %23 = getelementptr inbounds %1, %1* %22, i32 0, i32 0 + %24 = load double, double* %23, align 8 + %25 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8 + %26 = fsub double %24, %25 + %27 = load double, double* %15, align 8 + %28 = fmul double %26, %27 + store double %28, double* %9, align 8 + %29 = getelementptr inbounds %2, %2* %16, i32 0, i32 2 + %30 = getelementptr inbounds %1, %1* %29, i32 0, i32 0 + %31 = load double, double* %30, align 8 + %32 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8 + %33 = fsub double %31, %32 + %34 = load double, double* %15, align 8 + %35 = fmul double %33, %34 + store double %35, double* %12, align 8 + br label %51 + +; <label>:36: ; preds = %4 + %37 = getelementptr inbounds %2, %2* %16, i32 0, i32 2 + %38 = getelementptr inbounds %1, %1* %37, i32 0, i32 0 + %39 = load double, double* %38, align 8 + %40 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8 + %41 = fsub double %39, %40 + %42 = load double, double* %15, align 8 + %43 = fmul double %41, %42 + store double %43, double* %9, align 8 + %44 = getelementptr inbounds %2, %2* %16, i32 0, i32 1 + %45 = getelementptr inbounds %1, %1* %44, i32 0, i32 0 + %46 = load double, double* %45, align 8 + %47 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8 + %48 = fsub double %46, %47 + %49 = load double, double* %15, align 8 + %50 = fmul double %48, %49 + store double %50, double* %12, align 8 + br label %51 + +; <label>:51: ; preds = %36, %21 + %52 = load double, double* %12, align 8 + %53 = load double, double* %9, align 8 + %54 = fcmp olt double %52, %53 + ret i1 %54 +} diff --git a/llvm/test/Transforms/GVNHoist/hoist.ll b/llvm/test/Transforms/GVNHoist/hoist.ll new file mode 100644 index 00000000000..8e189418d72 --- /dev/null +++ b/llvm/test/Transforms/GVNHoist/hoist.ll @@ -0,0 +1,713 @@ +; RUN: opt -gvn-hoist -S < %s | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@GlobalVar = internal global float 1.000000e+00 + +; Check that all scalar expressions are hoisted. +; +; CHECK-LABEL: @scalarsHoisting +; CHECK: fsub +; CHECK: fsub +; CHECK: fmul +; CHECK: fmul +; CHECK-NOT: fmul +; CHECK-NOT: fsub +define float @scalarsHoisting(float %d, float %min, float %max, float %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %sub = fsub float %min, %a + %mul = fmul float %sub, %div + %sub1 = fsub float %max, %a + %mul2 = fmul float %sub1, %div + br label %if.end + +if.else: ; preds = %entry + %sub3 = fsub float %max, %a + %mul4 = fmul float %sub3, %div + %sub5 = fsub float %min, %a + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: ; preds = %if.else, %if.then + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %tmin.0 = phi float [ %mul, %if.then ], [ %mul4, %if.else ] + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that all loads and scalars depending on the loads are hoisted. +; Check that getelementptr computation gets hoisted before the load. +; +; CHECK-LABEL: @readsAndScalarsHoisting +; CHECK: load +; CHECK: load +; CHECK: load +; CHECK: fsub +; CHECK: fsub +; CHECK: fmul +; CHECK: fmul +; CHECK-NOT: load +; CHECK-NOT: fmul +; CHECK-NOT: fsub +define float @readsAndScalarsHoisting(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %A = getelementptr float, float* %min, i32 1 + %0 = load float, float* %A, align 4 + %1 = load float, float* %a, align 4 + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + br label %if.end + +if.else: ; preds = %entry + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %B = getelementptr float, float* %min, i32 1 + %5 = load float, float* %B, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: ; preds = %if.else, %if.then + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %tmin.0 = phi float [ %mul, %if.then ], [ %mul4, %if.else ] + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that we do not hoist loads after a store: the first two loads will be +; hoisted, and then the third load will not be hoisted. +; +; CHECK-LABEL: @readsAndWrites +; CHECK: load +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK: store +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK-NOT: load +; CHECK-NOT: fmul +; CHECK-NOT: fsub +define float @readsAndWrites(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + store float %0, float* @GlobalVar + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + br label %if.end + +if.else: ; preds = %entry + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: ; preds = %if.else, %if.then + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %tmin.0 = phi float [ %mul, %if.then ], [ %mul4, %if.else ] + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that we do hoist loads when the store is above the insertion point. +; +; CHECK-LABEL: @readsAndWriteAboveInsertPt +; CHECK: load +; CHECK: load +; CHECK: load +; CHECK: fsub +; CHECK: fsub +; CHECK: fmul +; CHECK: fmul +; CHECK-NOT: load +; CHECK-NOT: fmul +; CHECK-NOT: fsub +define float @readsAndWriteAboveInsertPt(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + store float 0.000000e+00, float* @GlobalVar + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + br label %if.end + +if.else: ; preds = %entry + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: ; preds = %if.else, %if.then + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %tmin.0 = phi float [ %mul, %if.then ], [ %mul4, %if.else ] + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that dependent expressions are hoisted. +; CHECK-LABEL: @dependentScalarsHoisting +; CHECK: fsub +; CHECK: fadd +; CHECK: fdiv +; CHECK: fmul +; CHECK-NOT: fsub +; CHECK-NOT: fadd +; CHECK-NOT: fdiv +; CHECK-NOT: fmul +define float @dependentScalarsHoisting(float %a, float %b, i1 %c) { +entry: + br i1 %c, label %if.then, label %if.else + +if.then: + %d = fsub float %b, %a + %e = fadd float %d, %a + %f = fdiv float %e, %a + %g = fmul float %f, %a + br label %if.end + +if.else: + %h = fsub float %b, %a + %i = fadd float %h, %a + %j = fdiv float %i, %a + %k = fmul float %j, %a + br label %if.end + +if.end: + %r = phi float [ %g, %if.then ], [ %k, %if.else ] + ret float %r +} + +; Check that all independent expressions are hoisted. +; CHECK-LABEL: @independentScalarsHoisting +; CHECK: fsub +; CHECK: fdiv +; CHECK: fmul +; CHECK: fadd +; CHECK-NOT: fsub +; CHECK-NOT: fdiv +; CHECK-NOT: fmul +define float @independentScalarsHoisting(float %a, float %b, i1 %c) { +entry: + br i1 %c, label %if.then, label %if.else + +if.then: + %d = fadd float %b, %a + %e = fsub float %b, %a + %f = fdiv float %b, %a + %g = fmul float %b, %a + br label %if.end + +if.else: + %i = fadd float %b, %a + %h = fsub float %b, %a + %j = fdiv float %b, %a + %k = fmul float %b, %a + br label %if.end + +if.end: + %p = phi float [ %d, %if.then ], [ %i, %if.else ] + %q = phi float [ %e, %if.then ], [ %h, %if.else ] + %r = phi float [ %f, %if.then ], [ %j, %if.else ] + %s = phi float [ %g, %if.then ], [ %k, %if.else ] + %t = fadd float %p, %q + %u = fadd float %r, %s + %v = fadd float %t, %u + ret float %v +} + +; Check that we hoist load and scalar expressions in triangles. +; CHECK-LABEL: @triangleHoisting +; CHECK: load +; CHECK: load +; CHECK: load +; CHECK: fsub +; CHECK: fsub +; CHECK: fmul +; CHECK: fmul +; CHECK-NOT: load +; CHECK-NOT: fmul +; CHECK-NOT: fsub +define float @triangleHoisting(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + br label %if.end + +if.end: ; preds = %entry + %p1 = phi float [ %mul2, %if.then ], [ 0.000000e+00, %entry ] + %p2 = phi float [ %mul, %if.then ], [ 0.000000e+00, %entry ] + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + + %x = fadd float %p1, %mul6 + %y = fadd float %p2, %mul4 + %z = fadd float %x, %y + ret float %z +} + +; Check that we hoist load and scalar expressions in dominator. +; CHECK-LABEL: @dominatorHoisting +; CHECK: load +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK-NOT: load +; CHECK-NOT: fmul +; CHECK-NOT: fsub +define float @dominatorHoisting(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: ; preds = %entry + %p1 = phi float [ %mul4, %if.then ], [ 0.000000e+00, %entry ] + %p2 = phi float [ %mul6, %if.then ], [ 0.000000e+00, %entry ] + + %x = fadd float %p1, %mul2 + %y = fadd float %p2, %mul + %z = fadd float %x, %y + ret float %z +} + +; Check that we hoist load and scalar expressions in dominator. +; CHECK-LABEL: @domHoisting +; CHECK: load +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK: load +; CHECK: fsub +; CHECK: fmul +; CHECK-NOT: load +; CHECK-NOT: fmul +; CHECK-NOT: fsub +define float @domHoisting(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.else: + %6 = load float, float* %max, align 4 + %7 = load float, float* %a, align 4 + %sub9 = fsub float %6, %7 + %mul10 = fmul float %sub9, %div + %8 = load float, float* %min, align 4 + %sub12 = fsub float %8, %7 + %mul13 = fmul float %sub12, %div + br label %if.end + +if.end: + %p1 = phi float [ %mul4, %if.then ], [ %mul10, %if.else ] + %p2 = phi float [ %mul6, %if.then ], [ %mul13, %if.else ] + + %x = fadd float %p1, %mul2 + %y = fadd float %p2, %mul + %z = fadd float %x, %y + ret float %z +} + +; Check that we do not hoist loads past stores within a same basic block. +; CHECK-LABEL: @noHoistInSingleBBWithStore +; CHECK: load +; CHECK: store +; CHECK: load +; CHECK: store +define i32 @noHoistInSingleBBWithStore() { +entry: + %D = alloca i32, align 4 + %0 = bitcast i32* %D to i8* + %bf = load i8, i8* %0, align 4 + %bf.clear = and i8 %bf, -3 + store i8 %bf.clear, i8* %0, align 4 + %bf1 = load i8, i8* %0, align 4 + %bf.clear1 = and i8 %bf1, 1 + store i8 %bf.clear1, i8* %0, align 4 + ret i32 0 +} + +; Check that we do not hoist loads past calls within a same basic block. +; CHECK-LABEL: @noHoistInSingleBBWithCall +; CHECK: load +; CHECK: call +; CHECK: load +declare void @foo() +define i32 @noHoistInSingleBBWithCall() { +entry: + %D = alloca i32, align 4 + %0 = bitcast i32* %D to i8* + %bf = load i8, i8* %0, align 4 + %bf.clear = and i8 %bf, -3 + call void @foo() + %bf1 = load i8, i8* %0, align 4 + %bf.clear1 = and i8 %bf1, 1 + ret i32 0 +} + +; Check that we do not hoist loads past stores in any branch of a diamond. +; CHECK-LABEL: @noHoistInDiamondWithOneStore1 +; CHECK: fdiv +; CHECK: fcmp +; CHECK: br +define float @noHoistInDiamondWithOneStore1(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + store float 0.000000e+00, float* @GlobalVar + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + br label %if.end + +if.else: ; preds = %entry + ; There are no side effects on the if.else branch. + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: ; preds = %if.else, %if.then + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %tmin.0 = phi float [ %mul, %if.then ], [ %mul4, %if.else ] + + %6 = load float, float* %max, align 4 + %7 = load float, float* %a, align 4 + %sub6 = fsub float %6, %7 + %mul7 = fmul float %sub6, %div + %8 = load float, float* %min, align 4 + %sub8 = fsub float %8, %7 + %mul9 = fmul float %sub8, %div + + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that we do not hoist loads past stores from half diamond. +; CHECK-LABEL: @noHoistInHalfDiamondPastStore +; CHECK: load +; CHECK-NEXT: load +; CHECK-NEXT: store +; CHECK-NEXT: br +; CHECK: load +; CHECK: load +; CHECK: load +; CHECK: br +define float @noHoistInHalfDiamondPastStore(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + + ; Loads should not be hoisted above this store. + store float 0.000000e+00, float* @GlobalVar + + br i1 %cmp, label %if.then, label %if.end + +if.then: + ; There are no side effects on the if.then branch. + %2 = load float, float* %max, align 4 + %3 = load float, float* %a, align 4 + %sub3 = fsub float %2, %3 + %mul4 = fmul float %sub3, %div + %4 = load float, float* %min, align 4 + %sub5 = fsub float %4, %3 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: + %tmax.0 = phi float [ %mul4, %if.then ], [ %0, %entry ] + %tmin.0 = phi float [ %mul6, %if.then ], [ %1, %entry ] + + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that we do not hoist loads past a store in any branch of a diamond. +; CHECK-LABEL: @noHoistInDiamondWithOneStore2 +; CHECK: fdiv +; CHECK: fcmp +; CHECK: br +define float @noHoistInDiamondWithOneStore2(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + ; There are no side effects on the if.then branch. + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + br label %if.end + +if.else: ; preds = %entry + store float 0.000000e+00, float* @GlobalVar + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: ; preds = %if.else, %if.then + %tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ] + %tmin.0 = phi float [ %mul, %if.then ], [ %mul4, %if.else ] + + %6 = load float, float* %max, align 4 + %7 = load float, float* %a, align 4 + %sub6 = fsub float %6, %7 + %mul7 = fmul float %sub6, %div + %8 = load float, float* %min, align 4 + %sub8 = fsub float %8, %7 + %mul9 = fmul float %sub8, %div + + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that we do not hoist loads outside a loop containing stores. +; CHECK-LABEL: @noHoistInLoopsWithStores +; CHECK: fdiv +; CHECK: fcmp +; CHECK: br +define float @noHoistInLoopsWithStores(float %d, float* %min, float* %max, float* %a) { +entry: + %div = fdiv float 1.000000e+00, %d + %cmp = fcmp oge float %div, 0.000000e+00 + br i1 %cmp, label %do.body, label %if.else + +do.body: + %0 = load float, float* %min, align 4 + %1 = load float, float* %a, align 4 + + ; It is unsafe to hoist the loads outside the loop because of the store. + store float 0.000000e+00, float* @GlobalVar + + %sub = fsub float %0, %1 + %mul = fmul float %sub, %div + %2 = load float, float* %max, align 4 + %sub1 = fsub float %2, %1 + %mul2 = fmul float %sub1, %div + br label %while.cond + +while.cond: + %cmp1 = fcmp oge float %mul2, 0.000000e+00 + br i1 %cmp1, label %if.end, label %do.body + +if.else: + %3 = load float, float* %max, align 4 + %4 = load float, float* %a, align 4 + %sub3 = fsub float %3, %4 + %mul4 = fmul float %sub3, %div + %5 = load float, float* %min, align 4 + %sub5 = fsub float %5, %4 + %mul6 = fmul float %sub5, %div + br label %if.end + +if.end: + %tmax.0 = phi float [ %mul2, %while.cond ], [ %mul6, %if.else ] + %tmin.0 = phi float [ %mul, %while.cond ], [ %mul4, %if.else ] + + %add = fadd float %tmax.0, %tmin.0 + ret float %add +} + +; Check that we hoist stores: all the instructions from the then branch +; should be hoisted. +; CHECK-LABEL: @hoistStores +; CHECK: zext +; CHECK-NEXT: trunc +; CHECK-NEXT: getelementptr +; CHECK-NEXT: load +; CHECK-NEXT: getelementptr +; CHECK-NEXT: getelementptr +; CHECK-NEXT: store +; CHECK-NEXT: load +; CHECK-NEXT: load +; CHECK-NEXT: zext +; CHECK-NEXT: add +; CHECK-NEXT: store +; CHECK-NEXT: br +; CHECK: if.then +; CHECK: br + +%struct.foo = type { i16* } + +define void @hoistStores(%struct.foo* %s, i32* %coord, i1 zeroext %delta) { +entry: + %frombool = zext i1 %delta to i8 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.else + +if.then: ; preds = %entry + %p = getelementptr inbounds %struct.foo, %struct.foo* %s, i32 0, i32 0 + %0 = load i16*, i16** %p, align 8 + %incdec.ptr = getelementptr inbounds i16, i16* %0, i32 1 + store i16* %incdec.ptr, i16** %p, align 8 + %1 = load i16, i16* %0, align 2 + %conv = zext i16 %1 to i32 + %2 = load i32, i32* %coord, align 4 + %add = add i32 %2, %conv + store i32 %add, i32* %coord, align 4 + br label %if.end + +if.else: ; preds = %entry + %p1 = getelementptr inbounds %struct.foo, %struct.foo* %s, i32 0, i32 0 + %3 = load i16*, i16** %p1, align 8 + %incdec.ptr2 = getelementptr inbounds i16, i16* %3, i32 1 + store i16* %incdec.ptr2, i16** %p1, align 8 + %4 = load i16, i16* %3, align 2 + %conv3 = zext i16 %4 to i32 + %5 = load i32, i32* %coord, align 4 + %add4 = add i32 %5, %conv3 + store i32 %add4, i32* %coord, align 4 + %6 = load i16*, i16** %p1, align 8 + %incdec.ptr6 = getelementptr inbounds i16, i16* %6, i32 1 + store i16* %incdec.ptr6, i16** %p1, align 8 + %7 = load i16, i16* %6, align 2 + %conv7 = zext i16 %7 to i32 + %shl = shl i32 %conv7, 8 + %8 = load i32, i32* %coord, align 4 + %add8 = add i32 %8, %shl + store i32 %add8, i32* %coord, align 4 + br label %if.end + +if.end: ; preds = %if.else, %if.then + ret void +} + +define i32 @mergeAlignments(i1 %b, i32* %y) { +entry: + br i1 %b, label %if.then, label %if.end + +if.then: ; preds = %entry + %l1 = load i32, i32* %y, align 4 + br label %return + +if.end: ; preds = %entry + %l2 = load i32, i32* %y, align 1 + br label %return + +return: ; preds = %if.end, %if.then + %retval.0 = phi i32 [ %l1, %if.then ], [ %l2, %if.end ] + ret i32 %retval.0 +} +; CHECK-LABEL: define i32 @mergeAlignments( +; CHECK: %[[load:.*]] = load i32, i32* %y, align 1 +; CHECK: %[[phi:.*]] = phi i32 [ %[[load]], %{{.*}} ], [ %[[load]], %{{.*}} ] +; CHECK: i32 %[[phi]] |

