ARM64: model pre/post-indexed operations properly.

We should be keeping track of the writeback on these instructions,
otherwise we're relying on LLVM's stupidity for correct code.

Fortunately, the MC layer can now handle all required constraints,
which means we can get rid of the CodeGen only PseudoInsts too.

llvm-svn: 209426
This commit is contained in:
Tim Northover 2014-05-22 11:56:20 +00:00
parent c350acfda5
commit 4a3ab28ac7
9 changed files with 237 additions and 332 deletions

View File

@ -423,45 +423,6 @@ void ARM64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
// instructions) auto-generated. // instructions) auto-generated.
#include "ARM64GenMCPseudoLowering.inc" #include "ARM64GenMCPseudoLowering.inc"
static unsigned getRealIndexedOpcode(unsigned Opc) {
switch (Opc) {
case ARM64::LDRXpre_isel: return ARM64::LDRXpre;
case ARM64::LDRWpre_isel: return ARM64::LDRWpre;
case ARM64::LDRQpre_isel: return ARM64::LDRQpre;
case ARM64::LDRDpre_isel: return ARM64::LDRDpre;
case ARM64::LDRSpre_isel: return ARM64::LDRSpre;
case ARM64::LDRBBpre_isel: return ARM64::LDRBBpre;
case ARM64::LDRHHpre_isel: return ARM64::LDRHHpre;
case ARM64::LDRSBWpre_isel: return ARM64::LDRSBWpre;
case ARM64::LDRSBXpre_isel: return ARM64::LDRSBXpre;
case ARM64::LDRSHWpre_isel: return ARM64::LDRSHWpre;
case ARM64::LDRSHXpre_isel: return ARM64::LDRSHXpre;
case ARM64::LDRSWpre_isel: return ARM64::LDRSWpre;
case ARM64::LDRQpost_isel: return ARM64::LDRQpost;
case ARM64::LDRDpost_isel: return ARM64::LDRDpost;
case ARM64::LDRSpost_isel: return ARM64::LDRSpost;
case ARM64::LDRXpost_isel: return ARM64::LDRXpost;
case ARM64::LDRWpost_isel: return ARM64::LDRWpost;
case ARM64::LDRHHpost_isel: return ARM64::LDRHHpost;
case ARM64::LDRBBpost_isel: return ARM64::LDRBBpost;
case ARM64::LDRSWpost_isel: return ARM64::LDRSWpost;
case ARM64::LDRSHWpost_isel: return ARM64::LDRSHWpost;
case ARM64::LDRSHXpost_isel: return ARM64::LDRSHXpost;
case ARM64::LDRSBWpost_isel: return ARM64::LDRSBWpost;
case ARM64::LDRSBXpost_isel: return ARM64::LDRSBXpost;
case ARM64::STRXpre_isel: return ARM64::STRXpre;
case ARM64::STRWpre_isel: return ARM64::STRWpre;
case ARM64::STRHHpre_isel: return ARM64::STRHHpre;
case ARM64::STRBBpre_isel: return ARM64::STRBBpre;
case ARM64::STRQpre_isel: return ARM64::STRQpre;
case ARM64::STRDpre_isel: return ARM64::STRDpre;
case ARM64::STRSpre_isel: return ARM64::STRSpre;
}
llvm_unreachable("Unexpected pre-indexed opcode!");
}
void ARM64AsmPrinter::EmitInstruction(const MachineInstr *MI) { void ARM64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
// Do any auto-generated pseudo lowerings. // Do any auto-generated pseudo lowerings.
if (emitPseudoExpansionLowering(OutStreamer, MI)) if (emitPseudoExpansionLowering(OutStreamer, MI))
@ -488,60 +449,6 @@ void ARM64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
} }
return; return;
} }
// Indexed loads and stores use a pseudo to handle complex operand
// tricks and writeback to the base register. We strip off the writeback
// operand and switch the opcode here. Post-indexed stores were handled by the
// tablegen'erated pseudos above. (The complex operand <--> simple
// operand isel is beyond tablegen's ability, so we do these manually).
case ARM64::LDRHHpre_isel:
case ARM64::LDRBBpre_isel:
case ARM64::LDRXpre_isel:
case ARM64::LDRWpre_isel:
case ARM64::LDRQpre_isel:
case ARM64::LDRDpre_isel:
case ARM64::LDRSpre_isel:
case ARM64::LDRSBWpre_isel:
case ARM64::LDRSBXpre_isel:
case ARM64::LDRSHWpre_isel:
case ARM64::LDRSHXpre_isel:
case ARM64::LDRSWpre_isel:
case ARM64::LDRQpost_isel:
case ARM64::LDRDpost_isel:
case ARM64::LDRSpost_isel:
case ARM64::LDRXpost_isel:
case ARM64::LDRWpost_isel:
case ARM64::LDRHHpost_isel:
case ARM64::LDRBBpost_isel:
case ARM64::LDRSWpost_isel:
case ARM64::LDRSHWpost_isel:
case ARM64::LDRSHXpost_isel:
case ARM64::LDRSBWpost_isel:
case ARM64::LDRSBXpost_isel: {
MCInst TmpInst;
// For loads, the writeback operand to be skipped is the second.
TmpInst.setOpcode(getRealIndexedOpcode(MI->getOpcode()));
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(2).getReg()));
TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
EmitToStreamer(OutStreamer, TmpInst);
return;
}
case ARM64::STRXpre_isel:
case ARM64::STRWpre_isel:
case ARM64::STRHHpre_isel:
case ARM64::STRBBpre_isel:
case ARM64::STRQpre_isel:
case ARM64::STRDpre_isel:
case ARM64::STRSpre_isel: {
MCInst TmpInst;
// For loads, the writeback operand to be skipped is the first.
TmpInst.setOpcode(getRealIndexedOpcode(MI->getOpcode()));
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(2).getReg()));
TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
EmitToStreamer(OutStreamer, TmpInst);
return;
}
// Tail calls use pseudo instructions so they have the proper code-gen // Tail calls use pseudo instructions so they have the proper code-gen
// attributes (isCall, isReturn, etc.). We lower them to the real // attributes (isCall, isReturn, etc.). We lower them to the real

View File

@ -246,14 +246,14 @@ void ARM64FrameLowering::emitPrologue(MachineFunction &MF) const {
// that is a multiple of -2. // that is a multiple of -2.
assert((MBBI->getOpcode() == ARM64::STPXpre || assert((MBBI->getOpcode() == ARM64::STPXpre ||
MBBI->getOpcode() == ARM64::STPDpre) && MBBI->getOpcode() == ARM64::STPDpre) &&
MBBI->getOperand(2).getReg() == ARM64::SP && MBBI->getOperand(3).getReg() == ARM64::SP &&
MBBI->getOperand(3).getImm() < 0 && MBBI->getOperand(4).getImm() < 0 &&
(MBBI->getOperand(3).getImm() & 1) == 0); (MBBI->getOperand(4).getImm() & 1) == 0);
// Frame pointer is fp = sp - 16. Since the STPXpre subtracts the space // Frame pointer is fp = sp - 16. Since the STPXpre subtracts the space
// required for the callee saved register area we get the frame pointer // required for the callee saved register area we get the frame pointer
// by addding that offset - 16 = -getImm()*8 - 2*8 = -(getImm() + 2) * 8. // by addding that offset - 16 = -getImm()*8 - 2*8 = -(getImm() + 2) * 8.
FPOffset = -(MBBI->getOperand(3).getImm() + 2) * 8; FPOffset = -(MBBI->getOperand(4).getImm() + 2) * 8;
assert(FPOffset >= 0 && "Bad Framepointer Offset"); assert(FPOffset >= 0 && "Bad Framepointer Offset");
} }
@ -409,12 +409,16 @@ static bool isCalleeSavedRegister(unsigned Reg, const MCPhysReg *CSRegs) {
} }
static bool isCSRestore(MachineInstr *MI, const MCPhysReg *CSRegs) { static bool isCSRestore(MachineInstr *MI, const MCPhysReg *CSRegs) {
unsigned RtIdx = 0;
if (MI->getOpcode() == ARM64::LDPXpost || MI->getOpcode() == ARM64::LDPDpost)
RtIdx = 1;
if (MI->getOpcode() == ARM64::LDPXpost || if (MI->getOpcode() == ARM64::LDPXpost ||
MI->getOpcode() == ARM64::LDPDpost || MI->getOpcode() == ARM64::LDPXi || MI->getOpcode() == ARM64::LDPDpost || MI->getOpcode() == ARM64::LDPXi ||
MI->getOpcode() == ARM64::LDPDi) { MI->getOpcode() == ARM64::LDPDi) {
if (!isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs) || if (!isCalleeSavedRegister(MI->getOperand(RtIdx).getReg(), CSRegs) ||
!isCalleeSavedRegister(MI->getOperand(1).getReg(), CSRegs) || !isCalleeSavedRegister(MI->getOperand(RtIdx + 1).getReg(), CSRegs) ||
MI->getOperand(2).getReg() != ARM64::SP) MI->getOperand(RtIdx + 2).getReg() != ARM64::SP)
return false; return false;
return true; return true;
} }
@ -667,8 +671,11 @@ bool ARM64FrameLowering::spillCalleeSavedRegisters(
const int Offset = (i == 0) ? -Count : i; const int Offset = (i == 0) ? -Count : i;
assert((Offset >= -64 && Offset <= 63) && assert((Offset >= -64 && Offset <= 63) &&
"Offset out of bounds for STP immediate"); "Offset out of bounds for STP immediate");
BuildMI(MBB, MI, DL, TII.get(StrOpc)) MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StrOpc));
.addReg(Reg2, getPrologueDeath(MF, Reg2)) if (StrOpc == ARM64::STPDpre || StrOpc == ARM64::STPXpre)
MIB.addReg(ARM64::SP, RegState::Define);
MIB.addReg(Reg2, getPrologueDeath(MF, Reg2))
.addReg(Reg1, getPrologueDeath(MF, Reg1)) .addReg(Reg1, getPrologueDeath(MF, Reg1))
.addReg(ARM64::SP) .addReg(ARM64::SP)
.addImm(Offset) // [sp, #offset * 8], where factor * 8 is implicit .addImm(Offset) // [sp, #offset * 8], where factor * 8 is implicit
@ -734,8 +741,11 @@ bool ARM64FrameLowering::restoreCalleeSavedRegisters(
const int Offset = (i == Count - 2) ? Count : Count - i - 2; const int Offset = (i == Count - 2) ? Count : Count - i - 2;
assert((Offset >= -64 && Offset <= 63) && assert((Offset >= -64 && Offset <= 63) &&
"Offset out of bounds for LDP immediate"); "Offset out of bounds for LDP immediate");
BuildMI(MBB, MI, DL, TII.get(LdrOpc)) MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(LdrOpc));
.addReg(Reg2, getDefRegState(true)) if (LdrOpc == ARM64::LDPXpost || LdrOpc == ARM64::LDPDpost)
MIB.addReg(ARM64::SP, RegState::Define);
MIB.addReg(Reg2, getDefRegState(true))
.addReg(Reg1, getDefRegState(true)) .addReg(Reg1, getDefRegState(true))
.addReg(ARM64::SP) .addReg(ARM64::SP)
.addImm(Offset); // [sp], #offset * 8 or [sp, #offset * 8] .addImm(Offset); // [sp], #offset * 8 or [sp, #offset * 8]

View File

@ -901,14 +901,14 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
ISD::LoadExtType ExtType = LD->getExtensionType(); ISD::LoadExtType ExtType = LD->getExtensionType();
bool InsertTo64 = false; bool InsertTo64 = false;
if (VT == MVT::i64) if (VT == MVT::i64)
Opcode = IsPre ? ARM64::LDRXpre_isel : ARM64::LDRXpost_isel; Opcode = IsPre ? ARM64::LDRXpre : ARM64::LDRXpost;
else if (VT == MVT::i32) { else if (VT == MVT::i32) {
if (ExtType == ISD::NON_EXTLOAD) if (ExtType == ISD::NON_EXTLOAD)
Opcode = IsPre ? ARM64::LDRWpre_isel : ARM64::LDRWpost_isel; Opcode = IsPre ? ARM64::LDRWpre : ARM64::LDRWpost;
else if (ExtType == ISD::SEXTLOAD) else if (ExtType == ISD::SEXTLOAD)
Opcode = IsPre ? ARM64::LDRSWpre_isel : ARM64::LDRSWpost_isel; Opcode = IsPre ? ARM64::LDRSWpre : ARM64::LDRSWpost;
else { else {
Opcode = IsPre ? ARM64::LDRWpre_isel : ARM64::LDRWpost_isel; Opcode = IsPre ? ARM64::LDRWpre : ARM64::LDRWpost;
InsertTo64 = true; InsertTo64 = true;
// The result of the load is only i32. It's the subreg_to_reg that makes // The result of the load is only i32. It's the subreg_to_reg that makes
// it into an i64. // it into an i64.
@ -917,11 +917,11 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
} else if (VT == MVT::i16) { } else if (VT == MVT::i16) {
if (ExtType == ISD::SEXTLOAD) { if (ExtType == ISD::SEXTLOAD) {
if (DstVT == MVT::i64) if (DstVT == MVT::i64)
Opcode = IsPre ? ARM64::LDRSHXpre_isel : ARM64::LDRSHXpost_isel; Opcode = IsPre ? ARM64::LDRSHXpre : ARM64::LDRSHXpost;
else else
Opcode = IsPre ? ARM64::LDRSHWpre_isel : ARM64::LDRSHWpost_isel; Opcode = IsPre ? ARM64::LDRSHWpre : ARM64::LDRSHWpost;
} else { } else {
Opcode = IsPre ? ARM64::LDRHHpre_isel : ARM64::LDRHHpost_isel; Opcode = IsPre ? ARM64::LDRHHpre : ARM64::LDRHHpost;
InsertTo64 = DstVT == MVT::i64; InsertTo64 = DstVT == MVT::i64;
// The result of the load is only i32. It's the subreg_to_reg that makes // The result of the load is only i32. It's the subreg_to_reg that makes
// it into an i64. // it into an i64.
@ -930,22 +930,22 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
} else if (VT == MVT::i8) { } else if (VT == MVT::i8) {
if (ExtType == ISD::SEXTLOAD) { if (ExtType == ISD::SEXTLOAD) {
if (DstVT == MVT::i64) if (DstVT == MVT::i64)
Opcode = IsPre ? ARM64::LDRSBXpre_isel : ARM64::LDRSBXpost_isel; Opcode = IsPre ? ARM64::LDRSBXpre : ARM64::LDRSBXpost;
else else
Opcode = IsPre ? ARM64::LDRSBWpre_isel : ARM64::LDRSBWpost_isel; Opcode = IsPre ? ARM64::LDRSBWpre : ARM64::LDRSBWpost;
} else { } else {
Opcode = IsPre ? ARM64::LDRBBpre_isel : ARM64::LDRBBpost_isel; Opcode = IsPre ? ARM64::LDRBBpre : ARM64::LDRBBpost;
InsertTo64 = DstVT == MVT::i64; InsertTo64 = DstVT == MVT::i64;
// The result of the load is only i32. It's the subreg_to_reg that makes // The result of the load is only i32. It's the subreg_to_reg that makes
// it into an i64. // it into an i64.
DstVT = MVT::i32; DstVT = MVT::i32;
} }
} else if (VT == MVT::f32) { } else if (VT == MVT::f32) {
Opcode = IsPre ? ARM64::LDRSpre_isel : ARM64::LDRSpost_isel; Opcode = IsPre ? ARM64::LDRSpre : ARM64::LDRSpost;
} else if (VT == MVT::f64 || VT.is64BitVector()) { } else if (VT == MVT::f64 || VT.is64BitVector()) {
Opcode = IsPre ? ARM64::LDRDpre_isel : ARM64::LDRDpost_isel; Opcode = IsPre ? ARM64::LDRDpre : ARM64::LDRDpost;
} else if (VT.is128BitVector()) { } else if (VT.is128BitVector()) {
Opcode = IsPre ? ARM64::LDRQpre_isel : ARM64::LDRQpost_isel; Opcode = IsPre ? ARM64::LDRQpre : ARM64::LDRQpost;
} else } else
return nullptr; return nullptr;
SDValue Chain = LD->getChain(); SDValue Chain = LD->getChain();
@ -954,21 +954,25 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
int OffsetVal = (int)OffsetOp->getZExtValue(); int OffsetVal = (int)OffsetOp->getZExtValue();
SDValue Offset = CurDAG->getTargetConstant(OffsetVal, MVT::i64); SDValue Offset = CurDAG->getTargetConstant(OffsetVal, MVT::i64);
SDValue Ops[] = { Base, Offset, Chain }; SDValue Ops[] = { Base, Offset, Chain };
SDNode *Res = CurDAG->getMachineNode(Opcode, SDLoc(N), DstVT, MVT::i64, SDNode *Res = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i64, DstVT,
MVT::Other, Ops); MVT::Other, Ops);
// Either way, we're replacing the node, so tell the caller that. // Either way, we're replacing the node, so tell the caller that.
Done = true; Done = true;
SDValue LoadedVal = SDValue(Res, 1);
if (InsertTo64) { if (InsertTo64) {
SDValue SubReg = CurDAG->getTargetConstant(ARM64::sub_32, MVT::i32); SDValue SubReg = CurDAG->getTargetConstant(ARM64::sub_32, MVT::i32);
SDNode *Sub = CurDAG->getMachineNode( LoadedVal =
ARM64::SUBREG_TO_REG, SDLoc(N), MVT::i64, SDValue(CurDAG->getMachineNode(ARM64::SUBREG_TO_REG, SDLoc(N), MVT::i64,
CurDAG->getTargetConstant(0, MVT::i64), SDValue(Res, 0), SubReg); CurDAG->getTargetConstant(0, MVT::i64),
ReplaceUses(SDValue(N, 0), SDValue(Sub, 0)); LoadedVal, SubReg),
ReplaceUses(SDValue(N, 1), SDValue(Res, 1)); 0);
ReplaceUses(SDValue(N, 2), SDValue(Res, 2));
return nullptr;
} }
return Res;
ReplaceUses(SDValue(N, 0), LoadedVal);
ReplaceUses(SDValue(N, 1), SDValue(Res, 0));
ReplaceUses(SDValue(N, 2), SDValue(Res, 2));
return nullptr;
} }
SDNode *ARM64DAGToDAGISel::SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc, SDNode *ARM64DAGToDAGISel::SelectLoad(SDNode *N, unsigned NumVecs, unsigned Opc,

View File

@ -2918,8 +2918,8 @@ multiclass StoreUnprivileged<bits<2> sz, bit V, bits<2> opc,
//--- //---
class BaseLoadStorePreIdx<bits<2> sz, bit V, bits<2> opc, dag oops, dag iops, class BaseLoadStorePreIdx<bits<2> sz, bit V, bits<2> opc, dag oops, dag iops,
string asm, string cstr> string asm, string cstr, list<dag> pat>
: I<oops, iops, asm, "\t$Rt, [$Rn, $offset]!", cstr, []> { : I<oops, iops, asm, "\t$Rt, [$Rn, $offset]!", cstr, pat> {
bits<5> Rt; bits<5> Rt;
bits<5> Rn; bits<5> Rn;
bits<9> offset; bits<9> offset;
@ -2939,74 +2939,34 @@ class BaseLoadStorePreIdx<bits<2> sz, bit V, bits<2> opc, dag oops, dag iops,
let hasSideEffects = 0 in { let hasSideEffects = 0 in {
let mayStore = 0, mayLoad = 1 in let mayStore = 0, mayLoad = 1 in
// FIXME: Modeling the write-back of these instructions for isel used
// to be tricky. we need the complex addressing mode for the memory
// reference, but we also need the write-back specified as a tied
// operand to the base register. It should work now, but needs to be
// done as a separate patch. This would allow us to be rid of the
// codegenonly pseudoinstructions below too.
class LoadPreIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype, class LoadPreIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype,
string asm> string asm>
: BaseLoadStorePreIdx<sz, V, opc, : BaseLoadStorePreIdx<sz, V, opc,
(outs regtype:$Rt/*, GPR64sp:$wback*/), (outs GPR64sp:$wback, regtype:$Rt),
(ins GPR64sp:$Rn, simm9:$offset), asm, (ins GPR64sp:$Rn, simm9:$offset), asm,
""/*"$Rn = $wback"*/>, "$Rn = $wback", []>,
Sched<[WriteLD, WriteAdr]>; Sched<[WriteLD, WriteAdr]>;
let mayStore = 1, mayLoad = 0 in let mayStore = 1, mayLoad = 0 in
class StorePreIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype, class StorePreIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype,
string asm> string asm, SDPatternOperator storeop, ValueType Ty>
: BaseLoadStorePreIdx<sz, V, opc, : BaseLoadStorePreIdx<sz, V, opc,
(outs/* GPR64sp:$wback*/), (outs GPR64sp:$wback),
(ins regtype:$Rt, GPR64sp:$Rn, simm9:$offset), (ins regtype:$Rt, GPR64sp:$Rn, simm9:$offset),
asm, ""/*"$Rn = $wback"*/>, asm, "$Rn = $wback",
[(set GPR64sp:$wback,
(storeop (Ty regtype:$Rt), GPR64sp:$Rn, simm9:$offset))]>,
Sched<[WriteAdr, WriteST]>; Sched<[WriteAdr, WriteST]>;
} // hasSideEffects = 0 } // hasSideEffects = 0
// ISel pseudo-instructions which have the tied operands. When the MC lowering
// logic finally gets smart enough to strip off tied operands that are just
// for isel convenience, we can get rid of these pseudos and just reference
// the real instructions directly.
//
// Ironically, also because of the writeback operands, we can't put the
// matcher pattern directly on the instruction, but need to define it
// separately.
//
// Loads aren't matched with patterns here at all, but rather in C++
// custom lowering.
let mayStore = 0, mayLoad = 1, hasSideEffects = 0 in {
class LoadPreIdxPseudo<RegisterClass regtype>
: Pseudo<(outs regtype:$Rt, GPR64sp:$wback),
(ins GPR64sp:$addr, simm9:$offset), [],
"$addr = $wback,@earlyclobber $wback">,
Sched<[WriteLD, WriteAdr]>;
class LoadPostIdxPseudo<RegisterClass regtype>
: Pseudo<(outs regtype:$Rt, GPR64sp:$wback),
(ins GPR64sp:$addr, simm9:$offset), [],
"$addr = $wback,@earlyclobber $wback">,
Sched<[WriteLD, WriteI]>;
}
multiclass StorePreIdxPseudo<RegisterClass regtype, ValueType Ty,
SDPatternOperator OpNode> {
let mayStore = 1, mayLoad = 0, hasSideEffects = 0 in
def _isel: Pseudo<(outs GPR64sp:$wback),
(ins regtype:$Rt, GPR64sp:$addr, simm9:$offset), [],
"$addr = $wback,@earlyclobber $wback">,
Sched<[WriteAdr, WriteST]>;
def : Pat<(OpNode (Ty regtype:$Rt), GPR64sp:$addr, simm9:$offset),
(!cast<Instruction>(NAME#_isel) regtype:$Rt, GPR64sp:$addr,
simm9:$offset)>;
}
//--- //---
// Load/store post-indexed // Load/store post-indexed
//--- //---
// (pre-index) load/stores. // (pre-index) load/stores.
class BaseLoadStorePostIdx<bits<2> sz, bit V, bits<2> opc, dag oops, dag iops, class BaseLoadStorePostIdx<bits<2> sz, bit V, bits<2> opc, dag oops, dag iops,
string asm, string cstr> string asm, string cstr, list<dag> pat>
: I<oops, iops, asm, "\t$Rt, [$Rn], $offset", cstr, []> { : I<oops, iops, asm, "\t$Rt, [$Rn], $offset", cstr, pat> {
bits<5> Rt; bits<5> Rt;
bits<5> Rn; bits<5> Rn;
bits<9> offset; bits<9> offset;
@ -3026,51 +2986,26 @@ class BaseLoadStorePostIdx<bits<2> sz, bit V, bits<2> opc, dag oops, dag iops,
let hasSideEffects = 0 in { let hasSideEffects = 0 in {
let mayStore = 0, mayLoad = 1 in let mayStore = 0, mayLoad = 1 in
// FIXME: Modeling the write-back of these instructions for isel used
// to be tricky. we need the complex addressing mode for the memory
// reference, but we also need the write-back specified as a tied
// operand to the base register. It should work now, but needs to be
// done as a separate patch. This would allow us to be rid of the
// codegenonly pseudoinstructions below too.
class LoadPostIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype, class LoadPostIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype,
string asm> string asm>
: BaseLoadStorePostIdx<sz, V, opc, : BaseLoadStorePostIdx<sz, V, opc,
(outs regtype:$Rt/*, GPR64sp:$wback*/), (outs GPR64sp:$wback, regtype:$Rt),
(ins GPR64sp:$Rn, simm9:$offset), (ins GPR64sp:$Rn, simm9:$offset),
asm, ""/*"$addr.base = $wback"*/>, asm, "$Rn = $wback", []>,
Sched<[WriteLD, WriteI]>; Sched<[WriteLD, WriteI]>;
let mayStore = 1, mayLoad = 0 in let mayStore = 1, mayLoad = 0 in
class StorePostIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype, class StorePostIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype,
string asm> string asm, SDPatternOperator storeop, ValueType Ty>
: BaseLoadStorePostIdx<sz, V, opc, : BaseLoadStorePostIdx<sz, V, opc,
(outs/* GPR64sp:$wback*/), (outs GPR64sp:$wback),
(ins regtype:$Rt, GPR64sp:$Rn, simm9:$offset), (ins regtype:$Rt, GPR64sp:$Rn, simm9:$offset),
asm, ""/*"$addr.base = $wback"*/>, asm, "$Rn = $wback",
[(set GPR64sp:$wback,
(storeop (Ty regtype:$Rt), GPR64sp:$Rn, simm9:$offset))]>,
Sched<[WriteAdr, WriteST, ReadAdrBase]>; Sched<[WriteAdr, WriteST, ReadAdrBase]>;
} // hasSideEffects = 0 } // hasSideEffects = 0
// ISel pseudo-instructions which have the tied operands. When the MC lowering
// logic finally gets smart enough to strip off tied operands that are just
// for isel convenience, we can get rid of these pseudos and just reference
// the real instructions directly.
//
// Ironically, also because of the writeback operands, we can't put the
// matcher pattern directly on the instruction, but need to define it
// separately.
multiclass StorePostIdxPseudo<RegisterClass regtype, ValueType Ty,
SDPatternOperator OpNode, Instruction Insn> {
let mayStore = 1, mayLoad = 0, hasSideEffects = 0 in
def _isel: Pseudo<(outs GPR64sp:$wback),
(ins regtype:$Rt, GPR64sp:$Rn, simm9:$idx), [],
"$Rn = $wback,@earlyclobber $wback">,
PseudoInstExpansion<(Insn regtype:$Rt, GPR64sp:$Rn, simm9:$idx)>,
Sched<[WriteAdr, WriteST, ReadAdrBase]>;
def : Pat<(OpNode (Ty regtype:$Rt), GPR64sp:$Rn, simm9:$idx),
(!cast<Instruction>(NAME#_isel) regtype:$Rt, GPR64sp:$Rn,
simm9:$idx)>;
}
//--- //---
// Load/store pair // Load/store pair
@ -3129,7 +3064,7 @@ multiclass StorePairOffset<bits<2> opc, bit V, RegisterClass regtype,
// (pre-indexed) // (pre-indexed)
class BaseLoadStorePairPreIdx<bits<2> opc, bit V, bit L, dag oops, dag iops, class BaseLoadStorePairPreIdx<bits<2> opc, bit V, bit L, dag oops, dag iops,
string asm> string asm>
: I<oops, iops, asm, "\t$Rt, $Rt2, [$Rn, $offset]!", "", []> { : I<oops, iops, asm, "\t$Rt, $Rt2, [$Rn, $offset]!", "$Rn = $wback", []> {
bits<5> Rt; bits<5> Rt;
bits<5> Rt2; bits<5> Rt2;
bits<5> Rn; bits<5> Rn;
@ -3152,14 +3087,14 @@ let mayStore = 0, mayLoad = 1 in
class LoadPairPreIdx<bits<2> opc, bit V, RegisterClass regtype, class LoadPairPreIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand indextype, string asm> Operand indextype, string asm>
: BaseLoadStorePairPreIdx<opc, V, 1, : BaseLoadStorePairPreIdx<opc, V, 1,
(outs regtype:$Rt, regtype:$Rt2), (outs GPR64sp:$wback, regtype:$Rt, regtype:$Rt2),
(ins GPR64sp:$Rn, indextype:$offset), asm>, (ins GPR64sp:$Rn, indextype:$offset), asm>,
Sched<[WriteLD, WriteLDHi, WriteAdr]>; Sched<[WriteLD, WriteLDHi, WriteAdr]>;
let mayStore = 1, mayLoad = 0 in let mayStore = 1, mayLoad = 0 in
class StorePairPreIdx<bits<2> opc, bit V, RegisterClass regtype, class StorePairPreIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand indextype, string asm> Operand indextype, string asm>
: BaseLoadStorePairPreIdx<opc, V, 0, (outs), : BaseLoadStorePairPreIdx<opc, V, 0, (outs GPR64sp:$wback),
(ins regtype:$Rt, regtype:$Rt2, (ins regtype:$Rt, regtype:$Rt2,
GPR64sp:$Rn, indextype:$offset), GPR64sp:$Rn, indextype:$offset),
asm>, asm>,
@ -3170,7 +3105,7 @@ class StorePairPreIdx<bits<2> opc, bit V, RegisterClass regtype,
class BaseLoadStorePairPostIdx<bits<2> opc, bit V, bit L, dag oops, dag iops, class BaseLoadStorePairPostIdx<bits<2> opc, bit V, bit L, dag oops, dag iops,
string asm> string asm>
: I<oops, iops, asm, "\t$Rt, $Rt2, [$Rn], $offset", "", []> { : I<oops, iops, asm, "\t$Rt, $Rt2, [$Rn], $offset", "$Rn = $wback", []> {
bits<5> Rt; bits<5> Rt;
bits<5> Rt2; bits<5> Rt2;
bits<5> Rn; bits<5> Rn;
@ -3193,7 +3128,7 @@ let mayStore = 0, mayLoad = 1 in
class LoadPairPostIdx<bits<2> opc, bit V, RegisterClass regtype, class LoadPairPostIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand idxtype, string asm> Operand idxtype, string asm>
: BaseLoadStorePairPostIdx<opc, V, 1, : BaseLoadStorePairPostIdx<opc, V, 1,
(outs regtype:$Rt, regtype:$Rt2), (outs GPR64sp:$wback, regtype:$Rt, regtype:$Rt2),
(ins GPR64sp:$Rn, idxtype:$offset), asm>, (ins GPR64sp:$Rn, idxtype:$offset), asm>,
Sched<[WriteLD, WriteLDHi, WriteAdr]>; Sched<[WriteLD, WriteLDHi, WriteAdr]>;
@ -3201,7 +3136,7 @@ let mayStore = 1, mayLoad = 0 in
class StorePairPostIdx<bits<2> opc, bit V, RegisterClass regtype, class StorePairPostIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand idxtype, string asm> Operand idxtype, string asm>
: BaseLoadStorePairPostIdx<opc, V, 0, (outs), : BaseLoadStorePairPostIdx<opc, V, 0, (outs),
(ins regtype:$Rt, regtype:$Rt2, (ins GPR64sp:$wback, regtype:$Rt, regtype:$Rt2,
GPR64sp:$Rn, idxtype:$offset), GPR64sp:$Rn, idxtype:$offset),
asm>, asm>,
Sched<[WriteAdr, WriteSTP]>; Sched<[WriteAdr, WriteSTP]>;

View File

@ -1389,10 +1389,12 @@ void ARM64InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
SrcReg, getKillRegState(KillSrc)); SrcReg, getKillRegState(KillSrc));
} else { } else {
BuildMI(MBB, I, DL, get(ARM64::STRQpre)) BuildMI(MBB, I, DL, get(ARM64::STRQpre))
.addReg(ARM64::SP, RegState::Define)
.addReg(SrcReg, getKillRegState(KillSrc)) .addReg(SrcReg, getKillRegState(KillSrc))
.addReg(ARM64::SP) .addReg(ARM64::SP)
.addImm(-16); .addImm(-16);
BuildMI(MBB, I, DL, get(ARM64::LDRQpre)) BuildMI(MBB, I, DL, get(ARM64::LDRQpre))
.addReg(ARM64::SP, RegState::Define)
.addReg(DestReg, RegState::Define) .addReg(DestReg, RegState::Define)
.addReg(ARM64::SP) .addReg(ARM64::SP)
.addImm(16); .addImm(16);

View File

@ -1699,21 +1699,6 @@ def LDRHHpre : LoadPreIdx<0b01, 0, 0b01, GPR32, "ldrh">;
// load sign-extended word // load sign-extended word
def LDRSWpre : LoadPreIdx<0b10, 0, 0b10, GPR64, "ldrsw">; def LDRSWpre : LoadPreIdx<0b10, 0, 0b10, GPR64, "ldrsw">;
// ISel pseudos and patterns. See expanded comment on LoadPreIdxPseudo.
def LDRQpre_isel : LoadPreIdxPseudo<FPR128>;
def LDRDpre_isel : LoadPreIdxPseudo<FPR64>;
def LDRSpre_isel : LoadPreIdxPseudo<FPR32>;
def LDRXpre_isel : LoadPreIdxPseudo<GPR64>;
def LDRWpre_isel : LoadPreIdxPseudo<GPR32>;
def LDRHHpre_isel : LoadPreIdxPseudo<GPR32>;
def LDRBBpre_isel : LoadPreIdxPseudo<GPR32>;
def LDRSWpre_isel : LoadPreIdxPseudo<GPR64>;
def LDRSHWpre_isel : LoadPreIdxPseudo<GPR32>;
def LDRSHXpre_isel : LoadPreIdxPseudo<GPR64>;
def LDRSBWpre_isel : LoadPreIdxPseudo<GPR32>;
def LDRSBXpre_isel : LoadPreIdxPseudo<GPR64>;
//--- //---
// (immediate post-indexed) // (immediate post-indexed)
def LDRWpost : LoadPostIdx<0b10, 0, 0b01, GPR32, "ldr">; def LDRWpost : LoadPostIdx<0b10, 0, 0b01, GPR32, "ldr">;
@ -1739,21 +1724,6 @@ def LDRHHpost : LoadPostIdx<0b01, 0, 0b01, GPR32, "ldrh">;
// load sign-extended word // load sign-extended word
def LDRSWpost : LoadPostIdx<0b10, 0, 0b10, GPR64, "ldrsw">; def LDRSWpost : LoadPostIdx<0b10, 0, 0b10, GPR64, "ldrsw">;
// ISel pseudos and patterns. See expanded comment on LoadPostIdxPseudo.
def LDRQpost_isel : LoadPostIdxPseudo<FPR128>;
def LDRDpost_isel : LoadPostIdxPseudo<FPR64>;
def LDRSpost_isel : LoadPostIdxPseudo<FPR32>;
def LDRXpost_isel : LoadPostIdxPseudo<GPR64>;
def LDRWpost_isel : LoadPostIdxPseudo<GPR32>;
def LDRHHpost_isel : LoadPostIdxPseudo<GPR32>;
def LDRBBpost_isel : LoadPostIdxPseudo<GPR32>;
def LDRSWpost_isel : LoadPostIdxPseudo<GPR64>;
def LDRSHWpost_isel : LoadPostIdxPseudo<GPR32>;
def LDRSHXpost_isel : LoadPostIdxPseudo<GPR64>;
def LDRSBWpost_isel : LoadPostIdxPseudo<GPR32>;
def LDRSBXpost_isel : LoadPostIdxPseudo<GPR64>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Store instructions. // Store instructions.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -2072,119 +2042,103 @@ defm STTRB : StoreUnprivileged<0b00, 0, 0b00, GPR32, "sttrb">;
//--- //---
// (immediate pre-indexed) // (immediate pre-indexed)
def STRWpre : StorePreIdx<0b10, 0, 0b00, GPR32, "str">; def STRWpre : StorePreIdx<0b10, 0, 0b00, GPR32, "str", pre_store, i32>;
def STRXpre : StorePreIdx<0b11, 0, 0b00, GPR64, "str">; def STRXpre : StorePreIdx<0b11, 0, 0b00, GPR64, "str", pre_store, i64>;
def STRBpre : StorePreIdx<0b00, 1, 0b00, FPR8, "str">; def STRBpre : StorePreIdx<0b00, 1, 0b00, FPR8, "str", pre_store, untyped>;
def STRHpre : StorePreIdx<0b01, 1, 0b00, FPR16, "str">; def STRHpre : StorePreIdx<0b01, 1, 0b00, FPR16, "str", pre_store, f16>;
def STRSpre : StorePreIdx<0b10, 1, 0b00, FPR32, "str">; def STRSpre : StorePreIdx<0b10, 1, 0b00, FPR32, "str", pre_store, f32>;
def STRDpre : StorePreIdx<0b11, 1, 0b00, FPR64, "str">; def STRDpre : StorePreIdx<0b11, 1, 0b00, FPR64, "str", pre_store, f64>;
def STRQpre : StorePreIdx<0b00, 1, 0b10, FPR128, "str">; def STRQpre : StorePreIdx<0b00, 1, 0b10, FPR128, "str", pre_store, f128>;
def STRBBpre : StorePreIdx<0b00, 0, 0b00, GPR32, "strb">; def STRBBpre : StorePreIdx<0b00, 0, 0b00, GPR32, "strb", pre_truncsti8, i32>;
def STRHHpre : StorePreIdx<0b01, 0, 0b00, GPR32, "strh">; def STRHHpre : StorePreIdx<0b01, 0, 0b00, GPR32, "strh", pre_truncsti16, i32>;
// ISel pseudos and patterns. See expanded comment on StorePreIdxPseudo.
defm STRQpre : StorePreIdxPseudo<FPR128, f128, pre_store>;
defm STRDpre : StorePreIdxPseudo<FPR64, f64, pre_store>;
defm STRSpre : StorePreIdxPseudo<FPR32, f32, pre_store>;
defm STRXpre : StorePreIdxPseudo<GPR64, i64, pre_store>;
defm STRWpre : StorePreIdxPseudo<GPR32, i32, pre_store>;
defm STRHHpre : StorePreIdxPseudo<GPR32, i32, pre_truncsti16>;
defm STRBBpre : StorePreIdxPseudo<GPR32, i32, pre_truncsti8>;
// truncstore i64 // truncstore i64
def : Pat<(pre_truncsti32 GPR64:$Rt, GPR64sp:$addr, simm9:$off), def : Pat<(pre_truncsti32 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
(STRWpre_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr, (STRWpre (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
simm9:$off)>; simm9:$off)>;
def : Pat<(pre_truncsti16 GPR64:$Rt, GPR64sp:$addr, simm9:$off), def : Pat<(pre_truncsti16 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
(STRHHpre_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr, (STRHHpre (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
simm9:$off)>; simm9:$off)>;
def : Pat<(pre_truncsti8 GPR64:$Rt, GPR64sp:$addr, simm9:$off), def : Pat<(pre_truncsti8 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
(STRBBpre_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr, (STRBBpre (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
simm9:$off)>; simm9:$off)>;
def : Pat<(pre_store (v8i8 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v8i8 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpre_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpre FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v4i16 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v4i16 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpre_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpre FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v2i32 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v2i32 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpre_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpre FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v2f32 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v2f32 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpre_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpre FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v1i64 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v1i64 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpre_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpre FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v1f64 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v1f64 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpre_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpre FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v16i8 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v16i8 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpre_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpre FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v8i16 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v8i16 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpre_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpre FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v4i32 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v4i32 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpre_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpre FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v4f32 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v4f32 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpre_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpre FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v2i64 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v2i64 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpre_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpre FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(pre_store (v2f64 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(pre_store (v2f64 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpre_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpre FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
//--- //---
// (immediate post-indexed) // (immediate post-indexed)
def STRWpost : StorePostIdx<0b10, 0, 0b00, GPR32, "str">; def STRWpost : StorePostIdx<0b10, 0, 0b00, GPR32, "str", post_store, i32>;
def STRXpost : StorePostIdx<0b11, 0, 0b00, GPR64, "str">; def STRXpost : StorePostIdx<0b11, 0, 0b00, GPR64, "str", post_store, i64>;
def STRBpost : StorePostIdx<0b00, 1, 0b00, FPR8, "str">; def STRBpost : StorePostIdx<0b00, 1, 0b00, FPR8, "str", post_store, untyped>;
def STRHpost : StorePostIdx<0b01, 1, 0b00, FPR16, "str">; def STRHpost : StorePostIdx<0b01, 1, 0b00, FPR16, "str", post_store, f16>;
def STRSpost : StorePostIdx<0b10, 1, 0b00, FPR32, "str">; def STRSpost : StorePostIdx<0b10, 1, 0b00, FPR32, "str", post_store, f32>;
def STRDpost : StorePostIdx<0b11, 1, 0b00, FPR64, "str">; def STRDpost : StorePostIdx<0b11, 1, 0b00, FPR64, "str", post_store, f64>;
def STRQpost : StorePostIdx<0b00, 1, 0b10, FPR128, "str">; def STRQpost : StorePostIdx<0b00, 1, 0b10, FPR128, "str", post_store, f128>;
def STRBBpost : StorePostIdx<0b00, 0, 0b00, GPR32, "strb">; def STRBBpost : StorePostIdx<0b00, 0, 0b00, GPR32, "strb", post_truncsti8, i32>;
def STRHHpost : StorePostIdx<0b01, 0, 0b00, GPR32, "strh">; def STRHHpost : StorePostIdx<0b01, 0, 0b00, GPR32, "strh", post_truncsti16, i32>;
// ISel pseudos and patterns. See expanded comment on StorePostIdxPseudo.
defm STRQpost : StorePostIdxPseudo<FPR128, f128, post_store, STRQpost>;
defm STRDpost : StorePostIdxPseudo<FPR64, f64, post_store, STRDpost>;
defm STRSpost : StorePostIdxPseudo<FPR32, f32, post_store, STRSpost>;
defm STRXpost : StorePostIdxPseudo<GPR64, i64, post_store, STRXpost>;
defm STRWpost : StorePostIdxPseudo<GPR32, i32, post_store, STRWpost>;
defm STRHHpost : StorePostIdxPseudo<GPR32, i32, post_truncsti16, STRHHpost>;
defm STRBBpost : StorePostIdxPseudo<GPR32, i32, post_truncsti8, STRBBpost>;
// truncstore i64 // truncstore i64
def : Pat<(post_truncsti32 GPR64:$Rt, GPR64sp:$addr, simm9:$off), def : Pat<(post_truncsti32 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
(STRWpost_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr, (STRWpost (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
simm9:$off)>; simm9:$off)>;
def : Pat<(post_truncsti16 GPR64:$Rt, GPR64sp:$addr, simm9:$off), def : Pat<(post_truncsti16 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
(STRHHpost_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr, (STRHHpost (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
simm9:$off)>; simm9:$off)>;
def : Pat<(post_truncsti8 GPR64:$Rt, GPR64sp:$addr, simm9:$off), def : Pat<(post_truncsti8 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
(STRBBpost_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr, (STRBBpost (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
simm9:$off)>; simm9:$off)>;
def : Pat<(post_store (v8i8 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v8i8 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpost_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpost FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v4i16 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v4i16 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpost_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpost FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v2i32 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v2i32 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpost_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpost FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v2f32 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v2f32 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpost_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpost FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v1i64 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v1i64 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpost_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpost FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v1f64 FPR64:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v1f64 FPR64:$Rt), GPR64sp:$addr, simm9:$off),
(STRDpost_isel FPR64:$Rt, GPR64sp:$addr, simm9:$off)>; (STRDpost FPR64:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v16i8 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v16i8 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpost_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpost FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v8i16 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v8i16 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpost_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpost FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v4i32 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v4i32 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpost_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpost FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v4f32 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v4f32 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpost_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpost FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v2i64 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v2i64 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpost_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpost FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
def : Pat<(post_store (v2f64 FPR128:$Rt), GPR64sp:$addr, simm9:$off), def : Pat<(post_store (v2f64 FPR128:$Rt), GPR64sp:$addr, simm9:$off),
(STRQpost_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>; (STRQpost FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Load/store exclusive instructions. // Load/store exclusive instructions.

View File

@ -528,6 +528,7 @@ ARM64LoadStoreOpt::mergePreIdxUpdateInsn(MachineBasicBlock::iterator I,
unsigned NewOpc = getPreIndexedOpcode(I->getOpcode()); unsigned NewOpc = getPreIndexedOpcode(I->getOpcode());
MachineInstrBuilder MIB = MachineInstrBuilder MIB =
BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc)) BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc))
.addOperand(Update->getOperand(0))
.addOperand(I->getOperand(0)) .addOperand(I->getOperand(0))
.addOperand(I->getOperand(1)) .addOperand(I->getOperand(1))
.addImm(Value); .addImm(Value);
@ -571,6 +572,7 @@ ARM64LoadStoreOpt::mergePostIdxUpdateInsn(MachineBasicBlock::iterator I,
unsigned NewOpc = getPostIndexedOpcode(I->getOpcode()); unsigned NewOpc = getPostIndexedOpcode(I->getOpcode());
MachineInstrBuilder MIB = MachineInstrBuilder MIB =
BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc)) BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc))
.addOperand(Update->getOperand(0))
.addOperand(I->getOperand(0)) .addOperand(I->getOperand(0))
.addOperand(I->getOperand(1)) .addOperand(I->getOperand(1))
.addImm(Value); .addImm(Value);

View File

@ -3146,9 +3146,9 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::LDPWpre: case ARM64::LDPWpre:
case ARM64::LDPXpost: case ARM64::LDPXpost:
case ARM64::LDPXpre: { case ARM64::LDPXpre: {
unsigned Rt = Inst.getOperand(0).getReg(); unsigned Rt = Inst.getOperand(1).getReg();
unsigned Rt2 = Inst.getOperand(1).getReg(); unsigned Rt2 = Inst.getOperand(2).getReg();
unsigned Rn = Inst.getOperand(2).getReg(); unsigned Rn = Inst.getOperand(3).getReg();
if (RI->isSubRegisterEq(Rn, Rt)) if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable LDP instruction, writeback base " return Error(Loc[0], "unpredictable LDP instruction, writeback base "
"is also a destination"); "is also a destination");
@ -3157,13 +3157,6 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
"is also a destination"); "is also a destination");
// FALLTHROUGH // FALLTHROUGH
} }
case ARM64::LDPDpost:
case ARM64::LDPDpre:
case ARM64::LDPQpost:
case ARM64::LDPQpre:
case ARM64::LDPSpost:
case ARM64::LDPSpre:
case ARM64::LDPSWpost:
case ARM64::LDPDi: case ARM64::LDPDi:
case ARM64::LDPQi: case ARM64::LDPQi:
case ARM64::LDPSi: case ARM64::LDPSi:
@ -3176,6 +3169,19 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt"); return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
break; break;
} }
case ARM64::LDPDpost:
case ARM64::LDPDpre:
case ARM64::LDPQpost:
case ARM64::LDPQpre:
case ARM64::LDPSpost:
case ARM64::LDPSpre:
case ARM64::LDPSWpost: {
unsigned Rt = Inst.getOperand(1).getReg();
unsigned Rt2 = Inst.getOperand(2).getReg();
if (Rt == Rt2)
return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
break;
}
case ARM64::STPDpost: case ARM64::STPDpost:
case ARM64::STPDpre: case ARM64::STPDpre:
case ARM64::STPQpost: case ARM64::STPQpost:
@ -3186,9 +3192,9 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::STPWpre: case ARM64::STPWpre:
case ARM64::STPXpost: case ARM64::STPXpost:
case ARM64::STPXpre: { case ARM64::STPXpre: {
unsigned Rt = Inst.getOperand(0).getReg(); unsigned Rt = Inst.getOperand(1).getReg();
unsigned Rt2 = Inst.getOperand(1).getReg(); unsigned Rt2 = Inst.getOperand(2).getReg();
unsigned Rn = Inst.getOperand(2).getReg(); unsigned Rn = Inst.getOperand(3).getReg();
if (RI->isSubRegisterEq(Rn, Rt)) if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable STP instruction, writeback base " return Error(Loc[0], "unpredictable STP instruction, writeback base "
"is also a source"); "is also a source");
@ -3219,8 +3225,8 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::LDRSWpost: case ARM64::LDRSWpost:
case ARM64::LDRWpost: case ARM64::LDRWpost:
case ARM64::LDRXpost: { case ARM64::LDRXpost: {
unsigned Rt = Inst.getOperand(0).getReg(); unsigned Rt = Inst.getOperand(1).getReg();
unsigned Rn = Inst.getOperand(1).getReg(); unsigned Rn = Inst.getOperand(2).getReg();
if (RI->isSubRegisterEq(Rn, Rt)) if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable LDR instruction, writeback base " return Error(Loc[0], "unpredictable LDR instruction, writeback base "
"is also a source"); "is also a source");
@ -3238,8 +3244,8 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::STRHpre: case ARM64::STRHpre:
case ARM64::STRWpre: case ARM64::STRWpre:
case ARM64::STRXpre: { case ARM64::STRXpre: {
unsigned Rt = Inst.getOperand(0).getReg(); unsigned Rt = Inst.getOperand(1).getReg();
unsigned Rn = Inst.getOperand(1).getReg(); unsigned Rn = Inst.getOperand(2).getReg();
if (RI->isSubRegisterEq(Rn, Rt)) if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable STR instruction, writeback base " return Error(Loc[0], "unpredictable STR instruction, writeback base "
"is also a source"); "is also a source");

View File

@ -902,6 +902,60 @@ static DecodeStatus DecodeSignedLdStInstruction(llvm::MCInst &Inst,
if (offset & (1 << (9 - 1))) if (offset & (1 << (9 - 1)))
offset |= ~((1LL << 9) - 1); offset |= ~((1LL << 9) - 1);
// First operand is always the writeback to the address register, if needed.
switch (Inst.getOpcode()) {
default:
break;
case ARM64::LDRSBWpre:
case ARM64::LDRSHWpre:
case ARM64::STRBBpre:
case ARM64::LDRBBpre:
case ARM64::STRHHpre:
case ARM64::LDRHHpre:
case ARM64::STRWpre:
case ARM64::LDRWpre:
case ARM64::LDRSBWpost:
case ARM64::LDRSHWpost:
case ARM64::STRBBpost:
case ARM64::LDRBBpost:
case ARM64::STRHHpost:
case ARM64::LDRHHpost:
case ARM64::STRWpost:
case ARM64::LDRWpost:
case ARM64::LDRSBXpre:
case ARM64::LDRSHXpre:
case ARM64::STRXpre:
case ARM64::LDRSWpre:
case ARM64::LDRXpre:
case ARM64::LDRSBXpost:
case ARM64::LDRSHXpost:
case ARM64::STRXpost:
case ARM64::LDRSWpost:
case ARM64::LDRXpost:
case ARM64::LDRQpre:
case ARM64::STRQpre:
case ARM64::LDRQpost:
case ARM64::STRQpost:
case ARM64::LDRDpre:
case ARM64::STRDpre:
case ARM64::LDRDpost:
case ARM64::STRDpost:
case ARM64::LDRSpre:
case ARM64::STRSpre:
case ARM64::LDRSpost:
case ARM64::STRSpost:
case ARM64::LDRHpre:
case ARM64::STRHpre:
case ARM64::LDRHpost:
case ARM64::STRHpost:
case ARM64::LDRBpre:
case ARM64::STRBpre:
case ARM64::LDRBpost:
case ARM64::STRBpost:
DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder);
break;
}
switch (Inst.getOpcode()) { switch (Inst.getOpcode()) {
default: default:
return Fail; return Fail;
@ -1112,6 +1166,37 @@ static DecodeStatus DecodePairLdStInstruction(llvm::MCInst &Inst, uint32_t insn,
unsigned Opcode = Inst.getOpcode(); unsigned Opcode = Inst.getOpcode();
bool NeedsDisjointWritebackTransfer = false; bool NeedsDisjointWritebackTransfer = false;
// First operand is always writeback of base register.
switch (Opcode) {
default:
break;
case ARM64::LDPXpost:
case ARM64::STPXpost:
case ARM64::LDPSWpost:
case ARM64::LDPXpre:
case ARM64::STPXpre:
case ARM64::LDPSWpre:
case ARM64::LDPWpost:
case ARM64::STPWpost:
case ARM64::LDPWpre:
case ARM64::STPWpre:
case ARM64::LDPQpost:
case ARM64::STPQpost:
case ARM64::LDPQpre:
case ARM64::STPQpre:
case ARM64::LDPDpost:
case ARM64::STPDpost:
case ARM64::LDPDpre:
case ARM64::STPDpre:
case ARM64::LDPSpost:
case ARM64::STPSpost:
case ARM64::LDPSpre:
case ARM64::STPSpre:
DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder);
break;
}
switch (Opcode) { switch (Opcode) {
default: default:
return Fail; return Fail;