The instruction DINS may be transformed into DINSU or DEXTM depending
[oota-llvm.git] / lib / Target / Mips / MipsAsmPrinter.cpp
index fc47ba5bfd6fa28b4a10c61cf54ca02564b33a54..e4db9915f0a9f2de20e535009f44e08d8d7c9996 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #define DEBUG_TYPE "mips-asm-printer"
-#include "MipsAsmPrinter.h"
 #include "Mips.h"
+#include "MipsAsmPrinter.h"
 #include "MipsInstrInfo.h"
+#include "MipsMCInstLower.h"
 #include "InstPrinter/MipsInstPrinter.h"
 #include "MCTargetDesc/MipsBaseInfo.h"
 #include "llvm/ADT/SmallString.h"
@@ -62,9 +63,43 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) {
 
   do {
     MCInst TmpInst0;
+
+    // Direct object specific instruction lowering
+    if (!OutStreamer.hasRawTextSupport())
+      switch (I->getOpcode()) {
+      // If shift amount is >= 32 it the inst needs to be lowered further
+      case Mips::DSLL:
+      case Mips::DSRL:
+      case Mips::DSRA:
+      {
+        assert(I->getNumOperands() == 3 &&
+            "Invalid no. of machine operands for shift!");
+        assert(I->getOperand(2).isImm());
+        int64_t Shift = I->getOperand(2).getImm();
+        if (Shift > 31) {
+          MCInst TmpInst0;
+          MCInstLowering.LowerLargeShift(I, TmpInst0, Shift - 32);
+          OutStreamer.EmitInstruction(TmpInst0);
+          return;
+        }
+      }
+      break;
+      // Double extract instruction is chosen by pos and size operands
+      case Mips::DEXT:
+      case Mips::DINS:
+        assert(Subtarget->hasMips64() && "DEXT/DINS are MIPS64 instructions");
+        {
+          MCInst TmpInst0;
+          MCInstLowering.LowerDextDins(I, TmpInst0);
+          OutStreamer.EmitInstruction(TmpInst0);
+          return;
+        }
+      }
+
     MCInstLowering.Lower(I++, TmpInst0);
     OutStreamer.EmitInstruction(TmpInst0);
-  } while ((I != E) && I->isInsideBundle());
+
+  } while ((I != E) && I->isInsideBundle()); // Delay slot check
 }
 
 //===----------------------------------------------------------------------===//
@@ -333,8 +368,10 @@ bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
         O << "$0";
       return false;
     }
-    case 'D': {
-      // Second part of a double word register operand
+    case 'D': // Second part of a double word register operand
+    case 'L': // Low order register of a double word register operand
+    case 'M': // High order register of a double word register operand
+    {
       if (OpNum == 0)
         return true;
       const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);
@@ -352,20 +389,30 @@ bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
         }
         return true;
       }
-      unsigned RegOp;
-      switch(ExtraCode[0]) {
-      case 'D':
-        RegOp = (!Subtarget->isGP32bit()) ? OpNum : OpNum + 1;
-        break;
+
+      unsigned RegOp = OpNum;
+      if (!Subtarget->isGP64bit()){
+        // Endianess reverses which register holds the high or low value
+        // between M and L.
+        switch(ExtraCode[0]) {
+        case 'M':
+          RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum;
+          break;
+        case 'L':
+          RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1;
+          break;
+        case 'D': // Always the second part
+          RegOp = OpNum + 1;
+        }
+        if (RegOp >= MI->getNumOperands())
+          return true;
+        const MachineOperand &MO = MI->getOperand(RegOp);
+        if (!MO.isReg())
+          return true;
+        unsigned Reg = MO.getReg();
+        O << '$' << MipsInstPrinter::getRegisterName(Reg);
+        return false;
       }
-      if (RegOp >= MI->getNumOperands())
-        return true;
-      const MachineOperand &MO = MI->getOperand(RegOp);
-      if (!MO.isReg())
-        return true;
-      unsigned Reg = MO.getReg();
-      O << '$' << MipsInstPrinter::getRegisterName(Reg);
-      return false;
     }
     }
   }