forked from OSchip/llvm-project
[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:
parent
fc34a536d0
commit
ad7e95df5a
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue