llvm/llvm/test/CodeGen/AArch64/GlobalISel/arm64-regbankselect.mir

# RUN: llc -O0 -debugify-and-strip-all-safe -run-pass=regbankselect %s -o - -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=FAST
# RUN: llc -O0 -debugify-and-strip-all-safe -run-pass=regbankselect %s -regbankselect-greedy -o - -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=GREEDY

--- |
  ; ModuleID = 'generic-virtual-registers-type-error.mir'
  target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
  target triple = "aarch64--"
  define void @defaultMapping() {
  entry:
    ret void
  }
  define void @defaultMappingVector() {
  entry:
    ret void
  }
  define void @defaultMapping1Repair() {
  entry:
    ret void
  }
  define void @defaultMapping2Repairs() {
  entry:
    ret void
  }
  define void @defaultMappingDefRepair() {
  entry:
    ret void
  }
  define void @phiPropagation(ptr %src, ptr %dst, i1 %cond) {
  entry:
    %srcVal = load i32, ptr %src
    br i1 %cond, label %end, label %then
  then:
    %res = add i32 %srcVal, 36
    br label %end
  end:
    %toStore = phi i32 [ %srcVal, %entry ], [ %res, %then ]
    store i32 %toStore, ptr %dst
    ret void
  }
  define void @defaultMappingUseRepairPhysReg() {
  entry:
    ret void
  }
  define void @defaultMappingDefRepairPhysReg() {
  entry:
    ret void
  }
  define void @greedyMappingOr() {
  entry:
    ret void
  }
  define void @greedyMappingOrWithConstraints() {
  entry:
    ret void
  }

  define void @ignoreTargetSpecificInst() { ret void }

  define void @regBankSelected_property() { ret void }

  define void @bitcast_s32_gpr() { ret void }
  define void @bitcast_s32_fpr() { ret void }
  define void @bitcast_s32_gpr_fpr() { ret void }
  define void @bitcast_s32_fpr_gpr() { ret void }
  define void @bitcast_s64_gpr() { ret void }
  define void @bitcast_s64_fpr() { ret void }
  define void @bitcast_s64_gpr_fpr() { ret void }
  define void @bitcast_s64_fpr_gpr() { ret void }
  define void @bitcast_s128() { ret void }
  define void @copy_s128() { ret void }
  define void @copy_s128_from_load() { ret void }
  define void @copy_fp16() { ret void }

  define i64 @greedyWithChainOfComputation(i64 %arg1, ptr %addr) {
    %varg1 = bitcast i64 %arg1 to <2 x i32>
    %varg2 = load <2 x i32>, ptr %addr
    %vres = or <2 x i32> %varg1, %varg2
    %res = bitcast <2 x i32> %vres to i64
    ret i64 %res
  }

  define i64 @floatingPointLoad(i64 %arg1, ptr %addr) {
    %varg1 = bitcast i64 %arg1 to double
    %varg2 = load double, ptr %addr
    %vres = fadd double %varg1, %varg2
    %res = bitcast double %vres to i64
    ret i64 %res
  }

  define void @floatingPointStore(i64 %arg1, ptr %addr) {
    %varg1 = bitcast i64 %arg1 to double
    %vres = fadd double %varg1, %varg1
    store double %vres, ptr %addr
    ret void
  }

  define void @fp16Ext32() { ret void }
  define void @fp16Ext64() { ret void }
  define void @fp32Ext64() { ret void }

  define half @passFp16(half %p) {
  entry:
    ret half %p
  }

  define half @passFp16ViaAllocas(half %p) {
  entry:
    %p.addr = alloca half, align 2
    store half %p, ptr %p.addr, align 2
    %0 = load half, ptr %p.addr, align 2
    ret half %0
  }
...

---
# Check that we assign a relevant register bank for %0.
# Based on the type i32, this should be gpr.
name:            defaultMapping
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
body: |
  bb.0.entry:
    liveins: $x0
    ; CHECK-LABEL: name: defaultMapping
    ; CHECK:      %1:gpr(s32) = G_ADD %0
    %0(s32) = COPY $w0
    %1(s32) = G_ADD %0, %0
...

---
# Check that we assign a relevant register bank for %0.
# Based on the type <2 x i32>, this should be fpr.
# FPR is used for both floating point and vector registers.
name:            defaultMappingVector
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
body: |
  bb.0.entry:
    liveins: $d0
    ; CHECK-LABEL: name: defaultMappingVector
    ; CHECK:      %0:fpr(<2 x s32>) = COPY $d0
    ; CHECK:      %1:fpr(<2 x s32>) = G_ADD %0
    %0(<2 x s32>) = COPY $d0
    %1(<2 x s32>) = G_ADD %0, %0
...

---
# Check that we repair the assignment for %0.
# Indeed based on the source of the copy it should live
# in FPR, but at the use, it should be GPR.
name:            defaultMapping1Repair
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
body: |
  bb.0.entry:
    liveins: $s0, $x0
    ; CHECK-LABEL: name: defaultMapping1Repair
    ; CHECK:           %0:fpr(s32) = COPY $s0
    ; CHECK-NEXT:      %1:gpr(s32) = COPY $w0
    ; CHECK-NEXT:      %3:gpr(s32) = COPY %0
    ; CHECK-NEXT:      %2:gpr(s32) = G_ADD %3, %1
    %0(s32) = COPY $s0
    %1(s32) = COPY $w0
    %2(s32) = G_ADD %0, %1
...

# Check that we repair the assignment for %0 differently for both uses.
name:            defaultMapping2Repairs
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
body: |
  bb.0.entry:
    liveins: $s0, $x0
    ; CHECK-LABEL: name: defaultMapping2Repairs
    ; CHECK:           %0:fpr(s32) = COPY $s0
    ; CHECK-NEXT:      %2:gpr(s32) = COPY %0
    ; CHECK-NEXT:      %3:gpr(s32) = COPY %0
    ; CHECK-NEXT:      %1:gpr(s32) = G_ADD %2, %3
    %0(s32) = COPY $s0
    %1(s32) = G_ADD %0, %0
...

---
# Check that we repair the definition of %1.
# %1 is forced to be into FPR, but its definition actually
# requires that it lives in GPR. Make sure regbankselect
# fixes that.
name:            defaultMappingDefRepair
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: fpr }
body: |
  bb.0.entry:
    liveins: $w0
    ; CHECK-LABEL: name: defaultMappingDefRepair
    ; CHECK:           %0:gpr(s32) = COPY $w0
    ; CHECK-NEXT:      %2:gpr(s32) = G_ADD %0, %0
    ; CHECK-NEXT:      %1:fpr(s32) = COPY %2
    %0(s32) = COPY $w0
    %1(s32) = G_ADD %0, %0
...

---
# Check that we are able to propagate register banks from phis.
name:            phiPropagation
legalized:       true
tracksRegLiveness:   true
# CHECK:      registers:
# CHECK-NEXT:   - { id: 0, class: gpr32, preferred-register: '' }
# CHECK-NEXT:   - { id: 1, class: gpr64sp, preferred-register: '' }
# CHECK-NEXT:   - { id: 2, class: gpr32, preferred-register: '' }
# CHECK-NEXT:   - { id: 3, class: gpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 4, class: gpr, preferred-register: '' }
registers:
  - { id: 0, class: gpr32 }
  - { id: 1, class: gpr64sp }
  - { id: 2, class: gpr32 }
  - { id: 3, class: _ }
  - { id: 4, class: _ }
  - { id: 5, class: _ }
body: |
  bb.0.entry:
    successors: %bb.2.end, %bb.1.then
    liveins: $x0, $x1, $w2

    %0 = LDRWui killed $x0, 0 :: (load (s32) from %ir.src)
    %5(s32) = COPY %0
    %1(p0) = COPY $x1
    %2 = COPY $w2
    TBNZW killed %2, 0, %bb.2.end

  bb.1.then:
    successors: %bb.2.end
    %3(s32) = G_ADD %5, %5

  bb.2.end:
    %4(s32) = PHI %0, %bb.0.entry, %3, %bb.1.then
    G_STORE killed %4, killed %1 :: (store (s32) into %ir.dst)
    RET_ReallyLR
...

---
# Make sure we can repair physical register uses as well.
name:            defaultMappingUseRepairPhysReg
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
body: |
  bb.0.entry:
    liveins: $w0, $s0
    ; CHECK-LABEL: name: defaultMappingUseRepairPhysReg
    ; CHECK:           %0:gpr(s32) = COPY $w0
    ; CHECK-NEXT:      %1:fpr(s32) = COPY $s0
    ; CHECK-NEXT:      %3:gpr(s32) = COPY %1
    ; CHECK-NEXT:      %2:gpr(s32) = G_ADD %0, %3
    %0(s32) = COPY $w0
    %1(s32) = COPY $s0
    %2(s32) = G_ADD %0, %1
...

---
# Make sure we can repair physical register defs.
name:            defaultMappingDefRepairPhysReg
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
body: |
  bb.0.entry:
    liveins: $w0
    ; CHECK-LABEL: name: defaultMappingDefRepairPhysReg
    ; CHECK:           %0:gpr(s32) = COPY $w0
    ; CHECK-NEXT:      %1:gpr(s32) = G_ADD %0, %0
    ; CHECK-NEXT:      $s0 = COPY %1
    %0(s32) = COPY $w0
    %1(s32) = G_ADD %0, %0
    $s0 = COPY %1
...

---
# Check that the greedy mode is able to switch the
# G_OR instruction from fpr to gpr.
name:            greedyMappingOr
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
body: |
  bb.0.entry:
    liveins: $x0, $x1
    ; CHECK: %0:gpr(<2 x s32>) = COPY $x0
    ; CHECK-NEXT: %1:gpr(<2 x s32>) = COPY $x1

    ; Fast mode tries to reuse the source of the copy for the destination.
    ; Now, the default mapping says that %0 and %1 need to be in FPR.
    ; The repairing code insert two copies to materialize that.
    ; FAST-NEXT: %3:fpr(<2 x s32>) = COPY %0
    ; FAST-NEXT: %4:fpr(<2 x s32>) = COPY %1
    ; The mapping of G_OR is on FPR.
    ; FAST-NEXT: %2:fpr(<2 x s32>) = G_OR %3, %4

    ; Greedy mode remapped the instruction on the GPR bank.
    ; GREEDY-NEXT: %2:gpr(<2 x s32>) = G_OR %0, %1
    %0(<2 x s32>) = COPY $x0
    %1(<2 x s32>) = COPY $x1
    %2(<2 x s32>) = G_OR %0, %1
...

---
# Check that the greedy mode is able to switch the
# G_OR instruction from fpr to gpr, while still honoring
# %2 constraint.
name:            greedyMappingOrWithConstraints
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: fpr }
body: |
  bb.0.entry:
    liveins: $x0, $x1
    ; CHECK-LABEL: name: greedyMappingOrWithConstraints

    ; CHECK: %0:gpr(<2 x s32>) = COPY $x0
    ; CHECK-NEXT: %1:gpr(<2 x s32>) = COPY $x1

    ; Fast mode tries to reuse the source of the copy for the destination.
    ; Now, the default mapping says that %0 and %1 need to be in FPR.
    ; The repairing code insert two copies to materialize that.
    ; FAST-NEXT: %3:fpr(<2 x s32>) = COPY %0
    ; FAST-NEXT: %4:fpr(<2 x s32>) = COPY %1
    ; The mapping of G_OR is on FPR.
    ; FAST-NEXT: %2:fpr(<2 x s32>) = G_OR %3, %4

    ; Greedy mode remapped the instruction on the GPR bank.
    ; GREEDY-NEXT: %3:gpr(<2 x s32>) = G_OR %0, %1
    ; We need to keep %2 into FPR because we do not know anything about it.
    ; GREEDY-NEXT: %2:fpr(<2 x s32>) = COPY %3
    %0(<2 x s32>) = COPY $x0
    %1(<2 x s32>) = COPY $x1
    %2(<2 x s32>) = G_OR %0, %1
...

---
# CHECK-LABEL: name: ignoreTargetSpecificInst
name:            ignoreTargetSpecificInst
legalized:       true
# CHECK:      registers:
# CHECK-NEXT:  - { id: 0, class: gpr64, preferred-register: '' }
# CHECK-NEXT:  - { id: 1, class: gpr64, preferred-register: '' }
registers:
  - { id: 0, class: gpr64 }
  - { id: 1, class: gpr64 }
body: |
  bb.0:
    liveins: $x0

    ; CHECK: %0:gpr64 = COPY $x0
    ; CHECK-NEXT: %1:gpr64 = ADDXrr %0, %0
    ; CHECK-NEXT: $x0 = COPY %1
    ; CHECK-NEXT: RET_ReallyLR implicit $x0

    %0 = COPY $x0
    %1 = ADDXrr %0, %0
    $x0 = COPY %1
    RET_ReallyLR implicit $x0
...

---
# Check that we set the "regBankSelected" property.
# CHECK-LABEL: name: regBankSelected_property
# CHECK: legalized: true
# CHECK: regBankSelected: true
name:            regBankSelected_property
legalized:       true
regBankSelected: false
body:             |
  bb.0:
...

---
# CHECK-LABEL: name: bitcast_s32_gpr
name:            bitcast_s32_gpr
legalized:       true

# CHECK:      registers:
# CHECK-NEXT:  - { id: 0, class: gpr, preferred-register: '' }
# FAST-NEXT:   - { id: 1, class: fpr, preferred-register: '' }
# GREEDY-NEXT: - { id: 1, class: gpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }

# CHECK:  body:
# CHECK:    %0:gpr(s32) = COPY $w0
# FAST-NEXT:   %1:fpr(<4 x s8>) = G_BITCAST %0
# GREEDY-NEXT: %1:gpr(<4 x s8>) = G_BITCAST %0
# The greedy check is incorrect and should produce fpr.
body:             |
  bb.0:
    liveins: $w0

    %0(s32) = COPY $w0
    %1(<4 x s8>) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s32_fpr
name:            bitcast_s32_fpr
legalized:       true

# CHECK:      registers:
# CHECK-NEXT:  - { id: 0, class: fpr, preferred-register: '' }
# FAST-NEXT:   - { id: 1, class: gpr, preferred-register: '' }
# GREEDY-NEXT: - { id: 1, class: fpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }

# CHECK:  body:
# CHECK:    %0:fpr(<2 x s16>) = COPY $s0
# FAST:     %1:gpr(s32) = G_BITCAST %0
# GREEDY:   %1:fpr(s32) = G_BITCAST %0
body:             |
  bb.0:
    liveins: $s0

    %0(<2 x s16>) = COPY $s0
    %1(s32) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s32_gpr_fpr
name:            bitcast_s32_gpr_fpr
legalized:       true

# CHECK:      registers:
# CHECK-NEXT:  - { id: 0, class: gpr, preferred-register: '' }
# FAST-NEXT:  - { id: 1, class: fpr, preferred-register: '' }
# GREEDY-NEXT:  - { id: 1, class: gpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }

# CHECK:  body:
# CHECK:    %0:gpr(s32) = COPY $w0
# FAST:     %1:fpr(<2 x s16>) = G_BITCAST %0
# GREEDY:   %1:gpr(<2 x s16>) = G_BITCAST %0
body:             |
  bb.0:
    liveins: $w0

    %0(s32) = COPY $w0
    %1(<2 x s16>) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s32_fpr_gpr
name:            bitcast_s32_fpr_gpr
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
# CHECK:  body:
# CHECK:    %0:fpr(<2 x s16>) = COPY $s0
# FAST:     %1:gpr(s32) = G_BITCAST %0
# GREEDY:   %1:fpr(s32) = G_BITCAST %0
body:             |
  bb.0:
    liveins: $s0

    %0(<2 x s16>) = COPY $s0
    %1(s32) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s64_gpr
name:            bitcast_s64_gpr
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
# CHECK:  body:
# CHECK:    %0:gpr(s64) = COPY $x0
# FAST:    %1:fpr(<2 x s32>) = G_BITCAST %0
# GREEDY:  %1:gpr(<2 x s32>) = G_BITCAST %0
body:             |
  bb.0:
    liveins: $x0

    %0(s64) = COPY $x0
    %1(<2 x s32>) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s64_fpr
name:            bitcast_s64_fpr
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
# CHECK:  body:
# CHECK:    %0:fpr(<2 x s32>) = COPY $d0
# FAST:     %1:gpr(s64) = G_BITCAST %0
# GREEDY:   %1:fpr(s64) = G_BITCAST %0
body:             |
  bb.0:
    liveins: $d0

    %0(<2 x s32>) = COPY $d0
    %1(s64) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s64_gpr_fpr
name:            bitcast_s64_gpr_fpr
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
# CHECK:  body:
# CHECK:    %0:gpr(s64) = COPY $x0
# FAST:     %1:fpr(<2 x s32>) = G_BITCAST %0
# GREEDY:   %1:gpr(<2 x s32>) = G_BITCAST %0
body:             |
  bb.0:
    liveins: $x0

    %0(s64) = COPY $x0
    %1(<2 x s32>) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s64_fpr_gpr
name:            bitcast_s64_fpr_gpr
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
# CHECK:  body:
# CHECK:    %0:fpr(<2 x s32>) = COPY $d0
# FAST:     %1:gpr(s64) = G_BITCAST %0
# GREEDY:   %1:fpr(s64) = G_BITCAST %0
body:             |
  bb.0:
    liveins: $d0

    %0(<2 x s32>) = COPY $d0
    %1(s64) = G_BITCAST %0
...

---
# CHECK-LABEL: name: bitcast_s128
name:            bitcast_s128
legalized: true
tracksRegLiveness: true
registers:
  - { id: 0, class: _}
  - { id: 1, class: _}
  - { id: 2, class: _}
  - { id: 3, class: _}
# CHECK: %3:fpr(s128) = G_MERGE_VALUES
# CHECK: %2:fpr(<2 x s64>) = G_BITCAST %3(s128)
body:             |
  bb.1:
    liveins: $x0, $x1
    %0(s64) = COPY $x0
    %1(s64) = COPY $x1
    %3(s128) = G_MERGE_VALUES %0(s64), %1(s64)
    %2(<2 x s64>) = G_BITCAST %3(s128)
    $q0 = COPY %2(<2 x s64>)
    RET_ReallyLR implicit $q0

...

---
# CHECK-LABEL: name: copy_s128
# This test checks that we issue the proper mapping
# for copy of size > 64.
# The mapping should be the same as G_BITCAST.
name:            copy_s128
legalized: true
tracksRegLiveness: true
registers:
  - { id: 0, class: _}
  - { id: 1, class: _}
  - { id: 2, class: _}
  - { id: 3, class: _}
  - { id: 4, class: _}
# CHECK: %3:fpr(s128) = G_MERGE_VALUES
# CHECK: %4:fpr(s128) = COPY %3(s128)
# CHECK-NEXT: %2:fpr(<2 x s64>) = G_BITCAST %4(s128)
body:             |
  bb.1:
    liveins: $x0, $x1
    %0(s64) = COPY $x0
    %1(s64) = COPY $x1
    %3(s128) = G_MERGE_VALUES %0(s64), %1(s64)
    %4(s128) = COPY %3(s128)
    %2(<2 x s64>) = G_BITCAST %4(s128)
    $q0 = COPY %2(<2 x s64>)
    RET_ReallyLR implicit $q0

...

---
# CHECK-LABEL: name: copy_s128_from_load
# This test checks that we issue the proper mapping
# for copy of size > 64 when the input is neither
# a physcal register nor a generic register.
# This used to crash when we moved to the statically
# computed mapping, because we were assuming non-physregs
# were generic registers and thus have a type, whereas
# it is not necessarily the case.
name:            copy_s128_from_load
legalized: true
tracksRegLiveness: true
registers:
  - { id: 0, class: fpr128}
  - { id: 1, class: _}
# CHECK: registers:
# CHECK:  - { id: 0, class: fpr128, preferred-register: '' }
# CHECK:  - { id: 1, class: fpr, preferred-register: '' }
# CHECK: %1:fpr(s128) = COPY %0
body:             |
  bb.1:
    liveins: $x0
    %0 = LDRQui killed $x0, 0
    %1(s128) = COPY %0
    $q0 = COPY %1(s128)
    RET_ReallyLR implicit $q0

...

---
# CHECK-LABEL: name: copy_fp16
# This test checks that we issue the proper mapping
# for copy of size == 16 when the destination is a fpr
# physical register and the source a gpr.
# We used to crash because we thought that mapping couldn't
# exist in a copy.
name:            copy_fp16
legalized: true
tracksRegLiveness: true
registers:
  - { id: 0, class: _}
  - { id: 1, class: _}
# CHECK: registers:
# CHECK:  - { id: 0, class: gpr, preferred-register: '' }
# CHECK:  - { id: 1, class: gpr, preferred-register: '' }
# CHECK: %0:gpr(s32) = COPY $w0
# CHECK-NEXT: %1:gpr(s16) = G_TRUNC %0(s32)
body:             |
  bb.1:
    liveins: $w0
    %0(s32) = COPY $w0
    %1(s16) = G_TRUNC %0(s32)
    $h0 = COPY %1(s16)
    RET_ReallyLR implicit $h0

...


---
# Make sure the greedy mode is able to take advantage of the
# alternative mappings of G_LOAD to coalesce the whole chain
# of computation on GPR.
# CHECK-LABEL: name: greedyWithChainOfComputation
name:            greedyWithChainOfComputation
legalized:       true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
  - { id: 3, class: _ }
  - { id: 4, class: _ }
  - { id: 5, class: _ }
# No repairing should be necessary for both modes.
# CHECK:         %0:gpr(s64) = COPY $x0
# CHECK-NEXT:    %1:gpr(p0) = COPY $x1
# FAST-NEXT:     %2:fpr(<2 x s32>) = G_BITCAST %0(s64)
# FAST-NEXT:     %3:fpr(<2 x s32>) = G_LOAD %1(p0) :: (load (<2 x s32>) from %ir.addr)
# FAST-NEXT:     %4:fpr(<2 x s32>) = G_OR %2, %3
# GREEDY-NEXT:   %2:gpr(<2 x s32>) = G_BITCAST %0(s64)
# GREEDY-NEXT:   %3:gpr(<2 x s32>) = G_LOAD %1(p0) :: (load (<2 x s32>) from %ir.addr)
# GREEDY-NEXT:   %4:gpr(<2 x s32>) = G_OR %2, %3
# CHECK-NEXT:    %5:gpr(s64) = G_BITCAST %4(<2 x s32>)
# CHECK-NEXT:    $x0 = COPY %5(s64)
# CHECK-NEXT:    RET_ReallyLR implicit $x0
body:             |
  bb.0:
    liveins: $x0, $x1

    %0(s64) = COPY $x0
    %1(p0) = COPY $x1
    %2(<2 x s32>) = G_BITCAST %0(s64)
    %3(<2 x s32>) = G_LOAD %1(p0) :: (load (<2 x s32>) from %ir.addr)
    %4(<2 x s32>) = G_OR %2, %3
    %5(s64) = G_BITCAST %4(<2 x s32>)
    $x0 = COPY %5(s64)
    RET_ReallyLR implicit $x0

...

---
# Make sure we map what looks like floating point
# loads to floating point register bank.
# CHECK-LABEL: name: floatingPointLoad
name:            floatingPointLoad
legalized:       true

# CHECK: registers:
# CHECK-NEXT:  - { id: 0, class: gpr, preferred-register: '' }
# CHECK-NEXT:  - { id: 1, class: gpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 2, class: fpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 3, class: fpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 4, class: fpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
  - { id: 3, class: _ }

# No repairing should be necessary for both modes.
# CHECK:         %0:gpr(s64) = COPY $x0
# CHECK-NEXT:    %1:gpr(p0) = COPY $x1
# CHECK-NEXT:    %2:fpr(s64) = G_LOAD %1(p0) :: (load (s64) from %ir.addr)
# %0 has been mapped to GPR, we need to repair to match FPR.
# CHECK-NEXT:    %4:fpr(s64) = COPY %0
# CHECK-NEXT:    %3:fpr(s64) = G_FADD %4, %2
# CHECK-NEXT:    $x0 = COPY %3(s64)
# CHECK-NEXT:    RET_ReallyLR implicit $x0

body:             |
  bb.0:
    liveins: $x0, $x1

    %0(s64) = COPY $x0
    %1(p0) = COPY $x1
    %2(s64) = G_LOAD %1(p0) :: (load (s64) from %ir.addr)
    %3(s64) = G_FADD %0, %2
    $x0 = COPY %3(s64)
    RET_ReallyLR implicit $x0

...

---
# Make sure we map what looks like floating point
# stores to floating point register bank.
# CHECK-LABEL: name: floatingPointStore
name:            floatingPointStore
legalized:       true

# CHECK: registers:
# CHECK-NEXT:  - { id: 0, class: gpr, preferred-register: '' }
# CHECK-NEXT:  - { id: 1, class: gpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 2, class: fpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 3, class: fpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 4, class: fpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }

# CHECK:         %0:gpr(s64) = COPY $x0
# CHECK-NEXT:    %1:gpr(p0) = COPY $x1
# %0 has been mapped to GPR, we need to repair to match FPR.
# CHECK-NEXT:    %3:fpr(s64) = COPY %0
# CHECK-NEXT:    %4:fpr(s64) = COPY %0
# CHECK-NEXT:    %2:fpr(s64) = G_FADD %3, %4
# CHECK-NEXT:    G_STORE %2(s64), %1(p0) :: (store (s64) into %ir.addr)
# CHECK-NEXT:    RET_ReallyLR

body:             |
  bb.0:
    liveins: $x0, $x1

    %0(s64) = COPY $x0
    %1(p0) = COPY $x1
    %2(s64) = G_FADD %0, %0
    G_STORE %2(s64), %1(p0) :: (store (s64) into %ir.addr)
    RET_ReallyLR

...

---
# Make sure we map FPEXT on FPR register bank.
# CHECK-LABEL: name: fp16Ext32
name:            fp16Ext32
alignment:       4
legalized:       true
# CHECK: registers:
# CHECK-NEXT:  - { id: 0, class: gpr, preferred-register: '' }
# CHECK-NEXT:  - { id: 1, class: gpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 2, class: fpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 3, class: fpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
# CHECK:         %1:gpr(s32) = COPY $w0
# CHECK-NEXT:    %0:gpr(s16) = G_TRUNC %1
# %0 has been mapped to GPR, we need to repair to match FPR.
# CHECK-NEXT:    %3:fpr(s16) = COPY %0
# CHECK-NEXT:    %2:fpr(s32) = G_FPEXT %3
# CHECK-NEXT:    $s0 = COPY %2
# CHECK-NEXT:    RET_ReallyLR

body:             |
  bb.1:
    liveins: $w0

    %1(s32) = COPY $w0
    %0(s16) = G_TRUNC %1(s32)
    %2(s32) = G_FPEXT %0(s16)
    $s0 = COPY %2(s32)
    RET_ReallyLR implicit $s0

...

---
# Make sure we map FPEXT on FPR register bank.
# CHECK-LABEL: name: fp16Ext64
name:            fp16Ext64
alignment:       4
legalized:       true
# CHECK: registers:
# CHECK-NEXT:  - { id: 0, class: gpr, preferred-register: '' }
# CHECK-NEXT:  - { id: 1, class: gpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 2, class: fpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 3, class: fpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
# CHECK:         %1:gpr(s32) = COPY $w0
# CHECK-NEXT:    %0:gpr(s16) = G_TRUNC %1
# %0 has been mapped to GPR, we need to repair to match FPR.
# CHECK-NEXT:    %3:fpr(s16) = COPY %0
# CHECK-NEXT:    %2:fpr(s64) = G_FPEXT %3
# CHECK-NEXT:    $d0 = COPY %2
# CHECK-NEXT:    RET_ReallyLR

body:             |
  bb.1:
    liveins: $w0

    %1(s32) = COPY $w0
    %0(s16) = G_TRUNC %1(s32)
    %2(s64) = G_FPEXT %0(s16)
    $d0 = COPY %2(s64)
    RET_ReallyLR implicit $d0

...

---
# Make sure we map FPEXT on FPR register bank.
# CHECK-LABEL: name: fp32Ext64
name:            fp32Ext64
alignment:       4
legalized:       true
# CHECK: registers:
# CHECK-NEXT:  - { id: 0, class: gpr, preferred-register: '' }
# CHECK-NEXT:  - { id: 1, class: fpr, preferred-register: '' }
# CHECK-NEXT:   - { id: 2, class: fpr, preferred-register: '' }
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
# CHECK:         %0:gpr(s32) = COPY $w0
# %0 has been mapped to GPR, we need to repair to match FPR.
# CHECK-NEXT:    %2:fpr(s32) = COPY %0
# CHECK-NEXT:    %1:fpr(s64) = G_FPEXT %2
# CHECK-NEXT:    $d0 = COPY %1
# CHECK-NEXT:    RET_ReallyLR
body:             |
  bb.1:
    liveins: $w0

    %0(s32) = COPY $w0
    %1(s64) = G_FPEXT %0(s32)
    $d0 = COPY %1(s64)
    RET_ReallyLR implicit $d0

...

---
# Make sure we map FP16 ABI on FPR register bank.
# CHECK-LABEL: name: passFp16
# CHECK: registers:
# CHECK:  - { id: 0, class: fpr, preferred-register: '' }
# CHECK:  %0:fpr(s16) = COPY $h0
# CHECK-NEXT: $h0 = COPY %0(s16)
name:            passFp16
alignment:       4
legalized:       true
registers:
  - { id: 0, class: _ }
body:             |
  bb.1.entry:
    liveins: $h0

    %0(s16) = COPY $h0
    $h0 = COPY %0(s16)
    RET_ReallyLR implicit $h0

...
---
# Make sure we properly detect fp types through copies.
# In that example, the copy comes from an ABI lowering of a fp type.
# CHECK-LABEL: name: passFp16ViaAllocas
# CHECK: registers:
# CHECK:  - { id: 0, class: fpr, preferred-register: '' }
# CHECK:  - { id: 1, class: gpr, preferred-register: '' }
# CHECK:  - { id: 2, class: fpr, preferred-register: '' }
#
# CHECK:  %0:fpr(s16) = COPY $h0
# CHECK-NEXT: %1:gpr(p0) = G_FRAME_INDEX %stack.0.p.addr
# If we didn't look through the copy for %0, the default mapping
# would have been on GPR and we would have to insert a copy to move
# the value away from FPR (h0).
# CHECK-NEXT: G_STORE %0(s16), %1(p0) :: (store (s16) into %ir.p.addr)
# If we didn't look through the copy for %2, the default mapping
# would have been on GPR and we would have to insert a copy to move
# the value to FPR (h0).
# CHECK-NEXT: %2:fpr(s16) = G_LOAD %1(p0) :: (load (s16) from %ir.p.addr)
# CHECK-NEXT: $h0 = COPY %2(s16)
name:            passFp16ViaAllocas
alignment:       4
legalized:       true
tracksRegLiveness: true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
  - { id: 2, class: _ }
frameInfo:
  maxAlignment:    2
stack:
  - { id: 0, name: p.addr, size: 2, alignment: 2, stack-id: default }
body:             |
  bb.1.entry:
    liveins: $h0

    %0(s16) = COPY $h0
    %1(p0) = G_FRAME_INDEX %stack.0.p.addr
    G_STORE %0(s16), %1(p0) :: (store (s16) into %ir.p.addr)
    %2(s16) = G_LOAD %1(p0) :: (load (s16) from %ir.p.addr)
    $h0 = COPY %2(s16)
    RET_ReallyLR implicit $h0

...