Implement a lot of cast functionality (no FP or 64)
[oota-llvm.git] / lib / Target / X86 / InstSelectSimple.cpp
index b646ed3644253c34b9973ca9d46128bd51a0b38e..217b219ba2a4ae47e6d7f5420d61147a06a5a9af 100644 (file)
@@ -138,8 +138,8 @@ namespace {
       } else if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
         // Move the address of the global into the register
         BuildMI(BB, X86::MOVir32, 1, Reg).addReg(GV);
-      } else {
-        assert(0 && "Don't know how to handle a value of this type!");
+      } else if (Argument *A = dyn_cast<Argument>(V)) {
+        std::cerr << "ERROR: Arguments not implemented in SimpleInstSel\n";
       }
 
       return Reg;
@@ -393,6 +393,9 @@ ISel::visitBranchInst (BranchInst & BI)
 void
 ISel::visitCallInst (CallInst & CI)
 {
+  // keep a counter of how many bytes we pushed on the stack
+  unsigned bytesPushed = 0;
+
   // Push the arguments on the stack in reverse order, as specified by
   // the ABI.
   for (unsigned i = CI.getNumOperands()-1; i >= 1; --i)
@@ -406,11 +409,13 @@ ISel::visitCallInst (CallInst & CI)
          // then push EAX.
          promote32 (X86::EAX, v);
          BuildMI (BB, X86::PUSHr32, 1).addReg (X86::EAX);
+          bytesPushed += 4;
          break;
        case cInt:
        case cFloat: {
           unsigned Reg = getReg(v);
           BuildMI (BB, X86::PUSHr32, 1).addReg(Reg);
+          bytesPushed += 4;
          break;
         }
        default:
@@ -421,6 +426,26 @@ ISel::visitCallInst (CallInst & CI)
     }
   // Emit a CALL instruction with PC-relative displacement.
   BuildMI (BB, X86::CALLpcrel32, 1).addPCDisp (CI.getCalledValue ());
+
+  // Adjust the stack by `bytesPushed' amount if non-zero
+  if (bytesPushed > 0)
+    BuildMI (BB, X86::ADDri32, 2).addReg(X86::ESP).addZImm(bytesPushed);
+
+  // If there is a return value, scavenge the result from the location the call
+  // leaves it in...
+  //
+  if (CI.getType() != Type::VoidTy) {
+    switch (getClass(CI.getType())) {
+    case cInt:
+      BuildMI(BB, X86::MOVrr32, 1, getReg(CI)).addReg(X86::EAX);
+      break;
+      
+    default:
+      std::cerr << "Cannot get return value for call of type '"
+                << *CI.getType() << "'\n";
+      visitInstruction(CI);
+    }
+  }
 }
 
 /// visitSimpleBinary - Implement simple binary operators for integral types...
@@ -640,45 +665,73 @@ void ISel::visitPHINode(PHINode &PN) {
 void
 ISel::visitCastInst (CastInst &CI)
 {
-//> cast larger int to smaller int -->  copy least significant byte/word w/ mov?
-//
-//I'm not really sure what to do with this.  We could insert a pseudo-op
-//that says take the low X bits of a Y bit register, but for now we can just
-//force the value into, say, EAX, then rip out AL or AX.  The advantage of  
-//the former is that the register allocator could use any register it wants,
-//but for now this obviously doesn't matter.  :)
-
   const Type *targetType = CI.getType ();
   Value *operand = CI.getOperand (0);
   unsigned int operandReg = getReg (operand);
   const Type *sourceType = operand->getType ();
   unsigned int destReg = getReg (CI);
-
-  // cast to bool:
-  if (targetType == Type::BoolTy) {
-    // Emit Compare
-    BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0);
-    // Emit Set-if-not-zero
-    BuildMI (BB, X86::SETNEr, 1, destReg);
-    return;
-  }
-
-// if size of target type == size of source type
-// Emit Mov reg(target) <- reg(source)
-
-// if size of target type > size of source type
-//     if both types are integer types
-//             if source type is signed
-//                 sbyte to short, ushort: Emit movsx 8->16
-//                 sbyte to int, uint:     Emit movsx 8->32
-//                 short to int, uint:     Emit movsx 16->32
-//             else if source type is unsigned
-//                 ubyte to short, ushort: Emit movzx 8->16
-//                 ubyte to int, uint:     Emit movzx 8->32
-//                 ushort to int, uint:    Emit movzx 16->32
-//     if both types are fp types
-//             float to double: Emit fstp, fld (???)
-
+  //
+  // Currently we handle:
+  //
+  // 1) cast * to bool
+  //
+  // 2) cast {sbyte, ubyte} to {sbyte, ubyte}
+  //    cast {short, ushort} to {ushort, short}
+  //    cast {int, uint, ptr} to {int, uint, ptr}
+  //
+  // 3) cast {sbyte, ubyte} to {ushort, short}
+  //    cast {sbyte, ubyte} to {int, uint, ptr}
+  //    cast {short, ushort} to {int, uint, ptr}
+  //
+  // 4) cast {int, uint, ptr} to {short, ushort}
+  //    cast {int, uint, ptr} to {sbyte, ubyte}
+  //    cast {short, ushort} to {sbyte, ubyte}
+  //
+  // 1) Implement casts to bool by using compare on the operand followed
+  // by set if not zero on the result.
+  if (targetType == Type::BoolTy)
+    {
+      BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0);
+      BuildMI (BB, X86::SETNEr, 1, destReg);
+      return;
+    }
+  // 2) Implement casts between values of the same type class (as determined
+  // by getClass) by using a register-to-register move.
+  unsigned int srcClass = getClass (sourceType);
+  unsigned int targClass = getClass (targetType);
+  static const unsigned regRegMove[] = {
+    X86::MOVrr8, X86::MOVrr16, X86::MOVrr32
+  };
+  if ((srcClass < 3) && (targClass < 3) && (srcClass == targClass))
+    {
+      BuildMI (BB, regRegMove[srcClass], 1, destReg).addReg (operandReg);
+      return;
+    }
+  // 3) Handle cast of SMALLER int to LARGER int using a move with sign
+  // extension or zero extension, depending on whether the source type
+  // was signed.
+  if ((srcClass < 3) && (targClass < 3) && (srcClass < targClass))
+    {
+      static const unsigned ops[] = {
+       X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16,
+       X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16
+      };
+      unsigned srcSigned = sourceType->isSigned ();
+      BuildMI (BB, ops[3 * srcSigned + srcClass + targClass - 1], 1,
+              destReg).addReg (operandReg);
+      return;
+    }
+  // 4) Handle cast of LARGER int to SMALLER int using a move to EAX
+  // followed by a move out of AX or AL.
+  if ((srcClass < 3) && (targClass < 3) && (srcClass > targClass))
+    {
+      static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX };
+      BuildMI (BB, regRegMove[srcClass], 1,
+              AReg[srcClass]).addReg (operandReg);
+      BuildMI (BB, regRegMove[targClass], 1, destReg).addReg (AReg[srcClass]);
+      return;
+    }
+  // Anything we haven't handled already, we can't (yet) handle at all.
   visitInstruction (CI);
 }