Add support for copying bool constants to registers.
[oota-llvm.git] / lib / Target / SparcV8 / InstSelectSimple.cpp
index 8ae5a0c27cff462ae9df9ce719b1b496291e21a6..6152c4fff7068d2cca7b63dc5de620a7788c6089 100644 (file)
@@ -57,9 +57,14 @@ namespace {
       BB = MBBMap[&LLVM_BB];
     }
 
-       void visitBinaryOperator(BinaryOperator &I);
-       void visitCallInst(CallInst &I);
-       void visitReturnInst(ReturnInst &RI);
+    void visitBinaryOperator(Instruction &I);
+    void visitShiftInstruction(Instruction &I) { visitBinaryOperator(I); }
+    void visitSetCondInst(Instruction &I);
+    void visitCallInst(CallInst &I);
+    void visitReturnInst(ReturnInst &I);
+    void visitCastInst(CastInst &I);
+    void visitLoadInst(LoadInst &I);
+    void visitStoreInst(StoreInst &I);
 
     void visitInstruction(Instruction &I) {
       std::cerr << "Unhandled instruction: " << I;
@@ -72,6 +77,8 @@ namespace {
     void LowerUnknownIntrinsicFunctionCalls(Function &F);
     void visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI);
 
+    void LoadArgumentsToVirtualRegs(Function *F);
+
     /// copyConstantToRegister - Output the instructions required to put the
     /// specified constant into the specified register.
     ///
@@ -151,6 +158,7 @@ static TypeClass getClass (const Type *T) {
   switch (T->getPrimitiveID ()) {
     case Type::UByteTyID:  case Type::SByteTyID:  return cByte;
     case Type::UShortTyID: case Type::ShortTyID:  return cShort;
+    case Type::PointerTyID:
     case Type::UIntTyID:   case Type::IntTyID:    return cInt;
     case Type::ULongTyID:  case Type::LongTyID:   return cLong;
     case Type::FloatTyID:                         return cFloat;
@@ -160,6 +168,12 @@ static TypeClass getClass (const Type *T) {
       return cByte;
   }
 }
+static TypeClass getClassB(const Type *T) {
+  if (T == Type::BoolTy) return cByte;
+  return getClass(T);
+}
+
+
 
 /// copyConstantToRegister - Output the instructions required to put the
 /// specified constant into the specified register.
@@ -167,33 +181,85 @@ static TypeClass getClass (const Type *T) {
 void V8ISel::copyConstantToRegister(MachineBasicBlock *MBB,
                                     MachineBasicBlock::iterator IP,
                                     Constant *C, unsigned R) {
-  if (ConstantInt *CI = dyn_cast<ConstantInt> (C)) {
-    unsigned Class = getClass(C->getType());
-    switch (Class) {
+  if (C->getType()->isIntegral ()) {
+    uint64_t Val;
+    if (C->getType() == Type::BoolTy) {
+      Val = (C == ConstantBool::True);
+    } else {
+      ConstantInt *CI = dyn_cast<ConstantInt> (C);
+      Val = CI->getRawValue ();
+    }
+    switch (getClassB (C->getType ())) {
       case cByte:
-        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (V8::G0).addImm ((uint8_t) CI->getRawValue ());
+        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (V8::G0).addImm((uint8_t)Val);
         return;
       case cShort: {
         unsigned TmpReg = makeAnotherReg (C->getType ());
-        BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg).addImm (((uint16_t) CI->getRawValue ()) >> 10);
-        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg).addImm (((uint16_t) CI->getRawValue ()) & 0x03ff);
+        BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg)
+          .addImm (((uint16_t) Val) >> 10);
+        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg)
+          .addImm (((uint16_t) Val) & 0x03ff);
         return;
       }
       case cInt: {
         unsigned TmpReg = makeAnotherReg (C->getType ());
-        BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg).addImm (((uint32_t) CI->getRawValue ()) >> 10);
-        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg).addImm (((uint32_t) CI->getRawValue ()) & 0x03ff);
+        BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg).addImm(((uint32_t)Val) >> 10);
+        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg)
+          .addImm (((uint32_t) Val) & 0x03ff);
+        return;
+      }
+      case cLong: {
+        unsigned TmpReg = makeAnotherReg (Type::UIntTy);
+        uint32_t topHalf = (uint32_t) (Val >> 32);
+        uint32_t bottomHalf = (uint32_t)Val;
+#if 0 // FIXME: This does not appear to be correct; it assigns SSA reg R twice.
+        BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg).addImm (topHalf >> 10);
+        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg)
+          .addImm (topHalf & 0x03ff);
+        BuildMI (*MBB, IP, V8::SETHIi, 1, TmpReg).addImm (bottomHalf >> 10);
+        BuildMI (*MBB, IP, V8::ORri, 2, R).addReg (TmpReg)
+          .addImm (bottomHalf & 0x03ff);
+#else
+        std::cerr << "Offending constant: " << *C << "\n";
+        assert (0 && "Can't copy this kind of constant into register yet");
+#endif
         return;
       }
       default:
+        std::cerr << "Offending constant: " << *C << "\n";
         assert (0 && "Can't copy this kind of constant into register yet");
         return;
     }
   }
 
+  std::cerr << "Offending constant: " << *C << "\n";
   assert (0 && "Can't copy this kind of constant into register yet");
 }
 
+void V8ISel::LoadArgumentsToVirtualRegs (Function *F) {
+  unsigned ArgOffset = 0;
+  static const unsigned IncomingArgRegs[] = { V8::I0, V8::I1, V8::I2,
+    V8::I3, V8::I4, V8::I5 };
+  assert (F->asize () < 7
+          && "Can't handle loading excess call args off the stack yet");
+
+  for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I) {
+    unsigned Reg = getReg(*I);
+    switch (getClassB(I->getType())) {
+    case cByte:
+    case cShort:
+    case cInt:
+      BuildMI(BB, V8::ORrr, 2, Reg).addReg (V8::G0)
+        .addReg (IncomingArgRegs[ArgOffset]);
+      break;
+    default:
+      assert (0 && "Only <=32-bit, integral arguments currently handled");
+      return;
+    }
+    ++ArgOffset;
+  }
+}
+
 bool V8ISel::runOnFunction(Function &Fn) {
   // First pass over the function, lower any unknown intrinsic functions
   // with the IntrinsicLowering class.
@@ -212,7 +278,7 @@ bool V8ISel::runOnFunction(Function &Fn) {
   //ReturnAddressIndex = F->getFrameInfo()->CreateFixedObject(4, -4);
   
   // Copy incoming arguments off of the stack and out of fixed registers.
-  //LoadArgumentsToVirtualRegs(Fn);
+  LoadArgumentsToVirtualRegs(&Fn);
   
   // Instruction select everything except PHI nodes
   visit(Fn);
@@ -227,8 +293,83 @@ bool V8ISel::runOnFunction(Function &Fn) {
   return true;
 }
 
+void V8ISel::visitCastInst(CastInst &I) {
+  unsigned SrcReg = getReg (I.getOperand (0));
+  unsigned DestReg = getReg (I);
+  const Type *oldTy = I.getOperand (0)->getType ();
+  const Type *newTy = I.getType ();
+  unsigned oldTyClass = getClassB (oldTy);
+  unsigned newTyClass = getClassB (newTy);
+
+  if (oldTyClass < cLong && newTyClass < cLong && oldTyClass >= newTyClass) {
+    // Emit a reg->reg copy to do a equal-size or non-narrowing cast,
+    // and do sign/zero extension (necessary if we change signedness).
+    unsigned TempReg1 = makeAnotherReg (newTy);
+    unsigned TempReg2 = makeAnotherReg (newTy);
+    BuildMI (BB, V8::ORrr, 2, TempReg1).addReg (V8::G0).addReg (SrcReg);
+    unsigned shiftWidth = 32 - (8 * TM.getTargetData ().getTypeSize (newTy));
+    BuildMI (BB, V8::SLLri, 2, TempReg2).addZImm (shiftWidth).addReg (TempReg1);
+    if (newTy->isSigned ()) { // sign-extend with SRA
+      BuildMI(BB, V8::SRAri, 2, DestReg).addZImm (shiftWidth).addReg (TempReg2);
+    } else { // zero-extend with SRL
+      BuildMI(BB, V8::SRLri, 2, DestReg).addZImm (shiftWidth).addReg (TempReg2);
+    }
+  } else {
+    std::cerr << "Casts w/ long, fp, double, or widening still unsupported: "
+              << I;
+    abort ();
+  }
+}
+
+void V8ISel::visitLoadInst(LoadInst &I) {
+  unsigned DestReg = getReg (I);
+  unsigned PtrReg = getReg (I.getOperand (0));
+  switch (getClass (I.getType ())) {
+   case cByte:
+    if (I.getType ()->isSigned ())
+      BuildMI (BB, V8::LDSBmr, 1, DestReg).addReg (PtrReg).addSImm(0);
+    else
+      BuildMI (BB, V8::LDUBmr, 1, DestReg).addReg (PtrReg).addSImm(0);
+    return;
+   case cShort:
+    if (I.getType ()->isSigned ())
+      BuildMI (BB, V8::LDSHmr, 1, DestReg).addReg (PtrReg).addSImm(0);
+    else
+      BuildMI (BB, V8::LDUHmr, 1, DestReg).addReg (PtrReg).addSImm(0);
+    return;
+   case cInt:
+    BuildMI (BB, V8::LDmr, 1, DestReg).addReg (PtrReg).addSImm(0);
+    return;
+   case cLong:
+    BuildMI (BB, V8::LDDmr, 1, DestReg).addReg (PtrReg).addSImm(0);
+    return;
+   default:
+    std::cerr << "Load instruction not handled: " << I;
+    abort ();
+    return;
+  }
+}
+
+void V8ISel::visitStoreInst(StoreInst &I) {
+  unsigned SrcReg = getReg (I.getOperand (0));
+  unsigned PtrReg = getReg (I.getOperand (1));
+  std::cerr << "Store instruction not handled: " << I;
+  abort ();
+}
+
 void V8ISel::visitCallInst(CallInst &I) {
-  assert (I.getNumOperands () == 1 && "Can't handle call args yet");
+  assert (I.getNumOperands () < 8
+          && "Can't handle pushing excess call args on the stack yet");
+  static const unsigned OutgoingArgRegs[] = { V8::O0, V8::O1, V8::O2, V8::O3,
+    V8::O4, V8::O5 };
+  for (unsigned i = 1; i < 7; ++i)
+    if (i < I.getNumOperands ()) {
+      unsigned ArgReg = getReg (I.getOperand (i));
+      // Schlep it over into the incoming arg register
+      BuildMI (BB, V8::ORrr, 2, OutgoingArgRegs[i - 1]).addReg (V8::G0)
+        .addReg (ArgReg);
+    }
+
   unsigned DestReg = getReg (I);
   BuildMI (BB, V8::CALL, 1).addPCDisp (I.getOperand (0));
   if (I.getType ()->getPrimitiveID () == Type::VoidTyID)
@@ -261,35 +402,71 @@ void V8ISel::visitReturnInst(ReturnInst &I) {
         visitInstruction (I);
         return;
     }
-  } else if (I.getNumOperands () != 1) {
-    visitInstruction (I);
   }
+
   // Just emit a 'retl' instruction to return.
   BuildMI(BB, V8::RETL, 0);
   return;
 }
 
-void V8ISel::visitBinaryOperator (BinaryOperator &I) {
+void V8ISel::visitBinaryOperator (Instruction &I) {
   unsigned DestReg = getReg (I);
   unsigned Op0Reg = getReg (I.getOperand (0));
   unsigned Op1Reg = getReg (I.getOperand (1));
 
-  unsigned ResultReg = makeAnotherReg (I.getType ());
+  unsigned ResultReg = DestReg;
+  if (getClassB(I.getType()) != cInt)
+    ResultReg = makeAnotherReg (I.getType ());
+  unsigned OpCase = ~0;
+
+  // FIXME: support long, ulong, fp.
   switch (I.getOpcode ()) {
-    case Instruction::Add: 
-      BuildMI (BB, V8::ADDrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
-      break;
-    case Instruction::Sub: 
-      BuildMI (BB, V8::SUBrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
-      break;
-    case Instruction::Mul: {
-      unsigned MulOpcode = I.getType ()->isSigned () ? V8::SMULrr : V8::UMULrr;
-      BuildMI (BB, MulOpcode, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
-      break;
+  case Instruction::Add: OpCase = 0; break;
+  case Instruction::Sub: OpCase = 1; break;
+  case Instruction::Mul: OpCase = 2; break;
+  case Instruction::And: OpCase = 3; break;
+  case Instruction::Or:  OpCase = 4; break;
+  case Instruction::Xor: OpCase = 5; break;
+  case Instruction::Shl: OpCase = 6; break;
+  case Instruction::Shr: OpCase = 7+I.getType()->isSigned(); break;
+
+  case Instruction::Div:
+  case Instruction::Rem: {
+    unsigned Dest = ResultReg;
+    if (I.getOpcode() == Instruction::Rem)
+      Dest = makeAnotherReg(I.getType());
+
+    // FIXME: this is probably only right for 32 bit operands.
+    if (I.getType ()->isSigned()) {
+      unsigned Tmp = makeAnotherReg (I.getType ());
+      // Sign extend into the Y register
+      BuildMI (BB, V8::SRAri, 2, Tmp).addReg (Op0Reg).addZImm (31);
+      BuildMI (BB, V8::WRrr, 2, V8::Y).addReg (Tmp).addReg (V8::G0);
+      BuildMI (BB, V8::SDIVrr, 2, Dest).addReg (Op0Reg).addReg (Op1Reg);
+    } else {
+      // Zero extend into the Y register, ie, just set it to zero
+      BuildMI (BB, V8::WRrr, 2, V8::Y).addReg (V8::G0).addReg (V8::G0);
+      BuildMI (BB, V8::UDIVrr, 2, Dest).addReg (Op0Reg).addReg (Op1Reg);
     }
-    default:
-      visitInstruction (I);
-      return;
+
+    if (I.getOpcode() == Instruction::Rem) {
+      unsigned Tmp = makeAnotherReg (I.getType ());
+      BuildMI (BB, V8::SMULrr, 2, Tmp).addReg(Dest).addReg(Op1Reg);
+      BuildMI (BB, V8::SUBrr, 2, ResultReg).addReg(Op0Reg).addReg(Tmp);
+    }
+    break;
+  }
+  default:
+    visitInstruction (I);
+    return;
+  }
+
+  if (OpCase != ~0U) {
+    static const unsigned Opcodes[] = {
+      V8::ADDrr, V8::SUBrr, V8::SMULrr, V8::ANDrr, V8::ORrr, V8::XORrr,
+      V8::SLLrr, V8::SRLrr, V8::SRArr
+    };
+    BuildMI (BB, Opcodes[OpCase], 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
   }
 
   switch (getClass (I.getType ())) {
@@ -314,7 +491,7 @@ void V8ISel::visitBinaryOperator (BinaryOperator &I) {
       }
       break;
     case cInt:
-      BuildMI (BB, V8::ORrr, 2, DestReg).addReg (V8::G0).addReg (ResultReg);
+      // Nothing todo here.
       break;
     default:
       visitInstruction (I);
@@ -322,6 +499,41 @@ void V8ISel::visitBinaryOperator (BinaryOperator &I) {
   }
 }
 
+void V8ISel::visitSetCondInst(Instruction &I) {
+  unsigned Op0Reg = getReg (I.getOperand (0));
+  unsigned Op1Reg = getReg (I.getOperand (1));
+  unsigned DestReg = getReg (I);
+  
+  // Compare the two values.
+  BuildMI(BB, V8::SUBCCrr, 2, V8::G0).addReg(Op0Reg).addReg(Op1Reg);
+
+  // Put 0 into a register.
+  //unsigned ZeroReg = makeAnotheRReg(Type::IntTy);
+  //BuildMI(BB, V8::ORri, 2, ZeroReg).addReg(V8::G0).addReg(V8::G0);
+
+  unsigned Opcode;
+  switch (I.getOpcode()) {
+  default: assert(0 && "Unknown setcc instruction!");
+  case Instruction::SetEQ:
+  case Instruction::SetNE:
+  case Instruction::SetLT:
+  case Instruction::SetGT:
+  case Instruction::SetLE:
+  case Instruction::SetGE:
+    ;
+  }
+
+  // FIXME: We need either conditional moves like the V9 has (e.g. movge), or we
+  // need to be able to turn a single LLVM basic block into multiple machine
+  // code basic blocks.  For now, it probably makes sense to emit Sparc V9
+  // instructions until the code generator is upgraded.  Note that this should
+  // only happen when the setcc cannot be folded into the branch, but this needs
+  // to be handled correctly!
+
+  visitInstruction(I);
+}
+
+
 
 /// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the
 /// function, lowering any calls to unknown intrinsic functions into the