; This tests a switch statement, including multiple branches to the
; same label which also results in phi instructions with multiple
; entries for the same incoming edge.

; For x86 see adv-switch-opt.ll

; TODO(jvoung): Update to -02 once the phi assignments is done for ARM
; RUN: %if --need=target_ARM32 \
; RUN:   --command %p2i --filetype=obj --disassemble \
; RUN:   --target arm32 -i %s --args -Om1 \
; RUN:   | %if --need=target_ARM32 \
; RUN:     --command FileCheck --check-prefix ARM32 %s

; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN:   --command %p2i --filetype=asm --assemble --disassemble \
; RUN:   --target mips32 -i %s --args -Om1 \
; RUN:   -allow-externally-defined-symbols \
; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
; RUN:     --command FileCheck --check-prefix MIPS32 %s

define internal i32 @testSwitch(i32 %a) {
entry:
  switch i32 %a, label %sw.default [
    i32 1, label %sw.epilog
    i32 2, label %sw.epilog
    i32 3, label %sw.epilog
    i32 7, label %sw.bb1
    i32 8, label %sw.bb1
    i32 15, label %sw.bb2
    i32 14, label %sw.bb2
  ]

sw.default:                                       ; preds = %entry
  %add = add i32 %a, 27
  br label %sw.epilog

sw.bb1:                                           ; preds = %entry, %entry
  %phitmp = sub i32 21, %a
  br label %sw.bb2

sw.bb2:                                           ; preds = %sw.bb1, %entry, %entry
  %result.0 = phi i32 [ 1, %entry ], [ 1, %entry ], [ %phitmp, %sw.bb1 ]
  br label %sw.epilog

sw.epilog:                                        ; preds = %sw.bb2, %sw.default, %entry, %entry, %entry
  %result.1 = phi i32 [ %add, %sw.default ], [ %result.0, %sw.bb2 ], [ 17, %entry ], [ 17, %entry ], [ 17, %entry ]
  ret i32 %result.1
}

; MIPS32-LABEL: testSwitch
; MIPS32: li	{{.*}},1
; MIPS32: li	{{.*}},17
; MIPS32: li	{{.*}},1
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <[[SW_EPILOG:.*]]>
; MIPS32: li	{{.*}},2
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <[[SW_EPILOG]]>
; MIPS32: li	{{.*}},3
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <[[SW_EPILOG]]>
; MIPS32: li	{{.*}},7
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <[[SW_BB1:.*]]>
; MIPS32: li	{{.*}},8
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <[[SW_BB1]]>
; MIPS32: li	{{.*}},15
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <[[SW_BB2:.*]]>
; MIPS32: li	{{.*}},14
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <[[SW_BB2]]>
; MIPS32: b	{{.*}} <[[SW_DEFAULT:.*]]>
; MIPS32: <[[SW_DEFAULT]]>
; MIPS32: addiu	{{.*}},27
; MIPS32: b	{{.*}} <[[SW_EPILOG]]>
; MIPS32: <[[SW_BB1]]>
; MIPS32: li	{{.*}},21
; MIPS32: b	{{.*}} <[[SW_BB2]]>
; MIPS32: <[[SW_BB2]]>
; MIPS32: b	{{.*}} <[[SW_EPILOG]]>
; MIPS32: <[[SW_EPILOG]]>
; MIPS32: jr	ra

; Check for a valid addressing mode when the switch operand is an
; immediate.  It's important that there is exactly one case, because
; for two or more cases the source operand is legalized into a
; register.
define internal i32 @testSwitchImm() {
entry:
  switch i32 10, label %sw.default [
    i32 1, label %sw.default
  ]

sw.default:
  ret i32 20
}
; ARM32-LABEL: testSwitchImm
; ARM32: cmp {{r[0-9]+}}, #1
; ARM32-NEXT: beq
; ARM32-NEXT: b

; MIPS32-LABEL: testSwitchImm
; MIPS32: li	{{.*}},10
; MIPS32: li	{{.*}},1
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <.LtestSwitchImm$sw.default>
; MIPS32: .LtestSwitchImm$sw.default
; MIPS32: li	v0,20
; MIPS32: jr	ra

; Test for correct 64-bit lowering.
define internal i32 @testSwitch64(i64 %a) {
entry:
  switch i64 %a, label %sw.default [
    i64 123, label %return
    i64 234, label %sw.bb1
    i64 345, label %sw.bb2
    i64 78187493520, label %sw.bb3
  ]

sw.bb1:                                           ; preds = %entry
  br label %return

sw.bb2:                                           ; preds = %entry
  br label %return

sw.bb3:                                           ; preds = %entry
  br label %return

sw.default:                                       ; preds = %entry
  br label %return

return:                                           ; preds = %sw.default, %sw.bb3, %sw.bb2, %sw.bb1, %entry
  %retval.0 = phi i32 [ 5, %sw.default ], [ 4, %sw.bb3 ], [ 3, %sw.bb2 ], [ 2, %sw.bb1 ], [ 1, %entry ]
  ret i32 %retval.0
}
; ARM32-LABEL: testSwitch64
; ARM32: cmp {{r[0-9]+}}, #123
; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
; ARM32-NEXT: beq
; ARM32: cmp {{r[0-9]+}}, #234
; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
; ARM32-NEXT: beq
; ARM32: movw [[REG:r[0-9]+]], #345
; ARM32-NEXT: cmp {{r[0-9]+}}, [[REG]]
; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
; ARM32-NEXT: beq
; ARM32: movw [[REG:r[0-9]+]], #30864
; ARM32-NEXT: movt [[REG]], #13398
; ARM32-NEXT: cmp {{r[0-9]+}}, [[REG]]
; ARM32-NEXT: cmpeq {{r[0-9]+}}, #18
; ARM32-NEXT: beq
; ARM32-NEXT: b

; MIPS32-LABEL: testSwitch64
; MIPS32: bne	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__0>
; MIPS32: li	{{.*}},123
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$local$__0
; MIPS32: li	{{.*}},0
; MIPS32: bne	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__1>
; MIPS32: li	{{.*}},234
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$sw.bb1>
; MIPS32: .LtestSwitch64$local$__1
; MIPS32: li	{{.*}},0
; MIPS32: bne	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__2>
; MIPS32: li	{{.*}},345
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$sw.bb2>
; MIPS32: .LtestSwitch64$local$__2
; MIPS32: li	{{.*}},18
; MIPS32: bne	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__3>
; MIPS32: lui	{{.*}},0x3456
; MIPS32: ori	{{.*}},{{.*}},0x7890
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <.LtestSwitch64$sw.bb3>
; MIPS32: .LtestSwitch64$local$__3
; MIPS32: b	{{.*}} <.LtestSwitch64$sw.default>
; MIPS32: .LtestSwitch64$sw.bb1
; MIPS32: li	{{.*}},2
; MIPS32: b	{{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$sw.bb2
; MIPS32: li	{{.*}},3
; MIPS32: b	{{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$sw.bb3
; MIPS32: li	{{.*}},4
; MIPS32: b	{{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$sw.default
; MIPS32: li	{{.*}},5
; MIPS32: b	{{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$return
; MIPS32: jr	ra

; Similar to testSwitchImm, make sure proper addressing modes are
; used.  In reality, this is tested by running the output through the
; assembler.
define internal i32 @testSwitchImm64() {
entry:
  switch i64 10, label %sw.default [
    i64 1, label %sw.default
  ]

sw.default:
  ret i32 20
}
; ARM32-LABEL: testSwitchImm64
; ARM32: cmp {{r[0-9]+}}, #1
; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
; ARM32-NEXT: beq [[ADDR:[0-9a-f]+]]
; ARM32-NEXT: b [[ADDR]]

; MIPS32-LABEL: testSwitchImm64
; MIPS32: li	{{.*}},10
; MIPS32: li	{{.*}},0
; MIPS32: li	{{.*}},0
; MIPS32: bne	{{.*}},{{.*}},{{.*}} <.LtestSwitchImm64$local$__0>
; MIPS32: li	{{.*}},1
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <.LtestSwitchImm64$sw.default>
; MIPS32: .LtestSwitchImm64$local$__0
; MIPS32: b	{{.*}} <.LtestSwitchImm64$sw.default>
; MIPS32: .LtestSwitchImm64$sw.default
; MIPS32: li	{{.*}},20
; MIPS32: jr	ra

define internal i32 @testSwitchUndef64() {
entry:
  switch i64 undef, label %sw.default [
    i64 1, label %sw.default
  ]

sw.default:
  ret i32 20
}
; ARM32-LABEL: testSwitchUndef64
; ARM32: mov {{.*}}, #0
; ARM32: mov {{.*}}, #0

; MIPS32-LABEL: testSwitchUndef64
; MIPS32: li	{{.*}},0
; MIPS32: li	{{.*}},0
; MIPS32: li	{{.*}},0
; MIPS32: bne	{{.*}},{{.*}},{{.*}} <.LtestSwitchUndef64$local$__0>
; MIPS32: li	{{.*}},1
; MIPS32: beq	{{.*}},{{.*}},{{.*}} <.LtestSwitchUndef64$sw.default>
; MIPS32: .LtestSwitchUndef64$local$__0
; MIPS32: b	{{.*}} <.LtestSwitchUndef64$sw.default>
; MIPS32: .LtestSwitchUndef64$sw.default
; MIPS32: li	{{.*}},20
; MIPS32: jr	ra