[mips] Implement the 'dins' aliases.
authorSimon Dardis <simon.dardis@imgtec.com>
Thu, 14 Sep 2017 15:17:50 +0000 (15:17 +0000)
committerSimon Dardis <simon.dardis@imgtec.com>
Thu, 14 Sep 2017 15:17:50 +0000 (15:17 +0000)
Traditionally GAS has provided automatic selection between dins, dinsm and
dinsu. Binutils also disassembles all instructions in that family as 'dins'
rather than the actual instruction.

Reviewers: slthakur

Differential Revision: https://reviews.llvm.org/D34877

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

lib/Target/Mips/AsmParser/MipsAsmParser.cpp
lib/Target/Mips/Disassembler/MipsDisassembler.cpp
lib/Target/Mips/MicroMips64r6InstrInfo.td
lib/Target/Mips/Mips64InstrInfo.td
lib/Target/Mips/MipsInstrInfo.td
test/MC/Disassembler/Mips/micromips64r6/valid.txt
test/MC/Mips/micromips64r6/invalid-wrong-error.s
test/MC/Mips/micromips64r6/invalid.s
test/MC/Mips/micromips64r6/valid.s
test/MC/Mips/mips64extins.s

index 9fcf917a8530540db90ee893b2bb37188af73ae7..0714f8cb5224db4f5939ae72b04b6fe03a46d9f2 100644 (file)
@@ -463,6 +463,8 @@ public:
     Match_RequiresSameSrcAndDst,
     Match_NoFCCRegisterForCurrentISA,
     Match_NonZeroOperandForSync,
+    Match_RequiresPosSizeRange0_32,
+    Match_RequiresPosSizeRange33_64,
 #define GET_OPERAND_DIAGNOSTIC_TYPES
 #include "MipsGenAsmMatcher.inc"
 #undef GET_OPERAND_DIAGNOSTIC_TYPES
@@ -4977,6 +4979,28 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
     if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())
       return Match_RequiresDifferentOperands;
     return Match_Success;
+   case Mips::DINS:
+   case Mips::DINS_MM64R6: {
+     assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() &&
+            "Operands must be immediates for dins!");
+     const signed Pos = Inst.getOperand(2).getImm();
+     const signed Size = Inst.getOperand(3).getImm();
+     if ((0 > (Pos + Size)) || ((Pos + Size) > 32))
+       return Match_RequiresPosSizeRange0_32;
+     return Match_Success;
+   }
+   case Mips::DINSM:
+   case Mips::DINSM_MM64R6:
+   case Mips::DINSU:
+   case Mips::DINSU_MM64R6: {
+     assert(Inst.getOperand(2).isImm() && Inst.getOperand(3).isImm() &&
+            "Operands must be immediates for dinsm/dinsu!");
+     const signed Pos = Inst.getOperand(2).getImm();
+     const signed Size = Inst.getOperand(3).getImm();
+     if ((32 >= (Pos + Size)) || ((Pos + Size) > 64))
+       return Match_RequiresPosSizeRange33_64;
+     return Match_Success;
+   }
   }
 
   uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags;
@@ -5169,6 +5193,18 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_MemSImm16:
     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
                  "expected memory with 16-bit signed offset");
+  case Match_RequiresPosSizeRange0_32: {
+    SMLoc ErrorStart = Operands[3]->getStartLoc();
+    SMLoc ErrorEnd = Operands[4]->getEndLoc();
+    return Error(ErrorStart, "size plus position are not in the range 0 .. 32",
+                 SMRange(ErrorStart, ErrorEnd));
+    }
+  case Match_RequiresPosSizeRange33_64: {
+    SMLoc ErrorStart = Operands[3]->getStartLoc();
+    SMLoc ErrorEnd = Operands[4]->getEndLoc();
+    return Error(ErrorStart, "size plus position are not in the range 33 .. 64",
+                 SMRange(ErrorStart, ErrorEnd));
+    }
   }
 
   llvm_unreachable("Implement any new match types added!");
index 41b965731e3af5a900ad29796a8382d78c788c46..8bd2e791998f8bea94ff3c647e36c3b9702358db 100644 (file)
@@ -519,6 +519,10 @@ static DecodeStatus
 DecodeBlezGroupBranchMMR6(MCInst &MI, InsnType insn, uint64_t Address,
                           const void *Decoder);
 
+template <typename InsnType>
+static DecodeStatus DecodeDINS(MCInst &MI, InsnType Insn, uint64_t Address,
+                               const void *Decoder);
+
 static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn,
                                          uint64_t Address,
                                          const void *Decoder);
@@ -1051,6 +1055,60 @@ static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn,
   return MCDisassembler::Success;
 }
 
+// Override the generated disassembler to produce DINS all the time. This is
+// for feature / behaviour parity with binutils.
+template <typename InsnType>
+static DecodeStatus DecodeDINS(MCInst &MI, InsnType Insn, uint64_t Address,
+                               const void *Decoder) {
+  unsigned Msbd = fieldFromInstruction(Insn, 11, 5);
+  unsigned Lsb = fieldFromInstruction(Insn, 6, 5);
+  unsigned Size = 0;
+  unsigned Pos = 0;
+  bool IsMicroMips = false;
+
+  switch (MI.getOpcode()) {
+    case Mips::DINS_MM64R6:
+      IsMicroMips = true;
+      LLVM_FALLTHROUGH;
+    case Mips::DINS:
+      Pos = Lsb;
+      Size = Msbd + 1 - Pos;
+      break;
+    case Mips::DINSM_MM64R6:
+      IsMicroMips = true;
+      LLVM_FALLTHROUGH;
+    case Mips::DINSM:
+      Pos = Lsb;
+      Size = Msbd + 33 - Pos;
+      break;
+    case Mips::DINSU_MM64R6:
+      IsMicroMips = true;
+      LLVM_FALLTHROUGH;
+    case Mips::DINSU:
+      Pos = Lsb + 32;
+      // mbsd = pos + size - 33
+      // mbsd - pos + 33 = size
+      Size = Msbd + 33 - Pos;
+      break;
+    default:
+      llvm_unreachable("Unknown DINS instruction!");
+  }
+
+  // Although the format of the instruction is similar, rs and rt are swapped
+  // for microMIPS64R6.
+  InsnType Rs = fieldFromInstruction(Insn, 21, 5);
+  InsnType Rt = fieldFromInstruction(Insn, 16, 5);
+  if (IsMicroMips)
+    std::swap(Rs, Rt);
+
+  MI.setOpcode(IsMicroMips ? Mips::DINS_MM64R6 : Mips::DINS);
+  MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID, Rt)));
+  MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR64RegClassID, Rs)));
+  MI.addOperand(MCOperand::createImm(Pos));
+  MI.addOperand(MCOperand::createImm(Size));
+
+  return MCDisassembler::Success;
+}
 /// Read two bytes from the ArrayRef and return 16 bit halfword sorted
 /// according to the given endianness.
 static DecodeStatus readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
@@ -2260,15 +2318,10 @@ static DecodeStatus DecodeInsSize(MCInst &Inst,
                                   uint64_t Address,
                                   const void *Decoder) {
   // First we need to grab the pos(lsb) from MCInst.
+  // This function only handles the 32 bit variants of ins, as dins
+  // variants are handled differently.
   int Pos = Inst.getOperand(2).getImm();
-  if (Inst.getOpcode() == Mips::DINSU)
-    Pos += 32;
-  int Size;
-  if (Inst.getOpcode() == Mips::DINSM ||
-      Inst.getOpcode() == Mips::DINSU)
-    Size = (int) Insn - Pos + 33;
-  else
-    Size = (int) Insn - Pos + 1;
+  int Size = (int) Insn - Pos + 1;
   Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Size)));
   return MCDisassembler::Success;
 }
index a37b31643ac3ece86259efe068835db04c5dc444..4f7248e8d014e8553d8fb9612ecab832d38ab1cc 100644 (file)
@@ -168,8 +168,9 @@ class DINSU_MM64R6_DESC : InsBase<"dinsu", GPR64Opnd, uimm5_plus32,
                                   immZExt5Plus1, MipsIns>;
 class DINSM_MM64R6_DESC : InsBase<"dinsm", GPR64Opnd, uimm5, uimm_range_2_64,
                                   immZExt5, immZExtRange2To64, MipsIns>;
-class DINS_MM64R6_DESC : InsBase<"dins", GPR64Opnd, uimm5, uimm5_inssize_plus1,
-                                 immZExt5, immZExt5Plus1,  MipsIns>;
+class DINS_MM64R6_DESC : InsBase<"dins", GPR64Opnd, uimm5_report_uimm6,
+                                 uimm5_inssize_plus1, immZExt5, immZExt5Plus1,
+                                 MipsIns>;
 class DMTC0_MM64R6_DESC : MTC0_MMR6_DESC_BASE<"dmtc0", COP0Opnd, GPR64Opnd,
                                               II_DMTC0>;
 class DMTC1_MM64R6_DESC : MTC1_MMR6_DESC_BASE<"dmtc1", FGR64Opnd, GPR64Opnd,
@@ -382,12 +383,14 @@ let DecoderNamespace = "MicroMipsR6" in {
                      ISA_MICROMIPS64R6;
   def DMODU_MM64R6 : R6MMR6Rel, DMODU_MM64R6_DESC, DMODU_MM64R6_ENC,
                      ISA_MICROMIPS64R6;
-  def DINSU_MM64R6: R6MMR6Rel, DINSU_MM64R6_DESC, DINSU_MM64R6_ENC,
-                    ISA_MICROMIPS64R6;
-  def DINSM_MM64R6: R6MMR6Rel, DINSM_MM64R6_DESC, DINSM_MM64R6_ENC,
-                    ISA_MICROMIPS64R6;
-  def DINS_MM64R6: R6MMR6Rel, DINS_MM64R6_DESC, DINS_MM64R6_ENC,
-                   ISA_MICROMIPS64R6;
+  let DecoderMethod = "DecodeDINS" in {
+    def DINSU_MM64R6: R6MMR6Rel, DINSU_MM64R6_DESC, DINSU_MM64R6_ENC,
+                      ISA_MICROMIPS64R6;
+    def DINSM_MM64R6: R6MMR6Rel, DINSM_MM64R6_DESC, DINSM_MM64R6_ENC,
+                      ISA_MICROMIPS64R6;
+    def DINS_MM64R6: R6MMR6Rel, DINS_MM64R6_DESC, DINS_MM64R6_ENC,
+                     ISA_MICROMIPS64R6;
+  }
   def DMTC0_MM64R6 : StdMMR6Rel, DMTC0_MM64R6_ENC, DMTC0_MM64R6_DESC,
                      ISA_MICROMIPS64R6;
   def DMTC1_MM64R6 : StdMMR6Rel, DMTC1_MM64R6_DESC, DMTC1_MM64R6_ENC,
@@ -562,3 +565,10 @@ def : MipsInstAlias<"dsrl $rd, $rt",
 def : MipsInstAlias<"dsll $rd, $rt",
                     (DSLLV_MM64R6 GPR64Opnd:$rd, GPR64Opnd:$rd,
                                   GPR32Opnd:$rt), 0>, ISA_MICROMIPS64R6;
+def : MipsInstAlias<"dins $rt, $rs, $pos, $size",
+                    (DINSM_MM64R6 GPR64Opnd:$rt, GPR64Opnd:$rs, uimm5:$pos,
+                                  uimm_range_2_64:$size), 0>, ISA_MICROMIPS64R6;
+def : MipsInstAlias<"dins $rt, $rs, $pos, $size",
+                    (DINSU_MM64R6 GPR64Opnd:$rt, GPR64Opnd:$rs,
+                                  uimm5_plus32:$pos, uimm5_plus1:$size), 0>,
+                    ISA_MICROMIPS64R6;
index a5c3096739cf99505cc672c7ad8ca51111ae4b06..3f0930355afc3d278f0ba59a1d47546b45c19d53 100644 (file)
@@ -327,14 +327,23 @@ let AdditionalPredicates = [NotInMicroMips] in {
   def DEXTU : ExtBase<"dextu", GPR64Opnd, uimm5_plus32, uimm5_plus1,
                       immZExt5Plus32, immZExt5Plus1, MipsExt>, EXT_FM<2>,
                       ISA_MIPS64R2;
-  def DINS : InsBase<"dins", GPR64Opnd, uimm6, uimm5_inssize_plus1, immZExt5,
-                      immZExt5Plus1, MipsIns>, EXT_FM<7>, ISA_MIPS64R2;
-  def DINSU : InsBase<"dinsu", GPR64Opnd, uimm5_plus32, uimm5_inssize_plus1,
-                      immZExt5Plus32, immZExt5Plus1, MipsIns>,
-              EXT_FM<6>, ISA_MIPS64R2;
-  def DINSM : InsBase<"dinsm", GPR64Opnd, uimm5, uimm_range_2_64,
-                      immZExt5, immZExtRange2To64, MipsIns>,
-              EXT_FM<5>, ISA_MIPS64R2;
+  // The 'pos + size' constraints for code generation are enforced by the
+  // code that lowers into MipsISD::Ins.
+  // For assembly parsing, we alias dinsu and dinsm to dins, and match by
+  // operand were possible then check the 'pos + size' in MipsAsmParser.
+  // We override the generated decoder to enforce that dins always comes out
+  // for dinsm and dinsu like binutils.
+  let DecoderMethod = "DecodeDINS" in {
+    def DINS  : InsBase<"dins", GPR64Opnd, uimm6, uimm5_inssize_plus1,
+                        immZExt5, immZExt5Plus1, MipsIns>, EXT_FM<7>,
+                ISA_MIPS64R2;
+    def DINSU : InsBase<"dinsu", GPR64Opnd, uimm5_plus32, uimm5_inssize_plus1,
+                        immZExt5Plus32, immZExt5Plus1, MipsIns>,
+                EXT_FM<6>, ISA_MIPS64R2;
+    def DINSM : InsBase<"dinsm", GPR64Opnd, uimm5, uimm_range_2_64,
+                        immZExt5, immZExtRange2To64, MipsIns>,
+                EXT_FM<5>, ISA_MIPS64R2;
+  }
 }
 
 let isCodeGenOnly = 1, AdditionalPredicates = [NotInMicroMips] in {
@@ -825,6 +834,12 @@ let AdditionalPredicates = [NotInMicroMips] in {
   def : MipsInstAlias<"dsll $rd, $rt",
                       (DSLLV GPR64Opnd:$rd, GPR64Opnd:$rd, GPR32Opnd:$rt), 0>,
                       ISA_MIPS3;
+  def : MipsInstAlias<"dins $rt, $rs, $pos, $size",
+                      (DINSM GPR64Opnd:$rt, GPR64Opnd:$rs, uimm5:$pos,
+                             uimm_range_2_64:$size), 0>, ISA_MIPS64R2;
+  def : MipsInstAlias<"dins $rt, $rs, $pos, $size",
+                      (DINSU GPR64Opnd:$rt, GPR64Opnd:$rs, uimm5_plus32:$pos,
+                             uimm5_plus1:$size), 0>, ISA_MIPS64R2;
 
 // Two operand (implicit 0 selector) versions:
   def : MipsInstAlias<"dmtc0 $rt, $rd",
index 22410864d70cc4b29719c7b2e1fb960df1325444..0ff1c4cf145e996e5d8e52c5fa9eff559abf0c13 100644 (file)
@@ -883,7 +883,7 @@ def uimm16_altrelaxed : Operand<i32> {
 // Like uimm5 but reports a less confusing error for 32-63 when
 // an instruction alias permits that.
 def uimm5_report_uimm6 : Operand<i32> {
-  let PrintMethod = "printUImm<5>";
+  let PrintMethod = "printUImm<6>";
   let ParserMatchClass = ConstantUImm5ReportUImm6AsmOperandClass;
 }
 
index 337be2fac4f720cfe2215033888667ff8038511b..66827e6d92061ce58f0ebf5eb5fd6fb28e9d0cb1 100644 (file)
 0x00 0x00 0x39 0x7c # CHECK: evp $zero
 0x00 0x00 0x43 0x7c # CHECK: tlbinv
 0x00 0x00 0x53 0x7c # CHECK: tlbinvf
-0x58 0x82 0x20 0x34 # CHECK: dinsu $4, $2, 32, 5
-0x58 0x82 0x38 0xc4 # CHECK: dinsm $4, $2, 3, 5
+0x58 0x82 0x20 0x34 # CHECK: dins $4, $2, 32, 5
+0x58 0x82 0x48 0xc4 # CHECK: dins $4, $2, 3, 39
 0x58 0x82 0x38 0xcc # CHECK: dins $4, $2, 3, 5
 0x00 0xa9 0x02 0xfc # CHECK: mtc0 $5, $9, 0
 0x00 0xa9 0x02 0xfc # CHECK: mtc0 $5, $9
index 977a2d031f2348f78b7bc9d9f3770aebfa6a7eb7..7afa97c997d355710d19b9da657c47a42f948c41 100644 (file)
@@ -34,7 +34,6 @@
   tne $8, $9, -1           # CHECK: :[[@LINE]]:15: error: expected 10-bit unsigned immediate
   tne $8, $9, 16           # CHECK: :[[@LINE]]:3: error: instruction requires a CPU feature not currently enabled
   dins $2, $3, -1, 1       # CHECK: :[[@LINE]]:16: error: expected 6-bit unsigned immediate
-  dins $2, $3, 32, 1       # CHECK: :[[@LINE]]:3: error: instruction requires a CPU feature not currently enabled
   syscall -1               # CHECK: :[[@LINE]]:11: error: expected 20-bit unsigned immediate
   syscall $4               # CHECK: :[[@LINE]]:11: error: expected 20-bit unsigned immediate
   syscall 1024             # CHECK: :[[@LINE]]:3: error: instruction requires a CPU feature not currently enabled
index 30021ea10f020ed7131af4b50987089d87d44db2..ffe50e75bf453bd5184ba0ba531f734a98dcab29 100644 (file)
@@ -45,9 +45,7 @@
   dextu $2, $3, 64, 1  # CHECK: :[[@LINE]]:17: error: expected immediate in range 32 .. 63
   dextu $2, $3, 32, 0  # CHECK: :[[@LINE]]:21: error: expected immediate in range 1 .. 32
   dextu $2, $3, 32, 33 # CHECK: :[[@LINE]]:21: error: expected immediate in range 1 .. 32
-  dins $2, $3, 31, 33  # CHECK: :[[@LINE]]:20: error: expected immediate in range 1 .. 32
   dins $2, $3, 31, 0   # CHECK: :[[@LINE]]:20: error: expected immediate in range 1 .. 32
-  # FIXME: Check '32 <= pos + size <= 64' constraint on dinsm
   dinsm $2, $3, -1, 1  # CHECK: :[[@LINE]]:17: error: expected 5-bit unsigned immediate
   dinsm $2, $3, 32, 1  # CHECK: :[[@LINE]]:17: error: expected 5-bit unsigned immediate
   dinsm $2, $3, 31, 0  # CHECK: :[[@LINE]]:21: error: expected immediate in range 2 .. 64
index 3ead62fc61692c26deab325095bd55075a44770b..641e16c14574290121eb013a1b4f49f79af91a6f 100644 (file)
@@ -198,7 +198,7 @@ a:
         tlbinv                   # CHECK: tlbinv                  # encoding: [0x00,0x00,0x43,0x7c]
         tlbinvf                  # CHECK: tlbinvf                 # encoding: [0x00,0x00,0x53,0x7c]
         dinsu $4, $2, 32, 5      # CHECK: dinsu $4, $2, 32, 5     # encoding: [0x58,0x82,0x20,0x34]
-        dinsm $4, $2, 3, 5       # CHECK: dinsm $4, $2, 3, 5      # encoding: [0x58,0x82,0x38,0xc4]
+        dinsm $4, $2, 31, 5      # CHECK: dinsm $4, $2, 31, 5     # encoding: [0x58,0x82,0x1f,0xc4]
         dins $4, $2, 3, 5        # CHECK: dins $4, $2, 3, 5       # encoding: [0x58,0x82,0x38,0xcc]
         lh $2, 8($4)             # CHECK: lh $2, 8($4)            # encoding: [0x3c,0x44,0x00,0x08]
         lhe $4, 8($2)            # CHECK: lhe $4, 8($2)           # encoding: [0x60,0x82,0x6a,0x08]
index 5bd18ff62d5e5be20be07c27e36567b245d84b41..ec8281b1ebf0eeda35e3905ee7d286f12432c58d 100644 (file)
@@ -1,9 +1,25 @@
 # RUN: llvm-mc -arch=mips64el -filetype=obj -mcpu=mips64r2 -target-abi=n64 %s -o - \
-# RUN:   | llvm-objdump -disassemble - | FileCheck %s
+# RUN:   | llvm-objdump -disassemble - | FileCheck --check-prefix=OBJ %s
+# RUN: llvm-mc -arch=mips64el -filetype=obj -mcpu=mips64r6 -mattr=+micromips \
+# RUN:         -target-abi=n64 %s -o - | llvm-objdump -disassemble - \
+# RUN:   | FileCheck --check-prefix=OBJ %s
 
-        dext $2, $4, 5, 10   # CHECK: dext ${{[0-9]+}}, ${{[0-9]+}}, 5, 10
-        dextu $2, $4, 34, 6  # CHECK: dextu ${{[0-9]+}}, ${{[0-9]+}}, 34, 6
-        dextm $2, $4, 5, 34  # CHECK: dextm ${{[0-9]+}}, ${{[0-9]+}}, 5, 34
-        dins $4, $5, 8, 10   # CHECK: dins ${{[0-9]+}}, ${{[0-9]+}}, 8, 10
-        dinsm $4, $5, 30, 6  # CHECK: dinsm ${{[0-9]+}}, ${{[0-9]+}}, 30, 6
-        dinsu $4, $5, 40, 13 # CHECK: dinsu ${{[0-9]+}}, ${{[0-9]+}}, 40, 13
+# RUN: llvm-mc -arch=mips64el -mcpu=mips64r2 -target-abi=n64 %s -o - \
+# RUN:   | FileCheck --check-prefix=ASM %s
+# RUN: llvm-mc -arch=mips64el -mcpu=mips64r6 -mattr=+micromips -target-abi=n64 \
+# RUN:     %s -o - | FileCheck --check-prefix=ASM %s
+
+        dext $2, $4, 5, 10   # OBJ: dext ${{[0-9]+}}, ${{[0-9]+}}, 5, 10
+        dextu $2, $4, 34, 6  # OBJ: dextu ${{[0-9]+}}, ${{[0-9]+}}, 34, 6
+        dextm $2, $4, 5, 34  # OBJ: dextm ${{[0-9]+}}, ${{[0-9]+}}, 5, 34
+        dins $4, $5, 8, 10   # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 8, 10
+        dinsm $4, $5, 30, 6  # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 30, 6
+        dinsu $4, $5, 40, 13 # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 40, 13
+        # check the aliases
+        dins $2, $4, 5, 10   # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 5, 10
+        dins $2, $4, 34, 6   # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 34, 6
+        dins $2, $4, 5, 34   # OBJ: dins ${{[0-9]+}}, ${{[0-9]+}}, 5, 34
+        # check the edge values
+        dins $3, $4, 31, 1  # ASM: dins $3, $4, 31, 1
+        dins $3, $4, 31, 33  # ASM: dinsm $3, $4, 31, 33
+        dins $3, $4, 32, 32  # ASM: dinsu $3, $4, 32, 32