When an sreg sub-register of a q register was spilled, AArch64InstrInfo::foldMemoryOperandImpl would emit a spill of a d register, which gives the wrong result when the target is big-endian as the following q register fill will put the value in the top half. Fix this by greatly simplifying the existing code for widening the spill to only handle wzr to xzr widening, as the default result we get if the function returns nullptr is already that a widened spill will be emitted.
136 lines
11 KiB
YAML
136 lines
11 KiB
YAML
# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass greedy -verify-machineinstrs -o - %s | FileCheck %s
|
|
# RUN: llc -mtriple=aarch64_be-none-linux-gnu -run-pass greedy -verify-machineinstrs -o - %s | FileCheck %s
|
|
--- |
|
|
define i64 @test_subreg_spill_fold() { ret i64 0 }
|
|
define i64 @test_subreg_spill_fold2() { ret i64 0 }
|
|
define i64 @test_subreg_spill_fold3() { ret i64 0 }
|
|
define <4 x float> @test_subreg_spill_fold4() { ret <4 x float> undef }
|
|
define i64 @test_subreg_fill_fold() { ret i64 0 }
|
|
define double @test_subreg_fill_fold2() { ret double 0.0 }
|
|
define <4 x float> @test_subreg_fill_fold3() { ret <4 x float> undef }
|
|
define i64 @test_nzcv_spill_fold() { ret i64 0 }
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_subreg_spill_fold
|
|
# Ensure that the spilled subreg COPY is eliminated and folded into the spill store.
|
|
name: test_subreg_spill_fold
|
|
registers:
|
|
- { id: 0, class: gpr64 }
|
|
body: |
|
|
bb.0:
|
|
; CHECK: STRXui $xzr, %stack.0, 0 :: (store (s64) into %stack.0)
|
|
undef %0.sub_32 = COPY $wzr
|
|
INLINEASM &nop, 1, 12, implicit-def dead $x0, 12, implicit-def dead $x1, 12, implicit-def dead $x2, 12, implicit-def dead $x3, 12, implicit-def dead $x4, 12, implicit-def dead $x5, 12, implicit-def dead $x6, 12, implicit-def dead $x7, 12, implicit-def dead $x8, 12, implicit-def dead $x9, 12, implicit-def dead $x10, 12, implicit-def dead $x11, 12, implicit-def dead $x12, 12, implicit-def dead $x13, 12, implicit-def dead $x14, 12, implicit-def dead $x15, 12, implicit-def dead $x16, 12, implicit-def dead $x17, 12, implicit-def dead $x18, 12, implicit-def dead $x19, 12, implicit-def dead $x20, 12, implicit-def dead $x21, 12, implicit-def dead $x22, 12, implicit-def dead $x23, 12, implicit-def dead $x24, 12, implicit-def dead $x25, 12, implicit-def dead $x26, 12, implicit-def dead $x27, 12, implicit-def dead $x28, 12, implicit-def dead $fp, 12, implicit-def dead $lr, 12, implicit-def $sp
|
|
$x0 = COPY %0
|
|
RET_ReallyLR implicit $x0
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_subreg_spill_fold2
|
|
# Similar to test_subreg_spill_fold, but with a %0 register class not containing %WZR.
|
|
name: test_subreg_spill_fold2
|
|
registers:
|
|
- { id: 0, class: gpr64sp }
|
|
body: |
|
|
bb.0:
|
|
; CHECK: STRXui $xzr, %stack.0, 0 :: (store (s64) into %stack.0)
|
|
undef %0.sub_32 = COPY $wzr
|
|
INLINEASM &nop, 1, 12, implicit-def dead $x0, 12, implicit-def dead $x1, 12, implicit-def dead $x2, 12, implicit-def dead $x3, 12, implicit-def dead $x4, 12, implicit-def dead $x5, 12, implicit-def dead $x6, 12, implicit-def dead $x7, 12, implicit-def dead $x8, 12, implicit-def dead $x9, 12, implicit-def dead $x10, 12, implicit-def dead $x11, 12, implicit-def dead $x12, 12, implicit-def dead $x13, 12, implicit-def dead $x14, 12, implicit-def dead $x15, 12, implicit-def dead $x16, 12, implicit-def dead $x17, 12, implicit-def dead $x18, 12, implicit-def dead $x19, 12, implicit-def dead $x20, 12, implicit-def dead $x21, 12, implicit-def dead $x22, 12, implicit-def dead $x23, 12, implicit-def dead $x24, 12, implicit-def dead $x25, 12, implicit-def dead $x26, 12, implicit-def dead $x27, 12, implicit-def dead $x28, 12, implicit-def dead $fp, 12, implicit-def dead $lr, 12, implicit-def $sp
|
|
$x0 = ADDXri %0, 1, 0
|
|
RET_ReallyLR implicit $x0
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_subreg_spill_fold3
|
|
# Similar to test_subreg_spill_fold, but with a cross register class copy.
|
|
name: test_subreg_spill_fold3
|
|
registers:
|
|
- { id: 0, class: fpr64 }
|
|
body: |
|
|
bb.0:
|
|
; CHECK: STRXui $xzr, %stack.0, 0 :: (store (s64) into %stack.0)
|
|
undef %0.ssub = COPY $wzr
|
|
INLINEASM &nop, 1, 12, implicit-def dead $d0, 12, implicit-def dead $d1, 12, implicit-def dead $d2, 12, implicit-def dead $d3, 12, implicit-def dead $d4, 12, implicit-def dead $d5, 12, implicit-def dead $d6, 12, implicit-def dead $d7, 12, implicit-def dead $d8, 12, implicit-def dead $d9, 12, implicit-def dead $d10, 12, implicit-def dead $d11, 12, implicit-def dead $d12, 12, implicit-def dead $d13, 12, implicit-def dead $d14, 12, implicit-def dead $d15, 12, implicit-def dead $d16, 12, implicit-def dead $d17, 12, implicit-def dead $d18, 12, implicit-def dead $d19, 12, implicit-def dead $d20, 12, implicit-def dead $d21, 12, implicit-def dead $d22, 12, implicit-def dead $d23, 12, implicit-def dead $d24, 12, implicit-def dead $d25, 12, implicit-def dead $d26, 12, implicit-def dead $d27, 12, implicit-def dead $d28, 12, implicit-def dead $d29, 12, implicit-def dead $d30, 12, implicit-def $d31
|
|
$x0 = COPY %0
|
|
RET_ReallyLR implicit $x0
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_subreg_spill_fold4
|
|
# A spilled write to a 128-bit register needs a 128-bit store
|
|
name: test_subreg_spill_fold4
|
|
registers:
|
|
- { id: 0, class: fpr128 }
|
|
body: |
|
|
bb.0:
|
|
; CHECK: undef %1.ssub:fpr128 = COPY $wzr
|
|
; CHECK-NEXT: STRQui %1, %stack.0, 0 :: (store (s128) into %stack.0)
|
|
undef %0.ssub:fpr128 = COPY $wzr
|
|
INLINEASM &nop, 1, 12, implicit-def dead $d0, 12, implicit-def dead $d1, 12, implicit-def dead $d2, 12, implicit-def dead $d3, 12, implicit-def dead $d4, 12, implicit-def dead $d5, 12, implicit-def dead $d6, 12, implicit-def dead $d7, 12, implicit-def dead $d8, 12, implicit-def dead $d9, 12, implicit-def dead $d10, 12, implicit-def dead $d11, 12, implicit-def dead $d12, 12, implicit-def dead $d13, 12, implicit-def dead $d14, 12, implicit-def dead $d15, 12, implicit-def dead $d16, 12, implicit-def dead $d17, 12, implicit-def dead $d18, 12, implicit-def dead $d19, 12, implicit-def dead $d20, 12, implicit-def dead $d21, 12, implicit-def dead $d22, 12, implicit-def dead $d23, 12, implicit-def dead $d24, 12, implicit-def dead $d25, 12, implicit-def dead $d26, 12, implicit-def dead $d27, 12, implicit-def dead $d28, 12, implicit-def dead $d29, 12, implicit-def dead $d30, 12, implicit-def $d31
|
|
$q0 = COPY %0
|
|
RET_ReallyLR implicit $q0
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_subreg_fill_fold
|
|
# Ensure that the filled COPY is eliminated and folded into the fill load.
|
|
name: test_subreg_fill_fold
|
|
registers:
|
|
- { id: 0, class: gpr32 }
|
|
- { id: 1, class: gpr64 }
|
|
body: |
|
|
bb.0:
|
|
%0 = COPY $wzr
|
|
INLINEASM &nop, 1, 12, implicit-def dead $x0, 12, implicit-def dead $x1, 12, implicit-def dead $x2, 12, implicit-def dead $x3, 12, implicit-def dead $x4, 12, implicit-def dead $x5, 12, implicit-def dead $x6, 12, implicit-def dead $x7, 12, implicit-def dead $x8, 12, implicit-def dead $x9, 12, implicit-def dead $x10, 12, implicit-def dead $x11, 12, implicit-def dead $x12, 12, implicit-def dead $x13, 12, implicit-def dead $x14, 12, implicit-def dead $x15, 12, implicit-def dead $x16, 12, implicit-def dead $x17, 12, implicit-def dead $x18, 12, implicit-def dead $x19, 12, implicit-def dead $x20, 12, implicit-def dead $x21, 12, implicit-def dead $x22, 12, implicit-def dead $x23, 12, implicit-def dead $x24, 12, implicit-def dead $x25, 12, implicit-def dead $x26, 12, implicit-def dead $x27, 12, implicit-def dead $x28, 12, implicit-def dead $fp, 12, implicit-def dead $lr, 12, implicit-def $sp
|
|
; CHECK: undef %1.sub_32:gpr64 = LDRWui %stack.0, 0 :: (load (s32) from %stack.0)
|
|
undef %1.sub_32 = COPY %0
|
|
$x0 = COPY %1
|
|
RET_ReallyLR implicit $x0
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_subreg_fill_fold2
|
|
# Similar to test_subreg_fill_fold, but with a cross-class copy.
|
|
name: test_subreg_fill_fold2
|
|
registers:
|
|
- { id: 0, class: gpr32 }
|
|
- { id: 1, class: fpr64 }
|
|
body: |
|
|
bb.0:
|
|
%0 = COPY $wzr
|
|
INLINEASM &nop, 1, 12, implicit-def dead $x0, 12, implicit-def dead $x1, 12, implicit-def dead $x2, 12, implicit-def dead $x3, 12, implicit-def dead $x4, 12, implicit-def dead $x5, 12, implicit-def dead $x6, 12, implicit-def dead $x7, 12, implicit-def dead $x8, 12, implicit-def dead $x9, 12, implicit-def dead $x10, 12, implicit-def dead $x11, 12, implicit-def dead $x12, 12, implicit-def dead $x13, 12, implicit-def dead $x14, 12, implicit-def dead $x15, 12, implicit-def dead $x16, 12, implicit-def dead $x17, 12, implicit-def dead $x18, 12, implicit-def dead $x19, 12, implicit-def dead $x20, 12, implicit-def dead $x21, 12, implicit-def dead $x22, 12, implicit-def dead $x23, 12, implicit-def dead $x24, 12, implicit-def dead $x25, 12, implicit-def dead $x26, 12, implicit-def dead $x27, 12, implicit-def dead $x28, 12, implicit-def dead $fp, 12, implicit-def dead $lr, 12, implicit-def $sp
|
|
; CHECK: undef %1.ssub:fpr64 = LDRSui %stack.0, 0 :: (load (s32) from %stack.0)
|
|
undef %1.ssub = COPY %0
|
|
$d0 = COPY %1
|
|
RET_ReallyLR implicit $d0
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_subreg_fill_fold3
|
|
# A filled copy from a sub-register should load the whole register
|
|
name: test_subreg_fill_fold3
|
|
tracksRegLiveness: true
|
|
registers:
|
|
- { id: 0, class: fpr128 }
|
|
liveins:
|
|
- { reg: '$q0' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $q0
|
|
%0 = COPY $q0
|
|
INLINEASM &nop, 1, 12, implicit-def dead $d0, 12, implicit-def dead $d1, 12, implicit-def dead $d2, 12, implicit-def dead $d3, 12, implicit-def dead $d4, 12, implicit-def dead $d5, 12, implicit-def dead $d6, 12, implicit-def dead $d7, 12, implicit-def dead $d8, 12, implicit-def dead $d9, 12, implicit-def dead $d10, 12, implicit-def dead $d11, 12, implicit-def dead $d12, 12, implicit-def dead $d13, 12, implicit-def dead $d14, 12, implicit-def dead $d15, 12, implicit-def dead $d16, 12, implicit-def dead $d17, 12, implicit-def dead $d18, 12, implicit-def dead $d19, 12, implicit-def dead $d20, 12, implicit-def dead $d21, 12, implicit-def dead $d22, 12, implicit-def dead $d23, 12, implicit-def dead $d24, 12, implicit-def dead $d25, 12, implicit-def dead $d26, 12, implicit-def dead $d27, 12, implicit-def dead $d28, 12, implicit-def dead $d29, 12, implicit-def dead $d30, 12, implicit-def $d31
|
|
; CHECK: %1:fpr128 = LDRQui %stack.0, 0 :: (load (s128) from %stack.0)
|
|
; CHECK-NEXT: $s0 = COPY %1.ssub
|
|
$s0 = COPY %0.ssub
|
|
RET_ReallyLR implicit $s0
|
|
...
|
|
---
|
|
# CHECK-LABEL: name: test_nzcv_spill_fold
|
|
# Ensure that nzcv COPY cannot be folded.
|
|
name: test_nzcv_spill_fold
|
|
registers:
|
|
- { id: 0, class: gpr64 }
|
|
body: |
|
|
bb.0:
|
|
; CHECK: %1:gpr64 = COPY $nzcv
|
|
; CHECK: STRXui %1, %stack.0, 0 :: (store (s64) into %stack.0)
|
|
%0 = COPY $nzcv
|
|
INLINEASM &nop, 1, 12, implicit-def dead $x0, 12, implicit-def dead $x1, 12, implicit-def dead $x2, 12, implicit-def dead $x3, 12, implicit-def dead $x4, 12, implicit-def dead $x5, 12, implicit-def dead $x6, 12, implicit-def dead $x7, 12, implicit-def dead $x8, 12, implicit-def dead $x9, 12, implicit-def dead $x10, 12, implicit-def dead $x11, 12, implicit-def dead $x12, 12, implicit-def dead $x13, 12, implicit-def dead $x14, 12, implicit-def dead $x15, 12, implicit-def dead $x16, 12, implicit-def dead $x17, 12, implicit-def dead $x18, 12, implicit-def dead $x19, 12, implicit-def dead $x20, 12, implicit-def dead $x21, 12, implicit-def dead $x22, 12, implicit-def dead $x23, 12, implicit-def dead $x24, 12, implicit-def dead $x25, 12, implicit-def dead $x26, 12, implicit-def dead $x27, 12, implicit-def dead $x28, 12, implicit-def dead $fp, 12, implicit-def dead $lr, 12, implicit-def $sp
|
|
$x0 = COPY %0
|
|
RET_ReallyLR implicit $x0
|
|
...
|