[AArch64] Fix offset calculation

r374772 changed Offset to be an int64_t but left NewOffset as an int.
Scale is unsigned, so in the calculation `Offset - NewOffset * Scale`,
`NewOffset * Scale` was promoted to unsigned and was then zero-extended
to 64 bits, leading to an incorrect computation which manifested as an
out-of-memory when building the Swift standard library for Android
aarch64. Promote NewOffset to int64_t to fix this, and promote
EmittableOffset as well, since its one user passes it to a function
which takes an int64_t anyway.

Test case based on a suggestion by Sander de Smalen!

Differential Revision: https://reviews.llvm.org/D69018

llvm-svn: 375043
This commit is contained in:
Shoaib Meenai 2019-10-16 21:41:05 +00:00
parent 34ed76e180
commit 6d1891c508
3 changed files with 21 additions and 4 deletions

View File

@ -3368,7 +3368,7 @@ int llvm::isAArch64FrameOffsetLegal(const MachineInstr &MI,
StackOffset &SOffset, StackOffset &SOffset,
bool *OutUseUnscaledOp, bool *OutUseUnscaledOp,
unsigned *OutUnscaledOp, unsigned *OutUnscaledOp,
int *EmittableOffset) { int64_t *EmittableOffset) {
// Set output values in case of early exit. // Set output values in case of early exit.
if (EmittableOffset) if (EmittableOffset)
*EmittableOffset = 0; *EmittableOffset = 0;
@ -3430,7 +3430,7 @@ int llvm::isAArch64FrameOffsetLegal(const MachineInstr &MI,
"Cannot have remainder when using unscaled op"); "Cannot have remainder when using unscaled op");
assert(MinOff < MaxOff && "Unexpected Min/Max offsets"); assert(MinOff < MaxOff && "Unexpected Min/Max offsets");
int NewOffset = Offset / Scale; int64_t NewOffset = Offset / Scale;
if (MinOff <= NewOffset && NewOffset <= MaxOff) if (MinOff <= NewOffset && NewOffset <= MaxOff)
Offset = Remainder; Offset = Remainder;
else { else {
@ -3471,7 +3471,7 @@ bool llvm::rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
return true; return true;
} }
int NewOffset; int64_t NewOffset;
unsigned UnscaledOp; unsigned UnscaledOp;
bool UseUnscaledOp; bool UseUnscaledOp;
int Status = isAArch64FrameOffsetLegal(MI, Offset, &UseUnscaledOp, int Status = isAArch64FrameOffsetLegal(MI, Offset, &UseUnscaledOp,

View File

@ -335,7 +335,7 @@ enum AArch64FrameOffsetStatus {
int isAArch64FrameOffsetLegal(const MachineInstr &MI, StackOffset &Offset, int isAArch64FrameOffsetLegal(const MachineInstr &MI, StackOffset &Offset,
bool *OutUseUnscaledOp = nullptr, bool *OutUseUnscaledOp = nullptr,
unsigned *OutUnscaledOp = nullptr, unsigned *OutUnscaledOp = nullptr,
int *EmittableOffset = nullptr); int64_t *EmittableOffset = nullptr);
static inline bool isUncondBranchOpcode(int Opc) { return Opc == AArch64::B; } static inline bool isUncondBranchOpcode(int Opc) { return Opc == AArch64::B; }

View File

@ -0,0 +1,17 @@
# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass=prologepilog %s -o - | FileCheck %s
---
name: framelayout_offset_immediate_change
tracksRegLiveness: true
fixedStack:
- { id: 0, offset: 0, size: 1}
body: |
bb.0:
$x0 = LDURXi %fixed-stack.0, -264
RET_ReallyLR
...
# CHECK: name: framelayout_offset_immediate_change
# CHECK: body: |
# CHECK-NEXT: bb.0:
# CHECK-NEXT: $x8 = SUBXri $sp, 8, 0
# CHECK-NEXT: $x0 = LDURXi killed $x8, -256
# CHECK-NEXT: RET_ReallyLR