[AArch64] Ensure FPR128 callee-save stack offsets are aligned (#184314)
This was benign for Linux targets (as when dividing by the scale the offset would be correctly truncated), so only resulted in failures with `-DLLVM_ENABLE_ASSERTIONS=On`. On Windows, this was a miscompile as the lack of alignment would result in the FPR128 callee-save getting assigned to the same offset as the previous GPR. Fixes: #183708
This commit is contained in:
parent
03347e0834
commit
327f1adef8
3 changed files with 86 additions and 5 deletions
|
|
@ -1730,6 +1730,12 @@ void computeCalleeSaveRegisterPairs(const AArch64FrameLowering &AFL,
|
|||
Register LastReg = 0;
|
||||
bool HasCSHazardPadding = AFI->hasStackHazardSlotIndex() && !SplitPPRs;
|
||||
|
||||
auto AlignOffset = [StackFillDir](int Offset, int Align) {
|
||||
if (StackFillDir < 0)
|
||||
return alignDown(Offset, Align);
|
||||
return alignTo(Offset, Align);
|
||||
};
|
||||
|
||||
// When iterating backwards, the loop condition relies on unsigned wraparound.
|
||||
for (unsigned i = FirstReg; i < Count; i += RegInc) {
|
||||
RegPairInfo RPI;
|
||||
|
|
@ -1844,11 +1850,15 @@ void computeCalleeSaveRegisterPairs(const AArch64FrameLowering &AFL,
|
|||
RPI.isPaired()) // RPI.FrameIdx must be the lower index of the pair
|
||||
RPI.FrameIdx = CSI[i + RegInc].getFrameIdx();
|
||||
|
||||
// Realign the scalable offset if necessary. This is relevant when
|
||||
// spilling predicates on Windows.
|
||||
if (RPI.isScalable() && ScalableByteOffset % Scale != 0) {
|
||||
ScalableByteOffset = alignTo(ScalableByteOffset, Scale);
|
||||
}
|
||||
// Realign the scalable offset if necessary. This is relevant when spilling
|
||||
// predicates on Windows.
|
||||
if (RPI.isScalable() && ScalableByteOffset % Scale != 0)
|
||||
ScalableByteOffset = AlignOffset(ScalableByteOffset, Scale);
|
||||
|
||||
// Realign the fixed offset if necessary. This is relevant when spilling Q
|
||||
// registers after spilling an odd amount of X registers.
|
||||
if (!RPI.isScalable() && ByteOffset % Scale != 0)
|
||||
ByteOffset = AlignOffset(ByteOffset, Scale);
|
||||
|
||||
int OffsetPre = RPI.isScalable() ? ScalableByteOffset : ByteOffset;
|
||||
assert(OffsetPre % Scale == 0);
|
||||
|
|
|
|||
33
llvm/test/CodeGen/AArch64/framelayout-fpr128-csr.ll
Normal file
33
llvm/test/CodeGen/AArch64/framelayout-fpr128-csr.ll
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
|
||||
; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s
|
||||
; RUN: llc -verify-machineinstrs -mtriple=aarch64-windows-msvc < %s | FileCheck %s --check-prefix=CHECK-WINDOWS
|
||||
|
||||
; The purpose of this test is to verify q8 is assigned a 16-byte aligned offset
|
||||
; after the x10 is assigned an offset. The CSR (on Linux) are assigned offsets
|
||||
; in the order GPRs then FPRs. The stack size of this function is 48
|
||||
; (alignTo((16 + 8 * 3), 16)), so after x8 is given the offset 24, q8 originally
|
||||
; would be assigned offset 8, which is not 16-byte aligned.
|
||||
define preserve_allcc void @d(ptr %ptr) nounwind {
|
||||
; CHECK-LABEL: d:
|
||||
; CHECK: // %bb.0: // %entry
|
||||
; CHECK-NEXT: str q8, [sp, #-32]! // 16-byte Folded Spill
|
||||
; CHECK-NEXT: str x10, [sp, #24] // 8-byte Spill
|
||||
; CHECK-NEXT: //APP
|
||||
; CHECK-NEXT: //NO_APP
|
||||
; CHECK-NEXT: ldr x10, [sp, #24] // 8-byte Reload
|
||||
; CHECK-NEXT: ldr q8, [sp], #32 // 16-byte Folded Reload
|
||||
; CHECK-NEXT: ret
|
||||
;
|
||||
; CHECK-WINDOWS-LABEL: d:
|
||||
; CHECK-WINDOWS: // %bb.0: // %entry
|
||||
; CHECK-WINDOWS-NEXT: str x10, [sp, #-32]! // 8-byte Folded Spill
|
||||
; CHECK-WINDOWS-NEXT: str q8, [sp, #16] // 16-byte Spill
|
||||
; CHECK-WINDOWS-NEXT: //APP
|
||||
; CHECK-WINDOWS-NEXT: //NO_APP
|
||||
; CHECK-WINDOWS-NEXT: ldr q8, [sp, #16] // 16-byte Reload
|
||||
; CHECK-WINDOWS-NEXT: ldr x10, [sp], #32 // 8-byte Folded Reload
|
||||
; CHECK-WINDOWS-NEXT: ret
|
||||
entry:
|
||||
tail call void asm sideeffect "", "~{x10},~{q8}"()
|
||||
ret void
|
||||
}
|
||||
38
llvm/test/CodeGen/AArch64/framelayout-fpr128-spill.mir
Normal file
38
llvm/test/CodeGen/AArch64/framelayout-fpr128-spill.mir
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
|
||||
# RUN: llc -mtriple=aarch64-linux-gnu -run-pass=prologepilog %s -o - | FileCheck %s
|
||||
# RUN: llc -mtriple=aarch64-windows-msvc -run-pass=prologepilog %s -o - | FileCheck %s --check-prefix=CHECK-WINDOWS
|
||||
|
||||
--- |
|
||||
; Tests Q8 is assigned a 16-byte aligned offset after X10 is assigned an offset.
|
||||
define preserve_allcc void @test_fpr128_spill_alignment() nounwind { entry: unreachable }
|
||||
...
|
||||
---
|
||||
name: test_fpr128_spill_alignment
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
; CHECK-LABEL: name: test_fpr128_spill_alignment
|
||||
; CHECK: liveins: $q8, $x10
|
||||
; CHECK-NEXT: {{ $}}
|
||||
; CHECK-NEXT: early-clobber $sp = frame-setup STRQpre killed $q8, $sp, -32 :: (store (s128) into %stack.1)
|
||||
; CHECK-NEXT: frame-setup STRXui killed $x10, $sp, 3 :: (store (s64) into %stack.0)
|
||||
; CHECK-NEXT: $q8 = IMPLICIT_DEF
|
||||
; CHECK-NEXT: $x10 = IMPLICIT_DEF
|
||||
; CHECK-NEXT: $x10 = frame-destroy LDRXui $sp, 3 :: (load (s64) from %stack.0)
|
||||
; CHECK-NEXT: early-clobber $sp, $q8 = frame-destroy LDRQpost $sp, 32 :: (load (s128) from %stack.1)
|
||||
; CHECK-NEXT: RET_ReallyLR
|
||||
;
|
||||
; CHECK-WINDOWS-LABEL: name: test_fpr128_spill_alignment
|
||||
; CHECK-WINDOWS: liveins: $x10, $q8
|
||||
; CHECK-WINDOWS-NEXT: {{ $}}
|
||||
; CHECK-WINDOWS-NEXT: early-clobber $sp = frame-setup STRXpre killed $x10, $sp, -32 :: (store (s64) into %stack.1)
|
||||
; CHECK-WINDOWS-NEXT: frame-setup STRQui killed $q8, $sp, 1 :: (store (s128) into %stack.0)
|
||||
; CHECK-WINDOWS-NEXT: $q8 = IMPLICIT_DEF
|
||||
; CHECK-WINDOWS-NEXT: $x10 = IMPLICIT_DEF
|
||||
; CHECK-WINDOWS-NEXT: $q8 = frame-destroy LDRQui $sp, 1 :: (load (s128) from %stack.0)
|
||||
; CHECK-WINDOWS-NEXT: early-clobber $sp, $x10 = frame-destroy LDRXpost $sp, 32 :: (load (s64) from %stack.1)
|
||||
; CHECK-WINDOWS-NEXT: RET_ReallyLR
|
||||
$q8 = IMPLICIT_DEF
|
||||
$x10 = IMPLICIT_DEF
|
||||
RET_ReallyLR
|
||||
...
|
||||
Loading…
Reference in a new issue