another missed SSE optimization
[oota-llvm.git] / lib / Target / X86 / X86CodeEmitter.cpp
index 2b4328b1612a650e5eaf097ec9dc8c0e67742ff4..8b22634bd429d9159c90ae4b371f908de71e24b5 100644 (file)
@@ -12,6 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#define DEBUG_TYPE "x86-emitter"
 #include "X86InstrInfo.h"
 #include "X86Subtarget.h"
 #include "X86TargetMachine.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Target/TargetOptions.h"
-#include <iostream>
 using namespace llvm;
 
-namespace {
-  Statistic<>
-  NumEmitted("x86-emitter", "Number of machine instructions emitted");
-}
+STATISTIC(NumEmitted, "Number of machine instructions emitted");
 
 namespace {
   class VISIBILITY_HIDDEN Emitter : public MachineFunctionPass {
@@ -42,11 +39,14 @@ namespace {
     MachineCodeEmitter  &MCE;
     bool Is64BitMode;
   public:
+    static char ID;
     explicit Emitter(TargetMachine &tm, MachineCodeEmitter &mce)
-      : II(0), TD(0), TM(tm), MCE(mce), Is64BitMode(false) {}
+      : MachineFunctionPass((intptr_t)&ID), II(0), TD(0), TM(tm), 
+      MCE(mce), Is64BitMode(false) {}
     Emitter(TargetMachine &tm, MachineCodeEmitter &mce,
             const X86InstrInfo &ii, const TargetData &td, bool is64)
-      : II(&ii), TD(&td), TM(tm), MCE(mce), Is64BitMode(is64) {}
+      : MachineFunctionPass((intptr_t)&ID), II(&ii), TD(&td), TM(tm), 
+      MCE(mce), Is64BitMode(is64) {}
 
     bool runOnMachineFunction(MachineFunction &MF);
 
@@ -60,12 +60,12 @@ namespace {
     void emitPCRelativeBlockAddress(MachineBasicBlock *MBB);
     void emitPCRelativeValue(intptr_t Address);
     void emitGlobalAddressForCall(GlobalValue *GV, bool DoesntNeedStub);
-    void emitGlobalAddressForPtr(GlobalValue *GV, bool isPCRelative,
+    void emitGlobalAddressForPtr(GlobalValue *GV, unsigned Reloc,
                                  int Disp = 0, unsigned PCAdj = 0);
-    void emitExternalSymbolAddress(const char *ES, bool isPCRelative);
-    void emitPCRelativeConstPoolAddress(unsigned CPI, int Disp = 0,
-                                        unsigned PCAdj = 0);
-    void emitPCRelativeJumpTableAddress(unsigned JTI, unsigned PCAdj = 0);
+    void emitExternalSymbolAddress(const char *ES, unsigned Reloc);
+    void emitConstPoolAddress(unsigned CPI, unsigned Reloc, int Disp = 0,
+                              unsigned PCAdj = 0);
+    void emitJumpTableAddress(unsigned JTI, unsigned Reloc, unsigned PCAdj = 0);
 
     void emitDisplacementField(const MachineOperand *RelocOp, int DispVal,
                                unsigned PCAdj = 0);
@@ -82,6 +82,7 @@ namespace {
     bool isX86_64ExtendedReg(const MachineOperand &MO);
     unsigned determineREX(const MachineInstr &MI);
   };
+  char Emitter::ID = 0;
 }
 
 /// createX86CodeEmitterPass - Return a pass that emits the collected X86 code
@@ -145,41 +146,49 @@ void Emitter::emitGlobalAddressForCall(GlobalValue *GV, bool DoesntNeedStub) {
 /// emitGlobalAddress - Emit the specified address to the code stream assuming
 /// this is part of a "take the address of a global" instruction.
 ///
-void Emitter::emitGlobalAddressForPtr(GlobalValue *GV, bool isPCRelative,
+void Emitter::emitGlobalAddressForPtr(GlobalValue *GV, unsigned Reloc,
                                       int Disp /* = 0 */,
                                       unsigned PCAdj /* = 0 */) {
-  unsigned rt = isPCRelative ? X86::reloc_pcrel_word : X86::reloc_absolute_word;
-  MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), rt,
+  MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc,
                                              GV, PCAdj));
+  if (Reloc == X86::reloc_absolute_dword)
+    MCE.emitWordLE(0);
   MCE.emitWordLE(Disp); // The relocated value will be added to the displacement
 }
 
 /// emitExternalSymbolAddress - Arrange for the address of an external symbol to
 /// be emitted to the current location in the function, and allow it to be PC
 /// relative.
-void Emitter::emitExternalSymbolAddress(const char *ES, bool isPCRelative) {
+void Emitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) {
   MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(),
-          isPCRelative ? X86::reloc_pcrel_word : X86::reloc_absolute_word, ES));
+                                                 Reloc, ES));
+  if (Reloc == X86::reloc_absolute_dword)
+    MCE.emitWordLE(0);
   MCE.emitWordLE(0);
 }
 
-/// emitPCRelativeConstPoolAddress - Arrange for the address of an constant pool
+/// emitConstPoolAddress - Arrange for the address of an constant pool
 /// to be emitted to the current location in the function, and allow it to be PC
 /// relative.
-void Emitter::emitPCRelativeConstPoolAddress(unsigned CPI, int Disp /* = 0 */,
-                                             unsigned PCAdj /* = 0 */) {
+void Emitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc,
+                                   int Disp /* = 0 */,
+                                   unsigned PCAdj /* = 0 */) {
   MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(),
-                                            X86::reloc_pcrel_word, CPI, PCAdj));
+                                                    Reloc, CPI, PCAdj));
+  if (Reloc == X86::reloc_absolute_dword)
+    MCE.emitWordLE(0);
   MCE.emitWordLE(Disp); // The relocated value will be added to the displacement
 }
 
-/// emitPCRelativeJumpTableAddress - Arrange for the address of a jump table to
+/// emitJumpTableAddress - Arrange for the address of a jump table to
 /// be emitted to the current location in the function, and allow it to be PC
 /// relative.
-void Emitter::emitPCRelativeJumpTableAddress(unsigned JTI,
-                                             unsigned PCAdj /* = 0 */) {
+void Emitter::emitJumpTableAddress(unsigned JTI, unsigned Reloc,
+                                   unsigned PCAdj /* = 0 */) {
   MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(),
-                                            X86::reloc_pcrel_word, JTI, PCAdj));
+                                                    Reloc, JTI, PCAdj));
+  if (Reloc == X86::reloc_absolute_dword)
+    MCE.emitWordLE(0);
   MCE.emitWordLE(0); // The relocated value will be added to the displacement
 }
 
@@ -292,15 +301,17 @@ void Emitter::emitDisplacementField(const MachineOperand *RelocOp,
     // But it's probably not beneficial.
     //  89 05 00 00 00 00      mov    %eax,0(%rip)  # PC-relative
     // 89 04 25 00 00 00 00    mov    %eax,0x0      # Absolute
-    emitGlobalAddressForPtr(RelocOp->getGlobal(), Is64BitMode,
+    unsigned rt= Is64BitMode ? X86::reloc_pcrel_word : X86::reloc_absolute_word;
+    emitGlobalAddressForPtr(RelocOp->getGlobal(), rt,
                             RelocOp->getOffset(), PCAdj);
   } else if (RelocOp->isConstantPoolIndex()) {
     // Must be in 64-bit mode.
-    emitPCRelativeConstPoolAddress(RelocOp->getConstantPoolIndex(),
-                                   RelocOp->getOffset(), PCAdj);
+    emitConstPoolAddress(RelocOp->getConstantPoolIndex(), X86::reloc_pcrel_word,
+                         RelocOp->getOffset(), PCAdj);
   } else if (RelocOp->isJumpTableIndex()) {
     // Must be in 64-bit mode.
-    emitPCRelativeJumpTableAddress(RelocOp->getJumpTableIndex(), PCAdj);
+    emitJumpTableAddress(RelocOp->getJumpTableIndex(), X86::reloc_pcrel_word,
+                         PCAdj);
   } else {
     assert(0 && "Unknown value to relocate!");
   }
@@ -418,8 +429,8 @@ void Emitter::emitMemModRMByte(const MachineInstr &MI,
   }
 }
 
-static unsigned sizeOfImm(const TargetInstrDescriptor &Desc) {
-  switch (Desc.TSFlags & X86II::ImmMask) {
+static unsigned sizeOfImm(const TargetInstrDescriptor *Desc) {
+  switch (Desc->TSFlags & X86II::ImmMask) {
   case X86II::Imm8:   return 1;
   case X86II::Imm16:  return 2;
   case X86II::Imm32:  return 4;
@@ -460,19 +471,19 @@ inline static bool isX86_64NonExtLowByteReg(unsigned reg) {
 /// size, and 3) use of X86-64 extended registers.
 unsigned Emitter::determineREX(const MachineInstr &MI) {
   unsigned REX = 0;
-  unsigned Opcode = MI.getOpcode();
-  const TargetInstrDescriptor &Desc = II->get(Opcode);
+  const TargetInstrDescriptor *Desc = MI.getInstrDescriptor();
+  unsigned Opcode = Desc->Opcode;
 
   // Pseudo instructions do not need REX prefix byte.
-  if ((Desc.TSFlags & X86II::FormMask) == X86II::Pseudo)
+  if ((Desc->TSFlags & X86II::FormMask) == X86II::Pseudo)
     return 0;
-  if (Desc.TSFlags & X86II::REX_W)
+  if (Desc->TSFlags & X86II::REX_W)
     REX |= 1 << 3;
 
-  unsigned NumOps = II->getNumOperands(Opcode);
+  unsigned NumOps = Desc->numOperands;
   if (NumOps) {
     bool isTwoAddr = NumOps > 1 &&
-      II->getOperandConstraint(Opcode, 1, TargetInstrInfo::TIED_TO) != -1;
+      Desc->getOperandConstraint(1, TOI::TIED_TO) != -1;
 
     // If it accesses SPL, BPL, SIL, or DIL, then it requires a 0x40 REX prefix.
     bool isTrunc8 = isX86_64TruncToByte(Opcode);
@@ -480,17 +491,17 @@ unsigned Emitter::determineREX(const MachineInstr &MI) {
     for (unsigned e = NumOps; i != e; ++i) {
       const MachineOperand& MO = MI.getOperand(i);
       if (MO.isRegister()) {
-       unsigned Reg = MO.getReg();
-       // Trunc to byte are actually movb. The real source operand is the low
-       // byte of the register.
-       if (isTrunc8 && i == 1)
-         Reg = getX86SubSuperRegister(Reg, MVT::i8);
-       if (isX86_64NonExtLowByteReg(Reg))
-         REX |= 0x40;
+        unsigned Reg = MO.getReg();
+        // Trunc to byte are actually movb. The real source operand is the low
+        // byte of the register.
+        if (isTrunc8 && i == 1)
+          Reg = getX86SubSuperRegister(Reg, MVT::i8);
+        if (isX86_64NonExtLowByteReg(Reg))
+          REX |= 0x40;
       }
     }
 
-    switch (Desc.TSFlags & X86II::FormMask) {
+    switch (Desc->TSFlags & X86II::FormMask) {
     case X86II::MRMInitReg:
       if (isX86_64ExtendedReg(MI.getOperand(0)))
         REX |= (1 << 0) | (1 << 2);
@@ -560,23 +571,31 @@ unsigned Emitter::determineREX(const MachineInstr &MI) {
 void Emitter::emitInstruction(const MachineInstr &MI) {
   NumEmitted++;  // Keep track of the # of mi's emitted
 
-  unsigned Opcode = MI.getOpcode();
-  const TargetInstrDescriptor &Desc = II->get(Opcode);
+  const TargetInstrDescriptor *Desc = MI.getInstrDescriptor();
+  unsigned Opcode = Desc->Opcode;
 
   // Emit the repeat opcode prefix as needed.
-  if ((Desc.TSFlags & X86II::Op0Mask) == X86II::REP) MCE.emitByte(0xF3);
+  if ((Desc->TSFlags & X86II::Op0Mask) == X86II::REP) MCE.emitByte(0xF3);
 
   // Emit the operand size opcode prefix as needed.
-  if (Desc.TSFlags & X86II::OpSize) MCE.emitByte(0x66);
+  if (Desc->TSFlags & X86II::OpSize) MCE.emitByte(0x66);
 
   // Emit the address size opcode prefix as needed.
-  if (Desc.TSFlags & X86II::AdSize) MCE.emitByte(0x67);
+  if (Desc->TSFlags & X86II::AdSize) MCE.emitByte(0x67);
 
   bool Need0FPrefix = false;
-  switch (Desc.TSFlags & X86II::Op0Mask) {
+  switch (Desc->TSFlags & X86II::Op0Mask) {
   case X86II::TB:
     Need0FPrefix = true;   // Two-byte opcode prefix
     break;
+  case X86II::T8:
+    MCE.emitByte(0x0F);
+    MCE.emitByte(0x38);
+    break;
+  case X86II::TA:
+    MCE.emitByte(0x0F);
+    MCE.emitByte(0x3A);
+    break;
   case X86II::REP: break; // already handled.
   case X86II::XS:   // F3 0F
     MCE.emitByte(0xF3);
@@ -589,7 +608,7 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
   case X86II::D8: case X86II::D9: case X86II::DA: case X86II::DB:
   case X86II::DC: case X86II::DD: case X86II::DE: case X86II::DF:
     MCE.emitByte(0xD8+
-                 (((Desc.TSFlags & X86II::Op0Mask)-X86II::D8)
+                 (((Desc->TSFlags & X86II::Op0Mask)-X86II::D8)
                                    >> X86II::Op0Shift));
     break; // Two-byte opcode prefix
   default: assert(0 && "Invalid prefix!");
@@ -608,14 +627,13 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
     MCE.emitByte(0x0F);
 
   // If this is a two-address instruction, skip one of the register operands.
-  unsigned NumOps = II->getNumOperands(Opcode);
+  unsigned NumOps = Desc->numOperands;
   unsigned CurOp = 0;
-  if (NumOps > 1 &&
-      II->getOperandConstraint(Opcode, 1, TargetInstrInfo::TIED_TO) != -1)
+  if (NumOps > 1 && Desc->getOperandConstraint(1, TOI::TIED_TO) != -1)
     CurOp++;
-  
-  unsigned char BaseOpcode = II->getBaseOpcodeFor(Opcode);
-  switch (Desc.TSFlags & X86II::FormMask) {
+
+  unsigned char BaseOpcode = II->getBaseOpcodeFor(Desc);
+  switch (Desc->TSFlags & X86II::FormMask) {
   default: assert(0 && "Unknown FormMask value in X86 MachineCodeEmitter!");
   case X86II::Pseudo:
 #ifndef NDEBUG
@@ -623,8 +641,9 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
     default: 
       assert(0 && "psuedo instructions should be removed before code emission");
     case TargetInstrInfo::INLINEASM:
-      std::cerr << "JIT does not support inline asm!\n";
-      abort();
+      assert(0 && "JIT does not support inline asm!\n");
+    case TargetInstrInfo::LABEL:
+      assert(0 && "JIT does not support meta labels!\n");
     case X86::IMPLICIT_USE:
     case X86::IMPLICIT_DEF:
     case X86::IMPLICIT_DEF_GR8:
@@ -649,11 +668,12 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
       if (MO.isMachineBasicBlock()) {
         emitPCRelativeBlockAddress(MO.getMachineBasicBlock());
       } else if (MO.isGlobalAddress()) {
-        bool isTailCall = Opcode == X86::TAILJMPd ||
-                          Opcode == X86::TAILJMPr || Opcode == X86::TAILJMPm;
-        emitGlobalAddressForCall(MO.getGlobal(), !isTailCall);
+        bool NeedStub = Is64BitMode ||
+                        Opcode == X86::TAILJMPd ||
+                        Opcode == X86::TAILJMPr || Opcode == X86::TAILJMPm;
+        emitGlobalAddressForCall(MO.getGlobal(), !NeedStub);
       } else if (MO.isExternalSymbol()) {
-        emitExternalSymbolAddress(MO.getSymbolName(), true);
+        emitExternalSymbolAddress(MO.getSymbolName(), X86::reloc_pcrel_word);
       } else if (MO.isImmediate()) {
         emitConstant(MO.getImm(), sizeOfImm(Desc));
       } else {
@@ -667,20 +687,21 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
     
     if (CurOp != NumOps) {
       const MachineOperand &MO1 = MI.getOperand(CurOp++);
-      if (MO1.isGlobalAddress()) {
-        assert(sizeOfImm(Desc) == TD->getPointerSize() &&
-               "Don't know how to emit non-pointer values!");
-        emitGlobalAddressForPtr(MO1.getGlobal(), Is64BitMode, MO1.getOffset());
-      } else if (MO1.isExternalSymbol()) {
-        assert(sizeOfImm(Desc) == TD->getPointerSize() &&
-               "Don't know how to emit non-pointer values!");
-        emitExternalSymbolAddress(MO1.getSymbolName(), false);
-      } else if (MO1.isJumpTableIndex()) {
-        assert(sizeOfImm(Desc) == TD->getPointerSize() &&
-               "Don't know how to emit non-pointer values!");
-        emitConstant(MCE.getJumpTableEntryAddress(MO1.getJumpTableIndex()), 4);
-      } else {
-        emitConstant(MO1.getImm(), sizeOfImm(Desc));
+      unsigned Size = sizeOfImm(Desc);
+      if (MO1.isImmediate())
+        emitConstant(MO1.getImm(), Size);
+      else {
+        unsigned rt = Is64BitMode ? X86::reloc_pcrel_word : X86::reloc_absolute_word;
+        if (Opcode == X86::MOV64ri)
+          rt = X86::reloc_absolute_dword;  // FIXME: add X86II flag?
+        if (MO1.isGlobalAddress())
+          emitGlobalAddressForPtr(MO1.getGlobal(), rt, MO1.getOffset());
+        else if (MO1.isExternalSymbol())
+          emitExternalSymbolAddress(MO1.getSymbolName(), rt);
+        else if (MO1.isConstantPoolIndex())
+          emitConstPoolAddress(MO1.getConstantPoolIndex(), rt);
+        else if (MO1.isJumpTableIndex())
+          emitJumpTableAddress(MO1.getJumpTableIndex(), rt);
       }
     }
     break;
@@ -730,10 +751,28 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
   case X86II::MRM6r: case X86II::MRM7r:
     MCE.emitByte(BaseOpcode);
     emitRegModRMByte(MI.getOperand(CurOp++).getReg(),
-                     (Desc.TSFlags & X86II::FormMask)-X86II::MRM0r);
+                     (Desc->TSFlags & X86II::FormMask)-X86II::MRM0r);
 
-    if (CurOp != NumOps && MI.getOperand(CurOp).isImmediate())
-      emitConstant(MI.getOperand(CurOp++).getImm(), sizeOfImm(Desc));
+    if (CurOp != NumOps) {
+      const MachineOperand &MO1 = MI.getOperand(CurOp++);
+      unsigned Size = sizeOfImm(Desc);
+      if (MO1.isImmediate())
+        emitConstant(MO1.getImm(), Size);
+      else {
+        unsigned rt = Is64BitMode ? X86::reloc_pcrel_word
+          : X86::reloc_absolute_word;
+        if (Opcode == X86::MOV64ri32)
+          rt = X86::reloc_absolute_word;  // FIXME: add X86II flag?
+        if (MO1.isGlobalAddress())
+          emitGlobalAddressForPtr(MO1.getGlobal(), rt, MO1.getOffset());
+        else if (MO1.isExternalSymbol())
+          emitExternalSymbolAddress(MO1.getSymbolName(), rt);
+        else if (MO1.isConstantPoolIndex())
+          emitConstPoolAddress(MO1.getConstantPoolIndex(), rt);
+        else if (MO1.isJumpTableIndex())
+          emitJumpTableAddress(MO1.getJumpTableIndex(), rt);
+      }
+    }
     break;
 
   case X86II::MRM0m: case X86II::MRM1m:
@@ -744,20 +783,29 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
       (MI.getOperand(CurOp+4).isImmediate() ? sizeOfImm(Desc) : 4) : 0;
 
     MCE.emitByte(BaseOpcode);
-    emitMemModRMByte(MI, CurOp, (Desc.TSFlags & X86II::FormMask)-X86II::MRM0m,
+    emitMemModRMByte(MI, CurOp, (Desc->TSFlags & X86II::FormMask)-X86II::MRM0m,
                      PCAdj);
     CurOp += 4;
 
     if (CurOp != NumOps) {
       const MachineOperand &MO = MI.getOperand(CurOp++);
+      unsigned Size = sizeOfImm(Desc);
       if (MO.isImmediate())
-        emitConstant(MO.getImm(), sizeOfImm(Desc));
-      else if (MO.isGlobalAddress())
-        emitGlobalAddressForPtr(MO.getGlobal(), Is64BitMode, MO.getOffset());
-      else if (MO.isJumpTableIndex())
-        emitConstant(MCE.getJumpTableEntryAddress(MO.getJumpTableIndex()), 4);
-      else
-        assert(0 && "Unknown operand!");
+        emitConstant(MO.getImm(), Size);
+      else {
+        unsigned rt = Is64BitMode ? X86::reloc_pcrel_word
+          : X86::reloc_absolute_word;
+        if (Opcode == X86::MOV64mi32)
+          rt = X86::reloc_absolute_word;  // FIXME: add X86II flag?
+        if (MO.isGlobalAddress())
+          emitGlobalAddressForPtr(MO.getGlobal(), rt, MO.getOffset());
+        else if (MO.isExternalSymbol())
+          emitExternalSymbolAddress(MO.getSymbolName(), rt);
+        else if (MO.isConstantPoolIndex())
+          emitConstPoolAddress(MO.getConstantPoolIndex(), rt);
+        else if (MO.isJumpTableIndex())
+          emitJumpTableAddress(MO.getJumpTableIndex(), rt);
+      }
     }
     break;
   }
@@ -771,6 +819,6 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
     break;
   }
 
-  assert((Desc.Flags & M_VARIABLE_OPS) != 0 ||
+  assert((Desc->Flags & M_VARIABLE_OPS) != 0 ||
          CurOp == NumOps && "Unknown encoding!");
 }