summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/GVNHoist
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/GVNHoist')
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-call.ll28
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-convergent.ll93
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-md.ll98
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-mssa.ll69
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-pr20242.ll74
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-pr22005.ll30
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-pr28606.ll50
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-pr28933.ll21
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist-recursive-geps.ll103
-rw-r--r--llvm/test/Transforms/GVNHoist/hoist.ll713
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]]
OpenPOWER on IntegriCloud