From: Tim Northover Date: Thu, 22 May 2014 11:56:20 +0000 (+0000) Subject: ARM64: model pre/post-indexed operations properly. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=369e565f23d34876f1689971b98255dd84131546;p=oota-llvm.git 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 --- diff --git a/lib/Target/ARM64/ARM64AsmPrinter.cpp b/lib/Target/ARM64/ARM64AsmPrinter.cpp index 5531101fe2f..78f9ed12f56 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 3b14649c487..9c17488ec58 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 8fec6f02b76..9b235db30a3 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 bf9fa2992b7..ea45b3d4fb2 100644 --- a/lib/Target/ARM64/ARM64InstrFormats.td +++ b/lib/Target/ARM64/ARM64InstrFormats.td @@ -2918,8 +2918,8 @@ multiclass StoreUnprivileged sz, bit V, bits<2> opc, //--- class BaseLoadStorePreIdx sz, bit V, bits<2> opc, dag oops, dag iops, - string asm, string cstr> - : I { + string asm, string cstr, list pat> + : I { bits<5> Rt; bits<5> Rn; bits<9> offset; @@ -2939,74 +2939,34 @@ class BaseLoadStorePreIdx 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 sz, bit V, bits<2> opc, RegisterClass regtype, string asm> : BaseLoadStorePreIdx, + "$Rn = $wback", []>, Sched<[WriteLD, WriteAdr]>; let mayStore = 1, mayLoad = 0 in class StorePreIdx sz, bit V, bits<2> opc, RegisterClass regtype, - string asm> + string asm, SDPatternOperator storeop, ValueType Ty> : BaseLoadStorePreIdx, + 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 - : Pseudo<(outs regtype:$Rt, GPR64sp:$wback), - (ins GPR64sp:$addr, simm9:$offset), [], - "$addr = $wback,@earlyclobber $wback">, - Sched<[WriteLD, WriteAdr]>; -class LoadPostIdxPseudo - : Pseudo<(outs regtype:$Rt, GPR64sp:$wback), - (ins GPR64sp:$addr, simm9:$offset), [], - "$addr = $wback,@earlyclobber $wback">, - Sched<[WriteLD, WriteI]>; -} -multiclass StorePreIdxPseudo { - 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(NAME#_isel) regtype:$Rt, GPR64sp:$addr, - simm9:$offset)>; -} - //--- // Load/store post-indexed //--- // (pre-index) load/stores. class BaseLoadStorePostIdx sz, bit V, bits<2> opc, dag oops, dag iops, - string asm, string cstr> - : I { + string asm, string cstr, list pat> + : I { bits<5> Rt; bits<5> Rn; bits<9> offset; @@ -3026,51 +2986,26 @@ class BaseLoadStorePostIdx 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 sz, bit V, bits<2> opc, RegisterClass regtype, string asm> : BaseLoadStorePostIdx, + asm, "$Rn = $wback", []>, Sched<[WriteLD, WriteI]>; let mayStore = 1, mayLoad = 0 in class StorePostIdx sz, bit V, bits<2> opc, RegisterClass regtype, - string asm> + string asm, SDPatternOperator storeop, ValueType Ty> : BaseLoadStorePostIdx, + 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 { - 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(NAME#_isel) regtype:$Rt, GPR64sp:$Rn, - simm9:$idx)>; -} //--- // Load/store pair @@ -3129,7 +3064,7 @@ multiclass StorePairOffset opc, bit V, RegisterClass regtype, // (pre-indexed) class BaseLoadStorePairPreIdx opc, bit V, bit L, dag oops, dag iops, string asm> - : I { + : I { bits<5> Rt; bits<5> Rt2; bits<5> Rn; @@ -3152,14 +3087,14 @@ let mayStore = 0, mayLoad = 1 in class LoadPairPreIdx opc, bit V, RegisterClass regtype, Operand indextype, string asm> : BaseLoadStorePairPreIdx, Sched<[WriteLD, WriteLDHi, WriteAdr]>; let mayStore = 1, mayLoad = 0 in class StorePairPreIdx opc, bit V, RegisterClass regtype, Operand indextype, string asm> - : BaseLoadStorePairPreIdx, @@ -3170,7 +3105,7 @@ class StorePairPreIdx opc, bit V, RegisterClass regtype, class BaseLoadStorePairPostIdx opc, bit V, bit L, dag oops, dag iops, string asm> - : I { + : I { bits<5> Rt; bits<5> Rt2; bits<5> Rn; @@ -3193,7 +3128,7 @@ let mayStore = 0, mayLoad = 1 in class LoadPairPostIdx opc, bit V, RegisterClass regtype, Operand idxtype, string asm> : BaseLoadStorePairPostIdx, Sched<[WriteLD, WriteLDHi, WriteAdr]>; @@ -3201,7 +3136,7 @@ let mayStore = 1, mayLoad = 0 in class StorePairPostIdx opc, bit V, RegisterClass regtype, Operand idxtype, string asm> : BaseLoadStorePairPostIdx, Sched<[WriteAdr, WriteSTP]>; diff --git a/lib/Target/ARM64/ARM64InstrInfo.cpp b/lib/Target/ARM64/ARM64InstrInfo.cpp index e1f9667841c..fbbddd56660 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 94a39c11122..9c39d72a8e7 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; -def LDRDpre_isel : LoadPreIdxPseudo; -def LDRSpre_isel : LoadPreIdxPseudo; -def LDRXpre_isel : LoadPreIdxPseudo; -def LDRWpre_isel : LoadPreIdxPseudo; -def LDRHHpre_isel : LoadPreIdxPseudo; -def LDRBBpre_isel : LoadPreIdxPseudo; - -def LDRSWpre_isel : LoadPreIdxPseudo; -def LDRSHWpre_isel : LoadPreIdxPseudo; -def LDRSHXpre_isel : LoadPreIdxPseudo; -def LDRSBWpre_isel : LoadPreIdxPseudo; -def LDRSBXpre_isel : LoadPreIdxPseudo; - //--- // (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; -def LDRDpost_isel : LoadPostIdxPseudo; -def LDRSpost_isel : LoadPostIdxPseudo; -def LDRXpost_isel : LoadPostIdxPseudo; -def LDRWpost_isel : LoadPostIdxPseudo; -def LDRHHpost_isel : LoadPostIdxPseudo; -def LDRBBpost_isel : LoadPostIdxPseudo; - -def LDRSWpost_isel : LoadPostIdxPseudo; -def LDRSHWpost_isel : LoadPostIdxPseudo; -def LDRSHXpost_isel : LoadPostIdxPseudo; -def LDRSBWpost_isel : LoadPostIdxPseudo; -def LDRSBXpost_isel : LoadPostIdxPseudo; - //===----------------------------------------------------------------------===// // 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; -defm STRDpre : StorePreIdxPseudo; -defm STRSpre : StorePreIdxPseudo; -defm STRXpre : StorePreIdxPseudo; -defm STRWpre : StorePreIdxPseudo; -defm STRHHpre : StorePreIdxPseudo; -defm STRBBpre : StorePreIdxPseudo; +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; -defm STRDpost : StorePostIdxPseudo; -defm STRSpost : StorePostIdxPseudo; -defm STRXpost : StorePostIdxPseudo; -defm STRWpost : StorePostIdxPseudo; -defm STRHHpost : StorePostIdxPseudo; -defm STRBBpost : StorePostIdxPseudo; +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 9a8e1c3d91c..e2c4b13f036 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 982690fe86c..0c422c5cece 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 20bcb366bf5..4fa9339d2b7 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;