summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2014-05-22 11:56:20 +0000
committerTim Northover <tnorthover@apple.com>2014-05-22 11:56:20 +0000
commit369e565f23d34876f1689971b98255dd84131546 (patch)
treed6a1000ad30999fbdadc47a05605290e7604fdd7
parente072ed71c87ba1be56f1bca1a1a8057760badea0 (diff)
downloadllvm-369e565f23d34876f1689971b98255dd84131546.tar.gz
llvm-369e565f23d34876f1689971b98255dd84131546.tar.bz2
llvm-369e565f23d34876f1689971b98255dd84131546.tar.xz
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209426 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/ARM64/ARM64AsmPrinter.cpp93
-rw-r--r--lib/Target/ARM64/ARM64FrameLowering.cpp32
-rw-r--r--lib/Target/ARM64/ARM64ISelDAGToDAG.cpp48
-rw-r--r--lib/Target/ARM64/ARM64InstrFormats.td113
-rw-r--r--lib/Target/ARM64/ARM64InstrInfo.cpp2
-rw-r--r--lib/Target/ARM64/ARM64InstrInfo.td162
-rw-r--r--lib/Target/ARM64/ARM64LoadStoreOptimizer.cpp2
-rw-r--r--lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp40
-rw-r--r--lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp85
9 files changed, 241 insertions, 336 deletions
diff --git a/lib/Target/ARM64/ARM64AsmPrinter.cpp b/lib/Target/ARM64/ARM64AsmPrinter.cpp
index 5531101fe2..78f9ed12f5 100644
--- a/lib/Target/ARM64/ARM64AsmPrinter.cpp
+++ b/lib/Target/ARM64/ARM64AsmPrinter.cpp
@@ -423,45 +423,6 @@ void ARM64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
// instructions) auto-generated.
#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) {
// Do any auto-generated pseudo lowerings.
if (emitPseudoExpansionLowering(OutStreamer, MI))
@@ -488,60 +449,6 @@ void ARM64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
}
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
// attributes (isCall, isReturn, etc.). We lower them to the real
diff --git a/lib/Target/ARM64/ARM64FrameLowering.cpp b/lib/Target/ARM64/ARM64FrameLowering.cpp
index 3b14649c48..9c17488ec5 100644
--- a/lib/Target/ARM64/ARM64FrameLowering.cpp
+++ b/lib/Target/ARM64/ARM64FrameLowering.cpp
@@ -246,14 +246,14 @@ void ARM64FrameLowering::emitPrologue(MachineFunction &MF) const {
// that is a multiple of -2.
assert((MBBI->getOpcode() == ARM64::STPXpre ||
MBBI->getOpcode() == ARM64::STPDpre) &&
- MBBI->getOperand(2).getReg() == ARM64::SP &&
- MBBI->getOperand(3).getImm() < 0 &&
- (MBBI->getOperand(3).getImm() & 1) == 0);
+ MBBI->getOperand(3).getReg() == ARM64::SP &&
+ MBBI->getOperand(4).getImm() < 0 &&
+ (MBBI->getOperand(4).getImm() & 1) == 0);
// Frame pointer is fp = sp - 16. Since the STPXpre subtracts the space
// required for the callee saved register area we get the frame pointer
// 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");
}
@@ -409,12 +409,16 @@ static bool isCalleeSavedRegister(unsigned Reg, 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 ||
MI->getOpcode() == ARM64::LDPDpost || MI->getOpcode() == ARM64::LDPXi ||
MI->getOpcode() == ARM64::LDPDi) {
- if (!isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs) ||
- !isCalleeSavedRegister(MI->getOperand(1).getReg(), CSRegs) ||
- MI->getOperand(2).getReg() != ARM64::SP)
+ if (!isCalleeSavedRegister(MI->getOperand(RtIdx).getReg(), CSRegs) ||
+ !isCalleeSavedRegister(MI->getOperand(RtIdx + 1).getReg(), CSRegs) ||
+ MI->getOperand(RtIdx + 2).getReg() != ARM64::SP)
return false;
return true;
}
@@ -667,8 +671,11 @@ bool ARM64FrameLowering::spillCalleeSavedRegisters(
const int Offset = (i == 0) ? -Count : i;
assert((Offset >= -64 && Offset <= 63) &&
"Offset out of bounds for STP immediate");
- BuildMI(MBB, MI, DL, TII.get(StrOpc))
- .addReg(Reg2, getPrologueDeath(MF, Reg2))
+ MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StrOpc));
+ 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(ARM64::SP)
.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;
assert((Offset >= -64 && Offset <= 63) &&
"Offset out of bounds for LDP immediate");
- BuildMI(MBB, MI, DL, TII.get(LdrOpc))
- .addReg(Reg2, getDefRegState(true))
+ MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(LdrOpc));
+ if (LdrOpc == ARM64::LDPXpost || LdrOpc == ARM64::LDPDpost)
+ MIB.addReg(ARM64::SP, RegState::Define);
+
+ MIB.addReg(Reg2, getDefRegState(true))
.addReg(Reg1, getDefRegState(true))
.addReg(ARM64::SP)
.addImm(Offset); // [sp], #offset * 8 or [sp, #offset * 8]
diff --git a/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp b/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp
index 8fec6f02b7..9b235db30a 100644
--- a/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp
+++ b/lib/Target/ARM64/ARM64ISelDAGToDAG.cpp
@@ -901,14 +901,14 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
ISD::LoadExtType ExtType = LD->getExtensionType();
bool InsertTo64 = false;
if (VT == MVT::i64)
- Opcode = IsPre ? ARM64::LDRXpre_isel : ARM64::LDRXpost_isel;
+ Opcode = IsPre ? ARM64::LDRXpre : ARM64::LDRXpost;
else if (VT == MVT::i32) {
if (ExtType == ISD::NON_EXTLOAD)
- Opcode = IsPre ? ARM64::LDRWpre_isel : ARM64::LDRWpost_isel;
+ Opcode = IsPre ? ARM64::LDRWpre : ARM64::LDRWpost;
else if (ExtType == ISD::SEXTLOAD)
- Opcode = IsPre ? ARM64::LDRSWpre_isel : ARM64::LDRSWpost_isel;
+ Opcode = IsPre ? ARM64::LDRSWpre : ARM64::LDRSWpost;
else {
- Opcode = IsPre ? ARM64::LDRWpre_isel : ARM64::LDRWpost_isel;
+ Opcode = IsPre ? ARM64::LDRWpre : ARM64::LDRWpost;
InsertTo64 = true;
// The result of the load is only i32. It's the subreg_to_reg that makes
// it into an i64.
@@ -917,11 +917,11 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
} else if (VT == MVT::i16) {
if (ExtType == ISD::SEXTLOAD) {
if (DstVT == MVT::i64)
- Opcode = IsPre ? ARM64::LDRSHXpre_isel : ARM64::LDRSHXpost_isel;
+ Opcode = IsPre ? ARM64::LDRSHXpre : ARM64::LDRSHXpost;
else
- Opcode = IsPre ? ARM64::LDRSHWpre_isel : ARM64::LDRSHWpost_isel;
+ Opcode = IsPre ? ARM64::LDRSHWpre : ARM64::LDRSHWpost;
} else {
- Opcode = IsPre ? ARM64::LDRHHpre_isel : ARM64::LDRHHpost_isel;
+ Opcode = IsPre ? ARM64::LDRHHpre : ARM64::LDRHHpost;
InsertTo64 = DstVT == MVT::i64;
// The result of the load is only i32. It's the subreg_to_reg that makes
// it into an i64.
@@ -930,22 +930,22 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
} else if (VT == MVT::i8) {
if (ExtType == ISD::SEXTLOAD) {
if (DstVT == MVT::i64)
- Opcode = IsPre ? ARM64::LDRSBXpre_isel : ARM64::LDRSBXpost_isel;
+ Opcode = IsPre ? ARM64::LDRSBXpre : ARM64::LDRSBXpost;
else
- Opcode = IsPre ? ARM64::LDRSBWpre_isel : ARM64::LDRSBWpost_isel;
+ Opcode = IsPre ? ARM64::LDRSBWpre : ARM64::LDRSBWpost;
} else {
- Opcode = IsPre ? ARM64::LDRBBpre_isel : ARM64::LDRBBpost_isel;
+ Opcode = IsPre ? ARM64::LDRBBpre : ARM64::LDRBBpost;
InsertTo64 = DstVT == MVT::i64;
// The result of the load is only i32. It's the subreg_to_reg that makes
// it into an i64.
DstVT = MVT::i32;
}
} 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()) {
- Opcode = IsPre ? ARM64::LDRDpre_isel : ARM64::LDRDpost_isel;
+ Opcode = IsPre ? ARM64::LDRDpre : ARM64::LDRDpost;
} else if (VT.is128BitVector()) {
- Opcode = IsPre ? ARM64::LDRQpre_isel : ARM64::LDRQpost_isel;
+ Opcode = IsPre ? ARM64::LDRQpre : ARM64::LDRQpost;
} else
return nullptr;
SDValue Chain = LD->getChain();
@@ -954,21 +954,25 @@ SDNode *ARM64DAGToDAGISel::SelectIndexedLoad(SDNode *N, bool &Done) {
int OffsetVal = (int)OffsetOp->getZExtValue();
SDValue Offset = CurDAG->getTargetConstant(OffsetVal, MVT::i64);
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);
// Either way, we're replacing the node, so tell the caller that.
Done = true;
+ SDValue LoadedVal = SDValue(Res, 1);
if (InsertTo64) {
SDValue SubReg = CurDAG->getTargetConstant(ARM64::sub_32, MVT::i32);
- SDNode *Sub = CurDAG->getMachineNode(
- ARM64::SUBREG_TO_REG, SDLoc(N), MVT::i64,
- CurDAG->getTargetConstant(0, MVT::i64), SDValue(Res, 0), SubReg);
- ReplaceUses(SDValue(N, 0), SDValue(Sub, 0));
- ReplaceUses(SDValue(N, 1), SDValue(Res, 1));
- ReplaceUses(SDValue(N, 2), SDValue(Res, 2));
- return nullptr;
+ LoadedVal =
+ SDValue(CurDAG->getMachineNode(ARM64::SUBREG_TO_REG, SDLoc(N), MVT::i64,
+ CurDAG->getTargetConstant(0, MVT::i64),
+ LoadedVal, SubReg),
+ 0);
}
- 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,
diff --git a/lib/Target/ARM64/ARM64InstrFormats.td b/lib/Target/ARM64/ARM64InstrFormats.td
index bf9fa2992b..ea45b3d4fb 100644
--- a/lib/Target/ARM64/ARM64InstrFormats.td
+++ b/lib/Target/ARM64/ARM64InstrFormats.td
@@ -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,
- string asm, string cstr>
- : I<oops, iops, asm, "\t$Rt, [$Rn, $offset]!", cstr, []> {
+ string asm, string cstr, list<dag> pat>
+ : I<oops, iops, asm, "\t$Rt, [$Rn, $offset]!", cstr, pat> {
bits<5> Rt;
bits<5> Rn;
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 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,
string asm>
: BaseLoadStorePreIdx<sz, V, opc,
- (outs regtype:$Rt/*, GPR64sp:$wback*/),
+ (outs GPR64sp:$wback, regtype:$Rt),
(ins GPR64sp:$Rn, simm9:$offset), asm,
- ""/*"$Rn = $wback"*/>,
+ "$Rn = $wback", []>,
Sched<[WriteLD, WriteAdr]>;
let mayStore = 1, mayLoad = 0 in
class StorePreIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype,
- string asm>
+ string asm, SDPatternOperator storeop, ValueType Ty>
: BaseLoadStorePreIdx<sz, V, opc,
- (outs/* GPR64sp:$wback*/),
+ (outs GPR64sp:$wback),
(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]>;
} // 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
//---
// (pre-index) load/stores.
class BaseLoadStorePostIdx<bits<2> sz, bit V, bits<2> opc, dag oops, dag iops,
- string asm, string cstr>
- : I<oops, iops, asm, "\t$Rt, [$Rn], $offset", cstr, []> {
+ string asm, string cstr, list<dag> pat>
+ : I<oops, iops, asm, "\t$Rt, [$Rn], $offset", cstr, pat> {
bits<5> Rt;
bits<5> Rn;
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 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,
string asm>
: BaseLoadStorePostIdx<sz, V, opc,
- (outs regtype:$Rt/*, GPR64sp:$wback*/),
+ (outs GPR64sp:$wback, regtype:$Rt),
(ins GPR64sp:$Rn, simm9:$offset),
- asm, ""/*"$addr.base = $wback"*/>,
+ asm, "$Rn = $wback", []>,
Sched<[WriteLD, WriteI]>;
let mayStore = 1, mayLoad = 0 in
class StorePostIdx<bits<2> sz, bit V, bits<2> opc, RegisterClass regtype,
- string asm>
+ string asm, SDPatternOperator storeop, ValueType Ty>
: BaseLoadStorePostIdx<sz, V, opc,
- (outs/* GPR64sp:$wback*/),
+ (outs GPR64sp:$wback),
(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]>;
} // 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
@@ -3129,7 +3064,7 @@ multiclass StorePairOffset<bits<2> opc, bit V, RegisterClass regtype,
// (pre-indexed)
class BaseLoadStorePairPreIdx<bits<2> opc, bit V, bit L, dag oops, dag iops,
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> Rt2;
bits<5> Rn;
@@ -3152,14 +3087,14 @@ let mayStore = 0, mayLoad = 1 in
class LoadPairPreIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand indextype, string asm>
: BaseLoadStorePairPreIdx<opc, V, 1,
- (outs regtype:$Rt, regtype:$Rt2),
+ (outs GPR64sp:$wback, regtype:$Rt, regtype:$Rt2),
(ins GPR64sp:$Rn, indextype:$offset), asm>,
Sched<[WriteLD, WriteLDHi, WriteAdr]>;
let mayStore = 1, mayLoad = 0 in
class StorePairPreIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand indextype, string asm>
- : BaseLoadStorePairPreIdx<opc, V, 0, (outs),
+ : BaseLoadStorePairPreIdx<opc, V, 0, (outs GPR64sp:$wback),
(ins regtype:$Rt, regtype:$Rt2,
GPR64sp:$Rn, indextype:$offset),
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,
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> Rt2;
bits<5> Rn;
@@ -3193,7 +3128,7 @@ let mayStore = 0, mayLoad = 1 in
class LoadPairPostIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand idxtype, string asm>
: BaseLoadStorePairPostIdx<opc, V, 1,
- (outs regtype:$Rt, regtype:$Rt2),
+ (outs GPR64sp:$wback, regtype:$Rt, regtype:$Rt2),
(ins GPR64sp:$Rn, idxtype:$offset), asm>,
Sched<[WriteLD, WriteLDHi, WriteAdr]>;
@@ -3201,7 +3136,7 @@ let mayStore = 1, mayLoad = 0 in
class StorePairPostIdx<bits<2> opc, bit V, RegisterClass regtype,
Operand idxtype, string asm>
: BaseLoadStorePairPostIdx<opc, V, 0, (outs),
- (ins regtype:$Rt, regtype:$Rt2,
+ (ins GPR64sp:$wback, regtype:$Rt, regtype:$Rt2,
GPR64sp:$Rn, idxtype:$offset),
asm>,
Sched<[WriteAdr, WriteSTP]>;
diff --git a/lib/Target/ARM64/ARM64InstrInfo.cpp b/lib/Target/ARM64/ARM64InstrInfo.cpp
index e1f9667841..fbbddd5666 100644
--- a/lib/Target/ARM64/ARM64InstrInfo.cpp
+++ b/lib/Target/ARM64/ARM64InstrInfo.cpp
@@ -1389,10 +1389,12 @@ void ARM64InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
SrcReg, getKillRegState(KillSrc));
} else {
BuildMI(MBB, I, DL, get(ARM64::STRQpre))
+ .addReg(ARM64::SP, RegState::Define)
.addReg(SrcReg, getKillRegState(KillSrc))
.addReg(ARM64::SP)
.addImm(-16);
BuildMI(MBB, I, DL, get(ARM64::LDRQpre))
+ .addReg(ARM64::SP, RegState::Define)
.addReg(DestReg, RegState::Define)
.addReg(ARM64::SP)
.addImm(16);
diff --git a/lib/Target/ARM64/ARM64InstrInfo.td b/lib/Target/ARM64/ARM64InstrInfo.td
index 94a39c1112..9c39d72a8e 100644
--- a/lib/Target/ARM64/ARM64InstrInfo.td
+++ b/lib/Target/ARM64/ARM64InstrInfo.td
@@ -1699,21 +1699,6 @@ def LDRHHpre : LoadPreIdx<0b01, 0, 0b01, GPR32, "ldrh">;
// load sign-extended word
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)
def LDRWpost : LoadPostIdx<0b10, 0, 0b01, GPR32, "ldr">;
@@ -1739,21 +1724,6 @@ def LDRHHpost : LoadPostIdx<0b01, 0, 0b01, GPR32, "ldrh">;
// load sign-extended word
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.
//===----------------------------------------------------------------------===//
@@ -2072,119 +2042,103 @@ defm STTRB : StoreUnprivileged<0b00, 0, 0b00, GPR32, "sttrb">;
//---
// (immediate pre-indexed)
-def STRWpre : StorePreIdx<0b10, 0, 0b00, GPR32, "str">;
-def STRXpre : StorePreIdx<0b11, 0, 0b00, GPR64, "str">;
-def STRBpre : StorePreIdx<0b00, 1, 0b00, FPR8, "str">;
-def STRHpre : StorePreIdx<0b01, 1, 0b00, FPR16, "str">;
-def STRSpre : StorePreIdx<0b10, 1, 0b00, FPR32, "str">;
-def STRDpre : StorePreIdx<0b11, 1, 0b00, FPR64, "str">;
-def STRQpre : StorePreIdx<0b00, 1, 0b10, FPR128, "str">;
-
-def STRBBpre : StorePreIdx<0b00, 0, 0b00, GPR32, "strb">;
-def STRHHpre : StorePreIdx<0b01, 0, 0b00, GPR32, "strh">;
-
-// 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>;
+def STRWpre : StorePreIdx<0b10, 0, 0b00, GPR32, "str", pre_store, i32>;
+def STRXpre : StorePreIdx<0b11, 0, 0b00, GPR64, "str", pre_store, i64>;
+def STRBpre : StorePreIdx<0b00, 1, 0b00, FPR8, "str", pre_store, untyped>;
+def STRHpre : StorePreIdx<0b01, 1, 0b00, FPR16, "str", pre_store, f16>;
+def STRSpre : StorePreIdx<0b10, 1, 0b00, FPR32, "str", pre_store, f32>;
+def STRDpre : StorePreIdx<0b11, 1, 0b00, FPR64, "str", pre_store, f64>;
+def STRQpre : StorePreIdx<0b00, 1, 0b10, FPR128, "str", pre_store, f128>;
+
+def STRBBpre : StorePreIdx<0b00, 0, 0b00, GPR32, "strb", pre_truncsti8, i32>;
+def STRHHpre : StorePreIdx<0b01, 0, 0b00, GPR32, "strh", pre_truncsti16, i32>;
+
// truncstore i64
def : Pat<(pre_truncsti32 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
- (STRWpre_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
- simm9:$off)>;
+ (STRWpre (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
+ simm9:$off)>;
def : Pat<(pre_truncsti16 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
- (STRHHpre_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
- simm9:$off)>;
+ (STRHHpre (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
+ simm9:$off)>;
def : Pat<(pre_truncsti8 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
- (STRBBpre_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
- simm9:$off)>;
+ (STRBBpre (EXTRACT_SUBREG GPR64:$Rt, sub_32), 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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (STRQpre_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
+ (STRQpre FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
//---
// (immediate post-indexed)
-def STRWpost : StorePostIdx<0b10, 0, 0b00, GPR32, "str">;
-def STRXpost : StorePostIdx<0b11, 0, 0b00, GPR64, "str">;
-def STRBpost : StorePostIdx<0b00, 1, 0b00, FPR8, "str">;
-def STRHpost : StorePostIdx<0b01, 1, 0b00, FPR16, "str">;
-def STRSpost : StorePostIdx<0b10, 1, 0b00, FPR32, "str">;
-def STRDpost : StorePostIdx<0b11, 1, 0b00, FPR64, "str">;
-def STRQpost : StorePostIdx<0b00, 1, 0b10, FPR128, "str">;
-
-def STRBBpost : StorePostIdx<0b00, 0, 0b00, GPR32, "strb">;
-def STRHHpost : StorePostIdx<0b01, 0, 0b00, GPR32, "strh">;
-
-// 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>;
+def STRWpost : StorePostIdx<0b10, 0, 0b00, GPR32, "str", post_store, i32>;
+def STRXpost : StorePostIdx<0b11, 0, 0b00, GPR64, "str", post_store, i64>;
+def STRBpost : StorePostIdx<0b00, 1, 0b00, FPR8, "str", post_store, untyped>;
+def STRHpost : StorePostIdx<0b01, 1, 0b00, FPR16, "str", post_store, f16>;
+def STRSpost : StorePostIdx<0b10, 1, 0b00, FPR32, "str", post_store, f32>;
+def STRDpost : StorePostIdx<0b11, 1, 0b00, FPR64, "str", post_store, f64>;
+def STRQpost : StorePostIdx<0b00, 1, 0b10, FPR128, "str", post_store, f128>;
+
+def STRBBpost : StorePostIdx<0b00, 0, 0b00, GPR32, "strb", post_truncsti8, i32>;
+def STRHHpost : StorePostIdx<0b01, 0, 0b00, GPR32, "strh", post_truncsti16, i32>;
+
// truncstore i64
def : Pat<(post_truncsti32 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
- (STRWpost_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
- simm9:$off)>;
+ (STRWpost (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
+ simm9:$off)>;
def : Pat<(post_truncsti16 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
- (STRHHpost_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
- simm9:$off)>;
+ (STRHHpost (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
+ simm9:$off)>;
def : Pat<(post_truncsti8 GPR64:$Rt, GPR64sp:$addr, simm9:$off),
- (STRBBpost_isel (EXTRACT_SUBREG GPR64:$Rt, sub_32), GPR64sp:$addr,
- simm9:$off)>;
+ (STRBBpost (EXTRACT_SUBREG GPR64:$Rt, sub_32), 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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (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),
- (STRQpost_isel FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
+ (STRQpost FPR128:$Rt, GPR64sp:$addr, simm9:$off)>;
//===----------------------------------------------------------------------===//
// Load/store exclusive instructions.
diff --git a/lib/Target/ARM64/ARM64LoadStoreOptimizer.cpp b/lib/Target/ARM64/ARM64LoadStoreOptimizer.cpp
index 9a8e1c3d91..e2c4b13f03 100644
--- a/lib/Target/ARM64/ARM64LoadStoreOptimizer.cpp
+++ b/lib/Target/ARM64/ARM64LoadStoreOptimizer.cpp
@@ -528,6 +528,7 @@ ARM64LoadStoreOpt::mergePreIdxUpdateInsn(MachineBasicBlock::iterator I,
unsigned NewOpc = getPreIndexedOpcode(I->getOpcode());
MachineInstrBuilder MIB =
BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc))
+ .addOperand(Update->getOperand(0))
.addOperand(I->getOperand(0))
.addOperand(I->getOperand(1))
.addImm(Value);
@@ -571,6 +572,7 @@ ARM64LoadStoreOpt::mergePostIdxUpdateInsn(MachineBasicBlock::iterator I,
unsigned NewOpc = getPostIndexedOpcode(I->getOpcode());
MachineInstrBuilder MIB =
BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc))
+ .addOperand(Update->getOperand(0))
.addOperand(I->getOperand(0))
.addOperand(I->getOperand(1))
.addImm(Value);
diff --git a/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp b/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
index 982690fe86..0c422c5cec 100644
--- a/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
+++ b/lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
@@ -3146,9 +3146,9 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::LDPWpre:
case ARM64::LDPXpost:
case ARM64::LDPXpre: {
- unsigned Rt = Inst.getOperand(0).getReg();
- unsigned Rt2 = Inst.getOperand(1).getReg();
- unsigned Rn = Inst.getOperand(2).getReg();
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rt2 = Inst.getOperand(2).getReg();
+ unsigned Rn = Inst.getOperand(3).getReg();
if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable LDP instruction, writeback base "
"is also a destination");
@@ -3157,13 +3157,6 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
"is also a destination");
// 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::LDPQi:
case ARM64::LDPSi:
@@ -3176,6 +3169,19 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
return Error(Loc[1], "unpredictable LDP instruction, Rt2==Rt");
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::STPDpre:
case ARM64::STPQpost:
@@ -3186,9 +3192,9 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::STPWpre:
case ARM64::STPXpost:
case ARM64::STPXpre: {
- unsigned Rt = Inst.getOperand(0).getReg();
- unsigned Rt2 = Inst.getOperand(1).getReg();
- unsigned Rn = Inst.getOperand(2).getReg();
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rt2 = Inst.getOperand(2).getReg();
+ unsigned Rn = Inst.getOperand(3).getReg();
if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable STP instruction, writeback base "
"is also a source");
@@ -3219,8 +3225,8 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::LDRSWpost:
case ARM64::LDRWpost:
case ARM64::LDRXpost: {
- unsigned Rt = Inst.getOperand(0).getReg();
- unsigned Rn = Inst.getOperand(1).getReg();
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rn = Inst.getOperand(2).getReg();
if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable LDR instruction, writeback base "
"is also a source");
@@ -3238,8 +3244,8 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
case ARM64::STRHpre:
case ARM64::STRWpre:
case ARM64::STRXpre: {
- unsigned Rt = Inst.getOperand(0).getReg();
- unsigned Rn = Inst.getOperand(1).getReg();
+ unsigned Rt = Inst.getOperand(1).getReg();
+ unsigned Rn = Inst.getOperand(2).getReg();
if (RI->isSubRegisterEq(Rn, Rt))
return Error(Loc[0], "unpredictable STR instruction, writeback base "
"is also a source");
diff --git a/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp b/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp
index 20bcb366bf..4fa9339d2b 100644
--- a/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp
+++ b/lib/Target/ARM64/Disassembler/ARM64Disassembler.cpp
@@ -902,6 +902,60 @@ static DecodeStatus DecodeSignedLdStInstruction(llvm::MCInst &Inst,
if (offset & (1 << (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()) {
default:
return Fail;
@@ -1112,6 +1166,37 @@ static DecodeStatus DecodePairLdStInstruction(llvm::MCInst &Inst, uint32_t insn,
unsigned Opcode = Inst.getOpcode();
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) {
default:
return Fail;