Encode pic load / store instructions; fix some encoding bugs.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@58780 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp
index 193df98..ce62c59 100644
--- a/lib/Target/ARM/ARMCodeEmitter.cpp
+++ b/lib/Target/ARM/ARMCodeEmitter.cpp
@@ -65,8 +65,12 @@
 
   private:
 
+    void emitWordLE(unsigned Binary);
+
     void emitConstPoolInstruction(const MachineInstr &MI);
 
+    void addPCLabel(unsigned LabelID);
+
     void emitPseudoInstruction(const MachineInstr &MI);
 
     unsigned getMachineSoRegOpValue(const MachineInstr &MI,
@@ -81,11 +85,14 @@
     unsigned getAddrModeSBit(const MachineInstr &MI,
                              const TargetInstrDesc &TID) const;
 
-    void emitDataProcessingInstruction(const MachineInstr &MI);
+    void emitDataProcessingInstruction(const MachineInstr &MI,
+                                       unsigned ImplicitRn = 0);
 
-    void emitLoadStoreInstruction(const MachineInstr &MI);
+    void emitLoadStoreInstruction(const MachineInstr &MI,
+                                  unsigned ImplicitRn = 0);
 
-    void emitMiscLoadStoreInstruction(const MachineInstr &MI);
+    void emitMiscLoadStoreInstruction(const MachineInstr &MI,
+                                      unsigned ImplicitRn = 0);
 
     void emitLoadStoreMultipleInstruction(const MachineInstr &MI);
 
@@ -114,9 +121,9 @@
       return (TID.TSFlags & ARMII::OpcodeMask) >> ARMII::OpcodeShift;
     }
 
-    /// getShiftOp - Return the shift opcode (bit[6:5]) of the machine operand.
+    /// getShiftOp - Return the shift opcode (bit[6:5]) of the immediate value.
     ///
-    unsigned getShiftOp(const MachineOperand &MO) const ;
+    unsigned getShiftOp(unsigned Imm) const ;
 
     /// Routines that handle operands which add machine relocations which are
     /// fixed up by the JIT fixup stage.
@@ -165,10 +172,10 @@
   return false;
 }
 
-/// getShiftOp - Return the shift opcode (bit[6:5]) of the machine operand.
+/// getShiftOp - Return the shift opcode (bit[6:5]) of the immediate value.
 ///
-unsigned ARMCodeEmitter::getShiftOp(const MachineOperand &MO) const {
-  switch (ARM_AM::getAM2ShiftOpc(MO.getImm())) {
+unsigned ARMCodeEmitter::getShiftOp(unsigned Imm) const {
+  switch (ARM_AM::getAM2ShiftOpc(Imm)) {
   default: assert(0 && "Unknown shift opc!");
   case ARM_AM::asr: return 2;
   case ARM_AM::lsl: return 0;
@@ -246,6 +253,11 @@
                                              ARM::reloc_arm_branch, BB));
 }
 
+void ARMCodeEmitter::emitWordLE(unsigned Binary) {
+  DOUT << "\t" << (void*)Binary << "\n";
+  MCE.emitWordLE(Binary);
+}
+
 void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) {
   DOUT << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << MI;
 
@@ -312,7 +324,7 @@
       assert(!ACPV->isNonLazyPointer() && "Don't know how to deal this yet!");
       emitExternalSymbolAddress(ACPV->getSymbol(), ARM::reloc_arm_absolute);
     }
-    MCE.emitWordLE(0);
+    emitWordLE(0);
   } else {
     Constant *CV = MCPE.Val.ConstVal;
 
@@ -321,17 +333,23 @@
 
     if (GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
       emitGlobalAddress(GV, ARM::reloc_arm_absolute, false);
-      MCE.emitWordLE(0);
+      emitWordLE(0);
     } else {
       assert(CV->getType()->isInteger() &&
              "Not expecting non-integer constpool entries yet!");
       const ConstantInt *CI = dyn_cast<ConstantInt>(CV);
       uint32_t Val = *(uint32_t*)CI->getValue().getRawData();
-      MCE.emitWordLE(Val);
+      emitWordLE(Val);
     }
   }
 }
 
+void ARMCodeEmitter::addPCLabel(unsigned LabelID) {
+  DOUT << "\t** LPC" << LabelID << " @ "
+       << (void*)MCE.getCurrentPCValue() << '\n';
+  JTI->addPCLabelAddr(LabelID, MCE.getCurrentPCValue());
+}
+
 void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) {
   unsigned Opcode = MI.getDesc().Opcode;
   switch (Opcode) {
@@ -342,13 +360,29 @@
     break;
   case ARM::PICADD: {
     // Remember of the address of the PC label for relocation later.
-    const MachineOperand &MO2 = MI.getOperand(2);
-    DOUT << "\t** LPC" << MO2.getImm() << " @ "
-         << (void*)MCE.getCurrentPCValue() << '\n';
-    JTI->addPCLabelAddr(MO2.getImm(), MCE.getCurrentPCValue());
-
+    addPCLabel(MI.getOperand(2).getImm());
     // PICADD is just an add instruction that implicitly read pc.
-    emitDataProcessingInstruction(MI);
+    emitDataProcessingInstruction(MI, ARM::PC);
+    break;
+  }
+  case ARM::PICLDR:
+  case ARM::PICLDRB:
+  case ARM::PICSTR:
+  case ARM::PICSTRB: {
+    // Remember of the address of the PC label for relocation later.
+    addPCLabel(MI.getOperand(2).getImm());
+    // These are just load / store instructions that implicitly read pc.
+    emitLoadStoreInstruction(MI, ARM::PC);
+    break;
+  }
+  case ARM::PICLDRH:
+  case ARM::PICLDRSH:
+  case ARM::PICLDRSB:
+  case ARM::PICSTRH: {
+    // Remember of the address of the PC label for relocation later.
+    addPCLabel(MI.getOperand(2).getImm());
+    // These are just load / store instructions that implicitly read pc.
+    emitMiscLoadStoreInstruction(MI, ARM::PC);
     break;
   }
   }
@@ -434,7 +468,8 @@
   return 0;
 }
 
-void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI,
+                                                   unsigned ImplicitRn) {
   const TargetInstrDesc &TID = MI.getDesc();
   if (TID.getOpcode() == ARM::MOVi2pieces)
     abort(); // FIXME
@@ -459,9 +494,9 @@
   // Encode first non-shifter register operand if there is one.
   bool isUnary = TID.TSFlags & ARMII::UnaryDP;
   if (!isUnary) {
-    if (TID.getOpcode() == ARM::PICADD)
-      // Special handling for PICADD. It implicitly uses PC register.
-      Binary |= (ARMRegisterInfo::getRegisterNumbering(ARM::PC)
+    if (ImplicitRn)
+      // Special handling for implicit use (e.g. PC).
+      Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn)
                  << ARMII::RegRnShift);
     else {
       Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRnShift;
@@ -473,13 +508,13 @@
   const MachineOperand &MO = MI.getOperand(OpIdx);
   if ((TID.TSFlags & ARMII::FormMask) == ARMII::DPSoRegFrm) {
     // Encode SoReg.
-    MCE.emitWordLE(Binary | getMachineSoRegOpValue(MI, TID, MO, OpIdx));
+    emitWordLE(Binary | getMachineSoRegOpValue(MI, TID, MO, OpIdx));
     return;
   }
 
   if (MO.isReg()) {
     // Encode register Rm.
-    MCE.emitWordLE(Binary | ARMRegisterInfo::getRegisterNumbering(MO.getReg()));
+    emitWordLE(Binary | ARMRegisterInfo::getRegisterNumbering(MO.getReg()));
     return;
   }
 
@@ -488,10 +523,11 @@
   Binary |= 1 << ARMII::I_BitShift;
   Binary |= getMachineSoImmOpValue(MI, TID, MO);
 
-  MCE.emitWordLE(Binary);
+  emitWordLE(Binary);
 }
 
-void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI,
+                                              unsigned ImplicitRn) {
   const TargetInstrDesc &TID = MI.getDesc();
 
   // Part of binary is determined by TableGn.
@@ -504,19 +540,28 @@
   Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift;
 
   // Set second operand
-  Binary |= getMachineOpValue(MI, 1) << ARMII::RegRnShift;
+  unsigned OpIdx = 1;
+  if (ImplicitRn)
+    // Special handling for implicit use (e.g. PC).
+    Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn)
+               << ARMII::RegRnShift);
+  else {
+    Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRnShift;
+    ++OpIdx;
+  }
 
-  const MachineOperand &MO2 = MI.getOperand(2);
-  const MachineOperand &MO3 = MI.getOperand(3);
+  const MachineOperand &MO2 = MI.getOperand(OpIdx);
+  unsigned AM2Opc = (OpIdx == TID.getNumOperands())
+    ? 0 : MI.getOperand(OpIdx+1).getImm();
 
   // Set bit U(23) according to sign of immed value (positive or negative).
-  Binary |= ((ARM_AM::getAM2Op(MO3.getImm()) == ARM_AM::add ? 1 : 0) <<
+  Binary |= ((ARM_AM::getAM2Op(AM2Opc) == ARM_AM::add ? 1 : 0) <<
              ARMII::U_BitShift);
   if (!MO2.getReg()) { // is immediate
-    if (ARM_AM::getAM2Offset(MO3.getImm()))
+    if (ARM_AM::getAM2Offset(AM2Opc))
       // Set the value of offset_12 field
-      Binary |= ARM_AM::getAM2Offset(MO3.getImm());
-    MCE.emitWordLE(Binary);
+      Binary |= ARM_AM::getAM2Offset(AM2Opc);
+    emitWordLE(Binary);
     return;
   }
 
@@ -528,15 +573,16 @@
 
   // if this instr is in scaled register offset/index instruction, set
   // shift_immed(bit[11:7]) and shift(bit[6:5]) fields.
-  if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) {
-    Binary |= getShiftOp(MO3) << 5;  // shift
-    Binary |= ShImm           << 7;  // shift_immed
+  if (unsigned ShImm = ARM_AM::getAM2Offset(AM2Opc)) {
+    Binary |= getShiftOp(AM2Opc) << 5;  // shift
+    Binary |= ShImm              << 7;  // shift_immed
   }
 
-  MCE.emitWordLE(Binary);
+  emitWordLE(Binary);
 }
 
-void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI) {
+void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI,
+                                                  unsigned ImplicitRn) {
   const TargetInstrDesc &TID = MI.getDesc();
 
   // Part of binary is determined by TableGn.
@@ -549,37 +595,44 @@
   Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift;
 
   // Set second operand
-  Binary |= getMachineOpValue(MI, 1) << ARMII::RegRnShift;
+  unsigned OpIdx = 1;
+  if (ImplicitRn)
+    // Special handling for implicit use (e.g. PC).
+    Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn)
+               << ARMII::RegRnShift);
+  else {
+    Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRnShift;
+    ++OpIdx;
+  }
 
-  const MachineOperand &MO2 = MI.getOperand(2);
-  const MachineOperand &MO3 = MI.getOperand(3);
+  const MachineOperand &MO2 = MI.getOperand(OpIdx);
+  unsigned AM3Opc = (OpIdx == TID.getNumOperands())
+    ? 0 : MI.getOperand(OpIdx+1).getImm();
 
   // Set bit U(23) according to sign of immed value (positive or negative)
-  Binary |= ((ARM_AM::getAM2Op(MO3.getImm()) == ARM_AM::add ? 1 : 0) <<
+  Binary |= ((ARM_AM::getAM3Op(AM3Opc) == ARM_AM::add ? 1 : 0) <<
              ARMII::U_BitShift);
 
   // If this instr is in register offset/index encoding, set bit[3:0]
   // to the corresponding Rm register.
   if (MO2.getReg()) {
     Binary |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg());
-    MCE.emitWordLE(Binary);
+    emitWordLE(Binary);
     return;
   }
 
   // if this instr is in immediate offset/index encoding, set bit 22 to 1
-  if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) {
+  if (unsigned ImmOffs = ARM_AM::getAM3Offset(AM3Opc)) {
     Binary |= 1 << 22;
     // Set operands
     Binary |= (ImmOffs >> 4) << 8;  // immedH
     Binary |= (ImmOffs & ~0xF);     // immedL
   }
 
-  MCE.emitWordLE(Binary);
+  emitWordLE(Binary);
 }
 
 void ARMCodeEmitter::emitLoadStoreMultipleInstruction(const MachineInstr &MI) {
-  const TargetInstrDesc &TID = MI.getDesc();
-
   // Part of binary is determined by TableGn.
   unsigned Binary = getBinaryCodeForInstr(MI);
 
@@ -619,7 +672,7 @@
     Binary |= 0x1 << RegNum;
   }
 
-  MCE.emitWordLE(Binary);
+  emitWordLE(Binary);
 }
 
 void ARMCodeEmitter::emitMulFrm1Instruction(const MachineInstr &MI) {
@@ -649,7 +702,7 @@
   // Encode Rs
   Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRsShift;
 
-  MCE.emitWordLE(Binary);
+  emitWordLE(Binary);
 }
 
 void ARMCodeEmitter::emitBranchInstruction(const MachineInstr &MI) {
@@ -670,7 +723,7 @@
     Binary |= getMachineOpValue(MI, 1) << 28;  // set conditional field
   }
 
-  MCE.emitWordLE(Binary);
+  emitWordLE(Binary);
 }
 
 void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) {
@@ -691,7 +744,7 @@
     // otherwise, set the return register
     Binary |= getMachineOpValue(MI, 0);
 
-  MCE.emitWordLE(Binary);
+  emitWordLE(Binary);
 }
 
 #include "ARMGenCodeEmitter.inc"