[mips][microMIPS] Implement SWP and LWP instructions
authorZoran Jovanovic <zoran.jovanovic@imgtec.com>
Tue, 16 Dec 2014 14:59:10 +0000 (14:59 +0000)
committerZoran Jovanovic <zoran.jovanovic@imgtec.com>
Tue, 16 Dec 2014 14:59:10 +0000 (14:59 +0000)
Differential Revision: http://reviews.llvm.org/D5667

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@224338 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/Mips/AsmParser/MipsAsmParser.cpp
lib/Target/Mips/Disassembler/MipsDisassembler.cpp
lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
lib/Target/Mips/InstPrinter/MipsInstPrinter.h
lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
lib/Target/Mips/MicroMipsInstrInfo.td
test/MC/Disassembler/Mips/micromips.txt
test/MC/Disassembler/Mips/micromips_le.txt
test/MC/Mips/micromips-loadstore-instructions.s

index 67725cb7ffa03b61deb0f681fceafc37aeeb5b5b..44e0532f413c2365917db16b3433ba202153dcef 100644 (file)
@@ -146,6 +146,9 @@ class MipsAsmParser : public MCTargetAsmParser {
 
   MipsAsmParser::OperandMatchResultTy parseLSAImm(OperandVector &Operands);
 
+  MipsAsmParser::OperandMatchResultTy
+  parseRegisterPair (OperandVector &Operands);
+
   MipsAsmParser::OperandMatchResultTy
   parseRegisterList (OperandVector  &Operands);
 
@@ -428,7 +431,8 @@ private:
     k_PhysRegister,  /// A physical register from the Mips namespace
     k_RegisterIndex, /// A register index in one or more RegKind.
     k_Token,         /// A simple token
-    k_RegList        /// A physical register list
+    k_RegList,       /// A physical register list
+    k_RegPair        /// A pair of physical register
   } Kind;
 
 public:
@@ -781,6 +785,13 @@ public:
       Inst.addOperand(MCOperand::CreateReg(RegNo));
   }
 
+  void addRegPairOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 2 && "Invalid number of operands!");
+    unsigned RegNo = getRegPair();
+    Inst.addOperand(MCOperand::CreateReg(RegNo++));
+    Inst.addOperand(MCOperand::CreateReg(RegNo));
+  }
+
   bool isReg() const override {
     // As a special case until we sort out the definition of div/divu, pretend
     // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly.
@@ -845,6 +856,7 @@ public:
     assert(Kind == k_Token && "Invalid access!");
     return StringRef(Tok.Data, Tok.Length);
   }
+  bool isRegPair() const { return Kind == k_RegPair; }
 
   unsigned getReg() const override {
     // As a special case until we sort out the definition of div/divu, pretend
@@ -886,6 +898,11 @@ public:
     return *(RegList.List);
   }
 
+  unsigned getRegPair() const {
+    assert((Kind == k_RegPair) && "Invalid access!");
+    return RegIdx.Index;
+  }
+
   static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S,
                                                   MipsAsmParser &Parser) {
     auto Op = make_unique<MipsOperand>(k_Token, Parser);
@@ -995,6 +1012,15 @@ public:
     return Op;
   }
 
+  static std::unique_ptr<MipsOperand>
+  CreateRegPair(unsigned RegNo, SMLoc S, SMLoc E, MipsAsmParser &Parser) {
+    auto Op = make_unique<MipsOperand>(k_RegPair, Parser);
+    Op->RegIdx.Index = RegNo;
+    Op->StartLoc = S;
+    Op->EndLoc = E;
+    return Op;
+  }
+
   bool isGPRAsmReg() const {
     return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31;
   }
@@ -1061,6 +1087,7 @@ public:
     case k_PhysRegister:
     case k_RegisterIndex:
     case k_Token:
+    case k_RegPair:
       break;
     }
   }
@@ -1094,6 +1121,9 @@ public:
         OS << Reg << " ";
       OS <<  ">";
       break;
+    case k_RegPair:
+      OS << "RegPair<" << RegIdx.Index << "," << RegIdx.Index + 1 << ">";
+      break;
     }
   }
 }; // class MipsOperand
@@ -2723,6 +2753,22 @@ MipsAsmParser::parseRegisterList(OperandVector &Operands) {
   return MatchOperand_Success;
 }
 
+MipsAsmParser::OperandMatchResultTy
+MipsAsmParser::parseRegisterPair(OperandVector &Operands) {
+  MCAsmParser &Parser = getParser();
+
+  SMLoc S = Parser.getTok().getLoc();
+  if (parseAnyRegister(Operands) != MatchOperand_Success)
+    return MatchOperand_ParseFail;
+
+  SMLoc E = Parser.getTok().getLoc();
+  MipsOperand &Op = static_cast<MipsOperand &>(*Operands.back());
+  unsigned Reg = Op.getGPR32Reg();
+  Operands.pop_back();
+  Operands.push_back(MipsOperand::CreateRegPair(Reg, S, E, *this));
+  return MatchOperand_Success;
+}
+
 MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) {
 
   MCSymbolRefExpr::VariantKind VK =
index ec90781f6292a0c66358732f6e495039d5dbffe0..d29347d6213c77a9ac44ca1897c3b1e6f92866b3 100644 (file)
@@ -1222,6 +1222,9 @@ static DecodeStatus DecodeMemMMImm12(MCInst &Inst,
     // fallthrough
   default:
     Inst.addOperand(MCOperand::CreateReg(Reg));
+    if (Inst.getOpcode() == Mips::LWP_MM || Inst.getOpcode() == Mips::SWP_MM)
+      Inst.addOperand(MCOperand::CreateReg(Reg+1));
+
     Inst.addOperand(MCOperand::CreateReg(Base));
     Inst.addOperand(MCOperand::CreateImm(Offset));
   }
index e8366290c164e7e54be62dbda5395109a2c9f972..80e555e5f5ca73c5f34aaa97f308060ad48a1a1c 100644 (file)
@@ -261,6 +261,11 @@ printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O) {
   O << MipsFCCToString((Mips::CondCode)MO.getImm());
 }
 
+void MipsInstPrinter::
+printRegisterPair(const MCInst *MI, int opNum, raw_ostream &O) {
+  printRegName(O, MI->getOperand(opNum).getReg());
+}
+
 void MipsInstPrinter::
 printSHFMask(const MCInst *MI, int opNum, raw_ostream &O) {
   llvm_unreachable("TODO");
index 42df0131d0a95e98b3547a463b867edc03fe4f45..468dc07818e7e516d94601f7f7ad494e6fead7ef 100644 (file)
@@ -99,6 +99,7 @@ private:
   void printMemOperand(const MCInst *MI, int opNum, raw_ostream &O);
   void printMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O);
   void printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O);
+  void printRegisterPair(const MCInst *MI, int opNum, raw_ostream &O);
   void printSHFMask(const MCInst *MI, int opNum, raw_ostream &O);
 
   bool printAlias(const char *Str, const MCInst &MI, unsigned OpNo,
index 0c86d11659c7dcc0f91f86334ac540328659fc00..689248b065f7c798bc0e4a5b171d7fcf9ec649a3 100644 (file)
@@ -862,4 +862,11 @@ MipsMCCodeEmitter::getRegisterListOpValue16(const MCInst &MI, unsigned OpNo,
   return (MI.getNumOperands() - 4);
 }
 
+unsigned
+MipsMCCodeEmitter::getRegisterPairOpValue(const MCInst &MI, unsigned OpNo,
+                                          SmallVectorImpl<MCFixup> &Fixups,
+                                          const MCSubtargetInfo &STI) const {
+  return getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI);
+}
+
 #include "MipsGenMCCodeEmitter.inc"
index b557f7404306aa5301037886e792f229c50eeeb7..4a4c9f6e0d3dea5185ec7ca2b81d36c81c099fec 100644 (file)
@@ -184,6 +184,10 @@ public:
                             SmallVectorImpl<MCFixup> &Fixups,
                             const MCSubtargetInfo &STI) const;
 
+  unsigned getRegisterPairOpValue(const MCInst &MI, unsigned OpNo,
+                                  SmallVectorImpl<MCFixup> &Fixups,
+                                  const MCSubtargetInfo &STI) const;
+
   unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,
                           const MCSubtargetInfo &STI) const;
 
index 9675ef214116a20d33deecddd1eb079373580af2..3fae97c32ef47ed0195cec02f01dc10459bcbe00 100644 (file)
@@ -148,6 +148,36 @@ class StoreLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
   let DecoderMethod = "DecodeMemMMImm12";
 }
 
+/// A register pair used by load/store pair instructions.
+def RegPairAsmOperand : AsmOperandClass {
+  let Name = "RegPair";
+  let ParserMethod = "parseRegisterPair";
+}
+
+def regpair : Operand<i32> {
+  let EncoderMethod = "getRegisterPairOpValue";
+  let ParserMatchClass = RegPairAsmOperand;
+  let PrintMethod = "printRegisterPair";
+  let DecoderMethod = "DecodeRegPairOperand";
+  let MIOperandInfo = (ops GPR32Opnd, GPR32Opnd);
+}
+
+class StorePairMM<string opstr, InstrItinClass Itin = NoItinerary,
+                  ComplexPattern Addr = addr> :
+  InstSE<(outs), (ins regpair:$rt, mem_mm_12:$addr),
+         !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> {
+  let DecoderMethod = "DecodeMemMMImm12";
+  let mayStore = 1;
+}
+
+class LoadPairMM<string opstr, InstrItinClass Itin = NoItinerary,
+                 ComplexPattern Addr = addr> :
+  InstSE<(outs regpair:$rt), (ins mem_mm_12:$addr),
+          !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> {
+  let DecoderMethod = "DecodeMemMMImm12";
+  let mayLoad = 1;
+}
+
 class LLBaseMM<string opstr, RegisterOperand RO> :
   InstSE<(outs RO:$rt), (ins mem_mm_12:$addr),
          !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> {
@@ -555,6 +585,10 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {
   def SWM16_MM : StoreMultMM16<"swm16">, LWM_FM_MM16<0x5>;
   def LWM16_MM : LoadMultMM16<"lwm16">, LWM_FM_MM16<0x4>;
 
+  /// Load and Store Pair Instructions
+  def SWP_MM  : StorePairMM<"swp">, LWM_FM_MM<0x9>;
+  def LWP_MM  : LoadPairMM<"lwp">, LWM_FM_MM<0x1>;
+
   /// Move Conditional
   def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd,
                   NoItinerary>, ADD_FM_MM<0, 0x58>;
index 164f5396df9fbb65fb0bad62faafddb85ecfb4b5..87aa9ede66d17df4fa390a3305bc65cb99e1dcde 100644 (file)
 # CHECK: swm32 $16, $17, 8($4)
 0x20 0x44 0xd0 0x08
 
+# CHECK: swp $16, 8($4)
+0x22 0x04 0x90 0x08
+
+# CHECK: lwp $16, 8($4)
+0x22 0x04 0x10 0x08
+
 # CHECK: nop
 0x00 0x00 0x00 0x00
 
index 39be8dc57b6a21fc98f2cb2670636d20500eb7f2..71acaf28aa0701d9ca309464b4f010381a6da14f 100644 (file)
 # CHECK: swm32 $16, $17, 8($4)
 0x44 0x20 0x08 0xd0
 
+# CHECK: swp $16, 8($4)
+0x04 0x22  0x08 0x90
+
+# CHECK: lwp $16, 8($4)
+0x04 0x22 0x08 0x10
+
 # CHECK: nop
 0x00 0x00 0x00 0x00
 
index 8c406695cf68ddefe901496faf81f0ec471cb973..5133c36bb02a109c05efdb80a58f93a0280ebf64 100644 (file)
@@ -31,6 +31,8 @@
 # CHECK-EL: swm32  $16, $17, $18, $19, 8($4)  # encoding: [0x84,0x20,0x08,0xd0]
 # CHECK-EL: lwm16  $16, $17, $ra, 8($sp)      # encoding: [0x12,0x45]
 # CHECK-EL: swm16  $16, $17, $ra, 8($sp)      # encoding: [0x52,0x45]
+# CHECK-EL: swp    $16, 8($4)                 # encoding: [0x04,0x22,0x08,0x90]
+# CHECK-EL: lwp    $16, 8($4)                 # encoding: [0x04,0x22,0x08,0x10]
 #------------------------------------------------------------------------------
 # Big endian
 #------------------------------------------------------------------------------
@@ -56,6 +58,8 @@
 # CHECK-EB: swm32  $16, $17, $18, $19, 8($4) # encoding: [0x20,0x84,0xd0,0x08]
 # CHECK-EB: lwm16  $16, $17, $ra, 8($sp)     # encoding: [0x45,0x12]
 # CHECK-EB: swm16  $16, $17, $ra, 8($sp)     # encoding: [0x45,0x52]
+# CHECK-EB: swp    $16, 8($4)                # encoding: [0x22,0x04,0x90,0x08]
+# CHECK-EB: lwp    $16, 8($4)                # encoding: [0x22,0x04,0x10,0x08]
      lb     $5, 8($4)
      lbu    $6, 8($4)
      lh     $2, 8($4)
@@ -78,3 +82,5 @@
      swm32  $16 - $19, 8($4)
      lwm16  $16, $17, $ra, 8($sp)
      swm16  $16, $17, $ra, 8($sp)
+     swp    $16, 8($4)
+     lwp    $16, 8($4)