[AArch64] NFC: Generalize emitFrameOffset to support more than byte offsets.

Refactor emitFrameOffset to accept a StackOffset struct as its offset argument.
This method currently only supports byte offsets (MVT::i8) but will be extended
in a later patch to support scalable offsets (MVT::nxv1i8) as well.

Reviewers: thegameg, rovka, t.p.northover, efriedma, greened

Reviewed By: efriedma

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

llvm-svn: 368049
This commit is contained in:
Sander de Smalen 2019-08-06 15:06:31 +00:00
parent fc34a536d0
commit ad7e95df5a
1 changed files with 82 additions and 64 deletions

View File

@ -2972,23 +2972,29 @@ void AArch64InstrInfo::loadRegFromStackSlot(
MI.addMemOperand(MMO); MI.addMemOperand(MMO);
} }
void llvm::emitFrameOffset(MachineBasicBlock &MBB, // Helper function to emit a frame offset adjustment from a given
MachineBasicBlock::iterator MBBI, const DebugLoc &DL, // pointer (SrcReg), stored into DestReg. This function is explicit
unsigned DestReg, unsigned SrcReg, // in that it requires the opcode.
StackOffset SOffset, const TargetInstrInfo *TII, static void emitFrameOffsetAdj(MachineBasicBlock &MBB,
MachineInstr::MIFlag Flag, bool SetNZCV, MachineBasicBlock::iterator MBBI,
bool NeedsWinCFI, bool *HasWinCFI) { const DebugLoc &DL, unsigned DestReg,
int64_t Offset; unsigned SrcReg, int64_t Offset, unsigned Opc,
SOffset.getForFrameOffset(Offset); const TargetInstrInfo *TII,
if (DestReg == SrcReg && Offset == 0) MachineInstr::MIFlag Flag, bool NeedsWinCFI,
return; bool *HasWinCFI) {
int Sign = 1;
assert((DestReg != AArch64::SP || Offset % 16 == 0) && unsigned MaxEncoding, ShiftSize;
"SP increment/decrement not 16-byte aligned"); switch (Opc) {
case AArch64::ADDXri:
bool isSub = Offset < 0; case AArch64::ADDSXri:
if (isSub) case AArch64::SUBXri:
Offset = -Offset; case AArch64::SUBSXri:
MaxEncoding = 0xfff;
ShiftSize = 12;
break;
default:
llvm_unreachable("Unsupported opcode");
}
// FIXME: If the offset won't fit in 24-bits, compute the offset into a // FIXME: If the offset won't fit in 24-bits, compute the offset into a
// scratch register. If DestReg is a virtual register, use it as the // scratch register. If DestReg is a virtual register, use it as the
@ -3001,65 +3007,77 @@ void llvm::emitFrameOffset(MachineBasicBlock &MBB,
// of code. // of code.
// assert(Offset < (1 << 24) && "unimplemented reg plus immediate"); // assert(Offset < (1 << 24) && "unimplemented reg plus immediate");
unsigned Opc;
if (SetNZCV)
Opc = isSub ? AArch64::SUBSXri : AArch64::ADDSXri;
else
Opc = isSub ? AArch64::SUBXri : AArch64::ADDXri;
const unsigned MaxEncoding = 0xfff;
const unsigned ShiftSize = 12;
const unsigned MaxEncodableValue = MaxEncoding << ShiftSize; const unsigned MaxEncodableValue = MaxEncoding << ShiftSize;
while (((unsigned)Offset) >= (1 << ShiftSize)) { do {
unsigned ThisVal; unsigned ThisVal = std::min<unsigned>(Offset, MaxEncodableValue);
if (((unsigned)Offset) > MaxEncodableValue) { unsigned LocalShiftSize = 0;
ThisVal = MaxEncodableValue; if (ThisVal > MaxEncoding) {
} else { ThisVal = ThisVal >> ShiftSize;
ThisVal = Offset & MaxEncodableValue; LocalShiftSize = ShiftSize;
} }
assert((ThisVal >> ShiftSize) <= MaxEncoding && assert((ThisVal >> ShiftSize) <= MaxEncoding &&
"Encoding cannot handle value that big"); "Encoding cannot handle value that big");
BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) auto MBI = BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)
.addReg(SrcReg) .addReg(SrcReg)
.addImm(ThisVal >> ShiftSize) .addImm(Sign * (int)ThisVal);
.addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftSize)) if (ShiftSize)
.setMIFlag(Flag); MBI = MBI.addImm(
AArch64_AM::getShifterImm(AArch64_AM::LSL, LocalShiftSize));
if (NeedsWinCFI && SrcReg == AArch64::SP && DestReg == AArch64::SP) { MBI = MBI.setMIFlag(Flag);
if (HasWinCFI)
*HasWinCFI = true;
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_StackAlloc))
.addImm(ThisVal)
.setMIFlag(Flag);
}
SrcReg = DestReg;
Offset -= ThisVal;
if (Offset == 0)
return;
}
BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg)
.addReg(SrcReg)
.addImm(Offset)
.addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, 0))
.setMIFlag(Flag);
if (NeedsWinCFI) { if (NeedsWinCFI) {
assert(Sign == 1 && "SEH directives should always have a positive sign");
int Imm = (int)(ThisVal << LocalShiftSize);
if ((DestReg == AArch64::FP && SrcReg == AArch64::SP) || if ((DestReg == AArch64::FP && SrcReg == AArch64::SP) ||
(SrcReg == AArch64::FP && DestReg == AArch64::SP)) { (SrcReg == AArch64::FP && DestReg == AArch64::SP)) {
if (HasWinCFI) if (HasWinCFI)
*HasWinCFI = true; *HasWinCFI = true;
if (Offset == 0) if (Imm == 0)
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_SetFP)). BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_SetFP)).setMIFlag(Flag);
setMIFlag(Flag);
else else
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_AddFP)). BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_AddFP))
addImm(Offset).setMIFlag(Flag); .addImm(Imm)
.setMIFlag(Flag);
assert((Offset - Imm) == 0 && "Expected remaining offset to be zero to "
"emit a single SEH directive");
} else if (DestReg == AArch64::SP) { } else if (DestReg == AArch64::SP) {
if (HasWinCFI) if (HasWinCFI)
*HasWinCFI = true; *HasWinCFI = true;
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_StackAlloc)). assert(SrcReg == AArch64::SP && "Unexpected SrcReg for SEH_StackAlloc");
addImm(Offset).setMIFlag(Flag); BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_StackAlloc))
.addImm(Imm)
.setMIFlag(Flag);
} }
if (HasWinCFI)
*HasWinCFI = true;
}
SrcReg = DestReg;
Offset -= ThisVal << LocalShiftSize;
} while (Offset);
}
void llvm::emitFrameOffset(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
unsigned DestReg, unsigned SrcReg,
StackOffset Offset, const TargetInstrInfo *TII,
MachineInstr::MIFlag Flag, bool SetNZCV,
bool NeedsWinCFI, bool *HasWinCFI) {
int64_t Bytes;
Offset.getForFrameOffset(Bytes);
// First emit non-scalable frame offsets, or a simple 'mov'.
if (Bytes || (!Offset && SrcReg != DestReg)) {
assert((DestReg != AArch64::SP || Bytes % 16 == 0) &&
"SP increment/decrement not 16-byte aligned");
unsigned Opc = SetNZCV ? AArch64::ADDSXri : AArch64::ADDXri;
if (Bytes < 0) {
Bytes = -Bytes;
Opc = SetNZCV ? AArch64::SUBSXri : AArch64::SUBXri;
}
emitFrameOffsetAdj(MBB, MBBI, DL, DestReg, SrcReg, Bytes, Opc, TII, Flag,
NeedsWinCFI, HasWinCFI);
SrcReg = DestReg;
} }
} }