; 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: fmul
; CHECK: fsub
; 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: fmul
; CHECK: fsub
; 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: fmul
; CHECK: fsub
; 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: fmul
; CHECK: fsub
; 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 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]]


declare i8 @pr30991_f() nounwind readonly
declare void @pr30991_f1(i8)
define i8 @pr30991(i8* %sp, i8* %word, i1 %b1, i1 %b2) {
entry:
  br i1 %b1, label %a, label %b

a:
  %r0 = load i8, i8* %word, align 1
  %incdec.ptr = getelementptr i8, i8* %sp, i32 1
  %rr0 = call i8 @pr30991_f() nounwind readonly
  call void @pr30991_f1(i8 %r0)
  ret i8 %rr0

b:
  br i1 %b2, label %c, label %x

c:
  %r1 = load i8, i8* %word, align 1
  %incdec.ptr115 = getelementptr i8, i8* %sp, i32 1
  %rr1 = call i8 @pr30991_f() nounwind readonly
  call void @pr30991_f1(i8 %r1)
  ret i8 %rr1

x:
  %r2 = load i8, i8* %word, align 1
  ret i8 %r2
}

; CHECK-LABEL: define i8 @pr30991
; CHECK:  %r0 = load i8, i8* %word, align 1
; CHECK-NEXT:  br i1 %b1, label %a, label %b
