; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S -passes='normalize<no-rename-all>' -verify-each < %s | FileCheck %s

define void @foo() {
; CHECK-LABEL: define void @foo() {
; CHECK-NEXT:  bb17254:
; CHECK-NEXT:    ret void
;
  ret void
}

define void @empty_basic_block() {
; CHECK-LABEL: define void @empty_basic_block() {
; CHECK-NEXT:  exit:
; CHECK-NEXT:    ret void
;
exit:
  ret void
}

declare void @effecting()

; Place dead instruction(s) before the terminator
define void @call_effecting() {
; CHECK-LABEL: define void @call_effecting() {
; CHECK-NEXT:  bb14885:
; CHECK-NEXT:    call void @effecting()
; CHECK-NEXT:    [[TMP0:%.*]] = add i32 0, 1
; CHECK-NEXT:    ret void
;
  %1 = add i32 0, 1
  call void @effecting()
  ret void
}

define void @dont_move_above_phi() {
; CHECK-LABEL: define void @dont_move_above_phi() {
; CHECK-NEXT:  bb76951:
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    [[TMP0:%.*]] = phi i32 [ 0, [[BB76951:%.*]] ]
; CHECK-NEXT:    call void @effecting()
; CHECK-NEXT:    ret void
;
  br label %exit
exit:
  %1 = phi i32 [0, %0]
  call void @effecting()
  ret void
}

define void @dont_move_above_alloca() {
; CHECK-LABEL: define void @dont_move_above_alloca() {
; CHECK-NEXT:  bb14885:
; CHECK-NEXT:    [[TMP0:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @effecting()
; CHECK-NEXT:    ret void
;
  %1 = alloca i32
  call void @effecting()
  ret void
}

declare void @effecting1()

define void @dont_reorder_effecting() {
; CHECK-LABEL: define void @dont_reorder_effecting() {
; CHECK-NEXT:  bb45003:
; CHECK-NEXT:    call void @effecting()
; CHECK-NEXT:    call void @effecting1()
; CHECK-NEXT:    ret void
;
  call void @effecting()
  call void @effecting1()
  ret void
}

declare void @effecting2(i32)

define void @dont_reorder_effecting1() {
; CHECK-LABEL: define void @dont_reorder_effecting1() {
; CHECK-NEXT:  bb45003:
; CHECK-NEXT:    [[ONE:%.*]] = add i32 1, 1
; CHECK-NEXT:    call void @effecting2(i32 [[ONE]])
; CHECK-NEXT:    [[TWO:%.*]] = add i32 2, 2
; CHECK-NEXT:    call void @effecting2(i32 [[TWO]])
; CHECK-NEXT:    ret void
;
  %one = add i32 1, 1
  %two = add i32 2, 2
  call void @effecting2(i32 %one)
  call void @effecting2(i32 %two)
  ret void
}

define void @dont_reorder_across_blocks() {
; CHECK-LABEL: define void @dont_reorder_across_blocks() {
; CHECK-NEXT:  bb76951:
; CHECK-NEXT:    [[ONE:%.*]] = add i32 1, 1
; CHECK-NEXT:    br label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    call void @effecting2(i32 [[ONE]])
; CHECK-NEXT:    ret void
;
  %one = add i32 1, 1
  br label %exit
exit:
  call void @effecting2(i32 %one)
  ret void
}

define void @independentldst(ptr %a, ptr %b) {
; CHECK-LABEL: define void @independentldst(
; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT:  bb10495:
; CHECK-NEXT:    %"vl12961([[B]])" = load i32, ptr [[B]], align 4
; CHECK-NEXT:    store i32 %"vl12961([[B]])", ptr [[A]], align 4
; CHECK-NEXT:    %"vl89528([[A]])" = load i32, ptr [[A]], align 4
; CHECK-NEXT:    store i32 %"vl89528([[A]])", ptr [[B]], align 4
; CHECK-NEXT:    ret void
;
  %2 = load i32, ptr %a
  %3 = load i32, ptr %b
  store i32 %3, ptr %a
  store i32 %2, ptr %b
  ret void
}

define void @multiple_use_ld(ptr %a, ptr %b) {
; CHECK-LABEL: define void @multiple_use_ld(
; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT:  bb14927:
; CHECK-NEXT:    %"vl16793([[A]])" = load i32, ptr [[A]], align 4
; CHECK-NEXT:    store i32 %"vl16793([[A]])", ptr [[A]], align 4
; CHECK-NEXT:    %"vl89528([[B]])" = load i32, ptr [[B]], align 4
; CHECK-NEXT:    store i32 %"vl89528([[B]])", ptr [[B]], align 4
; CHECK-NEXT:    store i32 %"vl16793([[A]])", ptr [[A]], align 4
; CHECK-NEXT:    ret void
;
  %2 = load i32, ptr %a
  store i32 %2, ptr %a
  %3 = load i32, ptr %b
  store i32 %3, ptr %b
  store i32 %2, ptr %a
  ret void
}

; This is an incorrect transformation. Moving the store above the load could
; change the loaded value. To do this, the pointers would need to be `noalias`.
define void @undef_st(ptr %a, ptr %b) {
; CHECK-LABEL: define void @undef_st(
; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]]) {
; CHECK-NEXT:  bb10495:
; CHECK-NEXT:    store i32 undef, ptr [[B]], align 4
; CHECK-NEXT:    %"vl16028([[A]])" = load i32, ptr [[A]], align 4
; CHECK-NEXT:    store i32 %"vl16028([[A]])", ptr [[A]], align 4
; CHECK-NEXT:    ret void
;
  %2 = load i32, ptr %a
  store i32 undef, ptr %b
  store i32 %2, ptr %a
  ret void
}
