MC/ARM: Add an ARMOperand class for condition codes.
[oota-llvm.git] / lib / Target / ARM / ARMCodeEmitter.cpp
index cf3ae9817450ec23962676bfeb4ebd8ba36c1db4..d323a32975aea7618435f2cf44b44fd552b92e5e 100644 (file)
@@ -55,6 +55,7 @@ namespace {
     const std::vector<MachineConstantPoolEntry> *MCPEs;
     const std::vector<MachineJumpTableEntry> *MJTEs;
     bool IsPIC;
+    bool IsThumb;
 
     void getAnalysisUsage(AnalysisUsage &AU) const {
       AU.addRequired<MachineModuleInfo>();
@@ -64,11 +65,11 @@ namespace {
     static char ID;
   public:
     ARMCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce)
-      : MachineFunctionPass(&ID), JTI(0),
+      : MachineFunctionPass(ID), JTI(0),
         II((const ARMInstrInfo *)tm.getInstrInfo()),
         TD(tm.getTargetData()), TM(tm),
-    MCE(mce), MCPEs(0), MJTEs(0),
-    IsPIC(TM.getRelocationModel() == Reloc::PIC_) {}
+        MCE(mce), MCPEs(0), MJTEs(0),
+        IsPIC(TM.getRelocationModel() == Reloc::PIC_), IsThumb(false) {}
 
     /// getBinaryCodeForInstr - This function, generated by the
     /// CodeEmitterGenerator using TableGen, produces the binary encoding for
@@ -123,6 +124,8 @@ namespace {
 
     void emitMiscArithInstruction(const MachineInstr &MI);
 
+    void emitSaturateInstruction(const MachineInstr &MI);
+
     void emitBranchInstruction(const MachineInstr &MI);
 
     void emitInlineJumpTable(unsigned JTIndex);
@@ -139,7 +142,8 @@ namespace {
 
     void emitMiscInstruction(const MachineInstr &MI);
 
-    void emitNEONGetLaneInstruction(const MachineInstr &MI);
+    void emitNEONLaneInstruction(const MachineInstr &MI);
+    void emitNEONDupInstruction(const MachineInstr &MI);
     void emitNEON1RegModImmInstruction(const MachineInstr &MI);
     void emitNEON2RegInstruction(const MachineInstr &MI);
     void emitNEON3RegInstruction(const MachineInstr &MI);
@@ -199,6 +203,7 @@ bool ARMCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
   MJTEs = 0;
   if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables();
   IsPIC = TM.getRelocationModel() == Reloc::PIC_;
+  IsThumb = MF.getInfo<ARMFunctionInfo>()->isThumbFunction();
   JTI->Initialize(MF, IsPIC);
   MMI = &getAnalysis<MachineModuleInfo>();
   MCE.setModuleInfo(MMI);
@@ -386,6 +391,9 @@ void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) {
   case ARMII::ArithMiscFrm:
     emitMiscArithInstruction(MI);
     break;
+  case ARMII::SatFrm:
+    emitSaturateInstruction(MI);
+    break;
   case ARMII::BrFrm:
     emitBranchInstruction(MI);
     break;
@@ -415,7 +423,11 @@ void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) {
     break;
   // NEON instructions.
   case ARMII::NGetLnFrm:
-    emitNEONGetLaneInstruction(MI);
+  case ARMII::NSetLnFrm:
+    emitNEONLaneInstruction(MI);
+    break;
+  case ARMII::NDupFrm:
+    emitNEONDupInstruction(MI);
     break;
   case ARMII::N1RegModImmFrm:
     emitNEON1RegModImmInstruction(MI);
@@ -647,6 +659,19 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) {
   switch (Opcode) {
   default:
     llvm_unreachable("ARMCodeEmitter::emitPseudoInstruction");
+  case ARM::BX:
+  case ARM::BMOVPCRX:
+  case ARM::BXr9:
+  case ARM::BMOVPCRXr9: {
+    // First emit mov lr, pc
+    unsigned Binary = 0x01a0e00f;
+    Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+    emitWordLE(Binary);
+
+    // and then emit the branch.
+    emitMiscBranchInstruction(MI);
+    break;
+  }
   case TargetOpcode::INLINEASM: {
     // We allow inline assembler nodes with empty bodies - they can
     // implicitly define registers, which is ok for JIT.
@@ -655,7 +680,7 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) {
     }
     break;
   }
-  case TargetOpcode::DBG_LABEL:
+  case TargetOpcode::PROLOG_LABEL:
   case TargetOpcode::EH_LABEL:
     MCE.emitLabel(MI.getOperand(0).getMCSymbol());
     break;
@@ -1208,6 +1233,46 @@ void ARMCodeEmitter::emitMiscArithInstruction(const MachineInstr &MI) {
   emitWordLE(Binary);
 }
 
+void ARMCodeEmitter::emitSaturateInstruction(const MachineInstr &MI) {
+  const TargetInstrDesc &TID = MI.getDesc();
+
+  // Part of binary is determined by TableGen.
+  unsigned Binary = getBinaryCodeForInstr(MI);
+
+  // Set the conditional execution predicate
+  Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+
+  // Encode Rd
+  Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift;
+
+  // Encode saturate bit position.
+  unsigned Pos = MI.getOperand(1).getImm();
+  if (TID.Opcode == ARM::SSATlsl ||
+      TID.Opcode == ARM::SSATasr ||
+      TID.Opcode == ARM::SSAT16)
+    Pos -= 1;
+  assert((Pos < 16 || (Pos < 32 &&
+                       TID.Opcode != ARM::SSAT16 &&
+                       TID.Opcode != ARM::USAT16)) &&
+         "saturate bit position out of range");
+  Binary |= Pos << 16;
+
+  // Encode Rm
+  Binary |= getMachineOpValue(MI, 2);
+
+  // Encode shift_imm.
+  if (TID.getNumOperands() == 4) {
+    unsigned ShiftAmt = MI.getOperand(3).getImm();
+    if (ShiftAmt == 32 &&
+        (TID.Opcode == ARM::SSATasr || TID.Opcode == ARM::USATasr))
+      ShiftAmt = 0;
+    assert(ShiftAmt < 32 && "shift_imm range is 0 to 31!");
+    Binary |= ShiftAmt << ARMII::ShiftShift;
+  }
+
+  emitWordLE(Binary);
+}
+
 void ARMCodeEmitter::emitBranchInstruction(const MachineInstr &MI) {
   const TargetInstrDesc &TID = MI.getDesc();
 
@@ -1594,16 +1659,28 @@ static unsigned convertNEONDataProcToThumb(unsigned Binary) {
   return 0xef000000 | (UBit << 28) | (Binary & 0xffffff);
 }
 
-void ARMCodeEmitter::emitNEONGetLaneInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitNEONLaneInstruction(const MachineInstr &MI) {
   unsigned Binary = getBinaryCodeForInstr(MI);
 
+  unsigned RegTOpIdx, RegNOpIdx, LnOpIdx;
+  const TargetInstrDesc &TID = MI.getDesc();
+  if ((TID.TSFlags & ARMII::FormMask) == ARMII::NGetLnFrm) {
+    RegTOpIdx = 0;
+    RegNOpIdx = 1;
+    LnOpIdx = 2;
+  } else { // ARMII::NSetLnFrm
+    RegTOpIdx = 2;
+    RegNOpIdx = 0;
+    LnOpIdx = 3;
+  }
+
   // Set the conditional execution predicate
-  Binary |= II->getPredicate(&MI) << ARMII::CondShift;
+  Binary |= (IsThumb ? ARMCC::AL : II->getPredicate(&MI)) << ARMII::CondShift;
 
-  unsigned RegT = MI.getOperand(0).getReg();
+  unsigned RegT = MI.getOperand(RegTOpIdx).getReg();
   RegT = ARMRegisterInfo::getRegisterNumbering(RegT);
   Binary |= (RegT << ARMII::RegRdShift);
-  Binary |= encodeNEONRn(MI, 1);
+  Binary |= encodeNEONRn(MI, RegNOpIdx);
 
   unsigned LaneShift;
   if ((Binary & (1 << 22)) != 0)
@@ -1613,7 +1690,7 @@ void ARMCodeEmitter::emitNEONGetLaneInstruction(const MachineInstr &MI) {
   else
     LaneShift = 2; // 32-bit elements
 
-  unsigned Lane = MI.getOperand(2).getImm() << LaneShift;
+  unsigned Lane = MI.getOperand(LnOpIdx).getImm() << LaneShift;
   unsigned Opc1 = Lane >> 2;
   unsigned Opc2 = Lane & 3;
   assert((Opc1 & 3) == 0 && "out-of-range lane number operand");
@@ -1623,6 +1700,19 @@ void ARMCodeEmitter::emitNEONGetLaneInstruction(const MachineInstr &MI) {
   emitWordLE(Binary);
 }
 
+void ARMCodeEmitter::emitNEONDupInstruction(const MachineInstr &MI) {
+  unsigned Binary = getBinaryCodeForInstr(MI);
+
+  // Set the conditional execution predicate
+  Binary |= (IsThumb ? ARMCC::AL : II->getPredicate(&MI)) << ARMII::CondShift;
+
+  unsigned RegT = MI.getOperand(1).getReg();
+  RegT = ARMRegisterInfo::getRegisterNumbering(RegT);
+  Binary |= (RegT << ARMII::RegRdShift);
+  Binary |= encodeNEONRn(MI, 0);
+  emitWordLE(Binary);
+}
+
 void ARMCodeEmitter::emitNEON1RegModImmInstruction(const MachineInstr &MI) {
   unsigned Binary = getBinaryCodeForInstr(MI);
   // Destination register is encoded in Dd.
@@ -1630,16 +1720,12 @@ void ARMCodeEmitter::emitNEON1RegModImmInstruction(const MachineInstr &MI) {
   // Immediate fields: Op, Cmode, I, Imm3, Imm4
   unsigned Imm = MI.getOperand(1).getImm();
   unsigned Op = (Imm >> 12) & 1;
-  Binary |= (Op << 5);
   unsigned Cmode = (Imm >> 8) & 0xf;
-  Binary |= (Cmode << 8);
   unsigned I = (Imm >> 7) & 1;
-  Binary |= (I << 24);
   unsigned Imm3 = (Imm >> 4) & 0x7;
-  Binary |= (Imm3 << 16);
   unsigned Imm4 = Imm & 0xf;
-  Binary |= Imm4;
-  if (Subtarget->isThumb())
+  Binary |= (I << 24) | (Imm3 << 16) | (Cmode << 8) | (Op << 5) | Imm4;
+  if (IsThumb)
     Binary = convertNEONDataProcToThumb(Binary);
   emitWordLE(Binary);
 }
@@ -1653,7 +1739,7 @@ void ARMCodeEmitter::emitNEON2RegInstruction(const MachineInstr &MI) {
   if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
     ++OpIdx;
   Binary |= encodeNEONRm(MI, OpIdx);
-  if (Subtarget->isThumb())
+  if (IsThumb)
     Binary = convertNEONDataProcToThumb(Binary);
   // FIXME: This does not handle VDUPfdf or VDUPfqf.
   emitWordLE(Binary);
@@ -1671,7 +1757,7 @@ void ARMCodeEmitter::emitNEON3RegInstruction(const MachineInstr &MI) {
   if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)
     ++OpIdx;
   Binary |= encodeNEONRm(MI, OpIdx);
-  if (Subtarget->isThumb())
+  if (IsThumb)
     Binary = convertNEONDataProcToThumb(Binary);
   // FIXME: This does not handle VMOVDneon or VMOVQ.
   emitWordLE(Binary);