blob: f5d85e189d75e862900a3ae887e609f8507f362c [file] [log] [blame]
# RUN: llc -O0 -run-pass=regbankselect -global-isel %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=FAST
# RUN: llc -O0 -run-pass=regbankselect -global-isel %s -regbankselect-greedy -o - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=GREEDY
# REQUIRES: global-isel
--- |
; ModuleID = 'generic-virtual-registers-type-error.mir'
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-apple-ios"
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(i32* %src, i32* %dst, i1 %cond) {
entry:
%srcVal = load i32, i32* %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, i32* %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
}
...
---
# Check that we assign a relevant register bank for %0.
# Based on the type i32, this should be gpr.
name: defaultMapping
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr }
registers:
- { id: 0, class: _ }
body: |
bb.0.entry:
liveins: %x0
; CHECK: %0(32) = G_ADD i32 %x0
%0(32) = G_ADD i32 %x0, %x0
...
---
# 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
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: fpr }
registers:
- { id: 0, class: _ }
body: |
bb.0.entry:
liveins: %d0
; CHECK: %0(32) = G_ADD <2 x i32> %d0
%0(32) = G_ADD <2 x i32> %d0, %d0
...
---
# 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
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: fpr }
# CHECK-NEXT: - { id: 1, class: gpr }
# CHECK-NEXT: - { id: 2, class: gpr }
registers:
- { id: 0, class: _ }
- { id: 1, class: _ }
body: |
bb.0.entry:
liveins: %s0, %x0
; CHECK: %0(32) = COPY %s0
; CHECK-NEXT: %2(32) = COPY %0
; CHECK-NEXT: %1(32) = G_ADD i32 %2, %x0
%0(32) = COPY %s0
%1(32) = G_ADD i32 %0, %x0
...
# Check that we repair the assignment for %0 differently for both uses.
name: defaultMapping2Repairs
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: fpr }
# CHECK-NEXT: - { id: 1, class: gpr }
# CHECK-NEXT: - { id: 2, class: gpr }
# CHECK-NEXT: - { id: 3, class: gpr }
registers:
- { id: 0, class: _ }
- { id: 1, class: _ }
body: |
bb.0.entry:
liveins: %s0, %x0
; CHECK: %0(32) = COPY %s0
; CHECK-NEXT: %2(32) = COPY %0
; CHECK-NEXT: %3(32) = COPY %0
; CHECK-NEXT: %1(32) = G_ADD i32 %2, %3
%0(32) = COPY %s0
%1(32) = G_ADD i32 %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
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr }
# CHECK-NEXT: - { id: 1, class: fpr }
# CHECK-NEXT: - { id: 2, class: gpr }
registers:
- { id: 0, class: _ }
- { id: 1, class: fpr }
body: |
bb.0.entry:
liveins: %w0
; CHECK: %0(32) = COPY %w0
; CHECK-NEXT: %2(32) = G_ADD i32 %0, %w0
; CHECK-NEXT: %1(32) = COPY %2
%0(32) = COPY %w0
%1(32) = G_ADD i32 %0, %w0
...
---
# Check that we are able to propagate register banks from phis.
name: phiPropagation
isSSA: true
tracksRegLiveness: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr32 }
# CHECK-NEXT: - { id: 1, class: gpr64sp }
# CHECK-NEXT: - { id: 2, class: gpr32 }
# CHECK-NEXT: - { id: 3, class: gpr }
# CHECK-NEXT: - { id: 4, class: gpr }
registers:
- { id: 0, class: gpr32 }
- { id: 1, class: gpr64sp }
- { id: 2, class: gpr32 }
- { id: 3, class: _ }
- { id: 4, class: _ }
body: |
bb.0.entry:
successors: %bb.2.end, %bb.1.then
liveins: %x0, %x1, %w2
%0 = LDRWui killed %x0, 0 :: (load 4 from %ir.src)
%1 = COPY %x1
%2 = COPY %w2
TBNZW killed %2, 0, %bb.2.end
bb.1.then:
successors: %bb.2.end
%3(32) = G_ADD i32 %0, %0
bb.2.end:
%4(32) = PHI %0, %bb.0.entry, %3, %bb.1.then
STRWui killed %4, killed %1, 0 :: (store 4 into %ir.dst)
RET_ReallyLR
...
---
# Make sure we can repair physical register uses as well.
name: defaultMappingUseRepairPhysReg
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr }
# CHECK-NEXT: - { id: 1, class: gpr }
# CHECK-NEXT: - { id: 2, class: gpr }
registers:
- { id: 0, class: _ }
- { id: 1, class: _ }
body: |
bb.0.entry:
liveins: %w0, %s0
; CHECK: %0(32) = COPY %w0
; CHECK-NEXT: %2(32) = COPY %s0
; CHECK-NEXT: %1(32) = G_ADD i32 %0, %2
%0(32) = COPY %w0
%1(32) = G_ADD i32 %0, %s0
...
---
# Make sure we can repair physical register defs.
name: defaultMappingDefRepairPhysReg
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr }
# CHECK-NEXT: - { id: 1, class: gpr }
registers:
- { id: 0, class: _ }
body: |
bb.0.entry:
liveins: %w0
; CHECK: %0(32) = COPY %w0
; CHECK-NEXT: %1(32) = G_ADD i32 %0, %0
; CHECK-NEXT: %s0 = COPY %1
%0(32) = COPY %w0
%s0 = G_ADD i32 %0, %0
...
---
# Check that the greedy mode is able to switch the
# G_OR instruction from fpr to gpr.
name: greedyMappingOr
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr }
# CHECK-NEXT: - { id: 1, class: gpr }
# Fast mode maps vector instruction on FPR.
# FAST-NEXT: - { id: 2, class: fpr }
# Fast mode needs two extra copies.
# FAST-NEXT: - { id: 3, class: fpr }
# FAST-NEXT: - { id: 4, class: fpr }
# Greedy mode coalesce the computation on the GPR register
# because it is the cheapest.
# GREEDY-NEXT: - { id: 2, class: gpr }
registers:
- { id: 0, class: _ }
- { id: 1, class: _ }
- { id: 2, class: _ }
body: |
bb.0.entry:
liveins: %x0, %x1
; CHECK: %0(64) = COPY %x0
; CHECK-NEXT: %1(64) = 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(64) = COPY %0
; FAST-NEXT: %4(64) = COPY %1
; The mapping of G_OR is on FPR.
; FAST-NEXT: %2(64) = G_OR <2 x i32> %3, %4
; Greedy mode remapped the instruction on the GPR bank.
; GREEDY-NEXT: %2(64) = G_OR <2 x i32> %0, %1
%0(64) = COPY %x0
%1(64) = COPY %x1
%2(64) = G_OR <2 x i32> %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
isSSA: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr }
# CHECK-NEXT: - { id: 1, class: gpr }
# CHECK-NEXT: - { id: 2, class: fpr }
# Fast mode maps vector instruction on FPR.
# Fast mode needs two extra copies.
# FAST-NEXT: - { id: 3, class: fpr }
# FAST-NEXT: - { id: 4, class: fpr }
# Greedy mode coalesce the computation on the GPR register because it
# is the cheapest, but will need one extra copy to materialize %2 into a FPR.
# GREEDY-NEXT: - { id: 3, class: gpr }
registers:
- { id: 0, class: _ }
- { id: 1, class: _ }
- { id: 2, class: fpr }
body: |
bb.0.entry:
liveins: %x0, %x1
; CHECK: %0(64) = COPY %x0
; CHECK-NEXT: %1(64) = 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(64) = COPY %0
; FAST-NEXT: %4(64) = COPY %1
; The mapping of G_OR is on FPR.
; FAST-NEXT: %2(64) = G_OR <2 x i32> %3, %4
; Greedy mode remapped the instruction on the GPR bank.
; GREEDY-NEXT: %3(64) = G_OR <2 x i32> %0, %1
; We need to keep %2 into FPR because we do not know anything about it.
; GREEDY-NEXT: %2(64) = COPY %3
%0(64) = COPY %x0
%1(64) = COPY %x1
%2(64) = G_OR <2 x i32> %0, %1
...