Implement SDIV by power of 2 as srawi/addze rather than load imm, divw
[oota-llvm.git] / lib / Target / PowerPC / PPCISelPattern.cpp
index 8ea208678748d7ea60149730b2b5b7d65aa24831..3b599c580ef04035395a61b345948f7be56e98f7 100644 (file)
@@ -25,6 +25,7 @@
 #include "llvm/CodeGen/SSARegMap.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetOptions.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/ADT/Statistic.h"
@@ -54,6 +55,7 @@ namespace {
       setOperationAction(ISD::SEXTLOAD, MVT::i1, Expand);
       setOperationAction(ISD::SEXTLOAD, MVT::i8, Expand);
 
+      setShiftAmountFlavor(Extend);   // shl X, 32 == 0
       addLegalFPImmediate(+0.0); // Necessary for FSEL
       addLegalFPImmediate(-0.0); // 
 
@@ -171,8 +173,13 @@ PPC32TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
     // We need to load the argument to a virtual register if we determined above
     // that we ran out of physical registers of the appropriate type 
     if (needsLoad) {
+      unsigned SubregOffset = 0;
+      if (ObjectVT == MVT::i8 || ObjectVT == MVT::i1) SubregOffset = 3;
+      if (ObjectVT == MVT::i16) SubregOffset = 2;
       int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
       SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
+      FIN = DAG.getNode(ISD::ADD, MVT::i32, FIN, 
+                        DAG.getConstant(SubregOffset, MVT::i32));
       argt = newroot = DAG.getLoad(ObjectVT, DAG.getEntryNode(), FIN);
     }
     
@@ -191,8 +198,25 @@ PPC32TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
 
   // If the function takes variable number of arguments, make a frame index for
   // the start of the first vararg value... for expansion of llvm.va_start.
-  if (F.isVarArg())
+  if (F.isVarArg()) {
     VarArgsFrameIndex = MFI->CreateFixedObject(4, ArgOffset);
+    SDOperand FIN = DAG.getFrameIndex(VarArgsFrameIndex, MVT::i32);
+    // If this function is vararg, store any remaining integer argument regs
+    // to their spots on the stack so that they may be loaded by deferencing the
+    // result of va_next.
+    std::vector<SDOperand> MemOps;
+    for (; GPR_remaining > 0; --GPR_remaining, ++GPR_idx) {
+      BuildMI(&BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]);
+      SDOperand Val = DAG.getCopyFromReg(GPR[GPR_idx], MVT::i32, DAG.getRoot());
+      SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1), 
+                                    Val, FIN);
+      MemOps.push_back(Store);
+      // Increment the address by four for the next argument to store
+      SDOperand PtrOff = DAG.getConstant(4, getPointerTy());
+      FIN = DAG.getNode(ISD::ADD, MVT::i32, FIN, PtrOff);
+    }
+    DAG.setRoot(DAG.getNode(ISD::TokenFactor, MVT::Other, MemOps));
+  }
 
   return ArgValues;
 }
@@ -251,15 +275,6 @@ PPC32TargetLowering::LowerCallTo(SDOperand Chain,
     unsigned ArgOffset = 24;
     unsigned GPR_remaining = 8;
     unsigned FPR_remaining = 13;
-    unsigned GPR_idx = 0, FPR_idx = 0;
-    static const unsigned GPR[] = { 
-      PPC::R3, PPC::R4, PPC::R5, PPC::R6,
-      PPC::R7, PPC::R8, PPC::R9, PPC::R10,
-    };
-    static const unsigned FPR[] = {
-      PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
-      PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13
-    };
     
     std::vector<SDOperand> MemOps;
     for (unsigned i = 0, e = Args.size(); i != e; ++i) {
@@ -283,10 +298,8 @@ PPC32TargetLowering::LowerCallTo(SDOperand Chain,
         // FALL THROUGH
       case MVT::i32:
         if (GPR_remaining > 0) {
-          args_to_use.push_back(DAG.getCopyToReg(Chain, Args[i].first, 
-                                               GPR[GPR_idx]));
+          args_to_use.push_back(Args[i].first);
           --GPR_remaining;
-          ++GPR_idx;
         } else {
           MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
                                           Args[i].first, PtrOff));
@@ -302,13 +315,11 @@ PPC32TargetLowering::LowerCallTo(SDOperand Chain,
             Args[i].first, DAG.getConstant(1, MVT::i32));
           SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, 
             Args[i].first, DAG.getConstant(0, MVT::i32));
-          args_to_use.push_back(DAG.getCopyToReg(Chain, Hi, GPR[GPR_idx]));
+          args_to_use.push_back(Hi);
           --GPR_remaining;
-          ++GPR_idx;
           if (GPR_remaining > 0) {
-            args_to_use.push_back(DAG.getCopyToReg(Chain, Lo, GPR[GPR_idx]));
+            args_to_use.push_back(Lo);
             --GPR_remaining;
-            ++GPR_idx;
           } else {
             SDOperand ConstFour = DAG.getConstant(4, getPointerTy());
             PtrOff = DAG.getNode(ISD::ADD, MVT::i32, PtrOff, ConstFour);
@@ -324,6 +335,8 @@ PPC32TargetLowering::LowerCallTo(SDOperand Chain,
       case MVT::f32:
       case MVT::f64:
         if (FPR_remaining > 0) {
+          args_to_use.push_back(Args[i].first);
+          --FPR_remaining;
           if (isVarArg) {
             SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Chain,
                                           Args[i].first, PtrOff);
@@ -332,32 +345,29 @@ PPC32TargetLowering::LowerCallTo(SDOperand Chain,
             if (GPR_remaining > 0) {
               SDOperand Load = DAG.getLoad(MVT::i32, Store, PtrOff);
               MemOps.push_back(Load);
-              args_to_use.push_back(DAG.getCopyToReg(Load, Load, 
-                                                     GPR[GPR_idx]));
+              args_to_use.push_back(Load);
+              --GPR_remaining;
             }
-            if (GPR_remaining > 1 && MVT::f64 == ArgVT) {
+            if (GPR_remaining > 0 && MVT::f64 == ArgVT) {
               SDOperand ConstFour = DAG.getConstant(4, getPointerTy());
               PtrOff = DAG.getNode(ISD::ADD, MVT::i32, PtrOff, ConstFour);
               SDOperand Load = DAG.getLoad(MVT::i32, Store, PtrOff);
               MemOps.push_back(Load);
-              args_to_use.push_back(DAG.getCopyToReg(Load, Load, 
-                                                     GPR[GPR_idx+1]));
+              args_to_use.push_back(Load);
+              --GPR_remaining;
+            }
+          } else {
+            // If we have any FPRs remaining, we may also have GPRs remaining.
+            // Args passed in FPRs consume either 1 (f32) or 2 (f64) available
+            // GPRs.
+            if (GPR_remaining > 0) {
+              args_to_use.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
+              --GPR_remaining;
+            }
+            if (GPR_remaining > 0 && MVT::f64 == ArgVT) {
+              args_to_use.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
+              --GPR_remaining;
             }
-          }
-          args_to_use.push_back(DAG.getCopyToReg(Chain, Args[i].first, 
-                                                 FPR[FPR_idx]));
-          --FPR_remaining;
-          ++FPR_idx;
-          // If we have any FPRs remaining, we may also have GPRs remaining.
-          // Args passed in FPRs consume either 1 (f32) or 2 (f64) available
-          // GPRs.
-          if (GPR_remaining > 0) {
-            --GPR_remaining;
-            ++GPR_idx;
-          }
-          if (GPR_remaining > 0 && MVT::f64 == ArgVT) {
-            --GPR_remaining;
-            ++GPR_idx;
           }
         } else {
           MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
@@ -422,7 +432,8 @@ LowerFrameReturnAddress(bool isFrameAddress, SDOperand Chain, unsigned Depth,
 }
 
 namespace {
-
+Statistic<>NotLogic("ppc-codegen", "Number of inverted logical ops");
+Statistic<>FusedFP("ppc-codegen", "Number of fused fp operations");
 //===--------------------------------------------------------------------===//
 /// ISel - PPC32 specific code to select PPC32 machine instructions for
 /// SelectionDAG operations.
@@ -474,6 +485,18 @@ public:
   void SelectBranchCC(SDOperand N);
 };
 
+/// ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N.  It
+/// returns zero when the input is not exactly a power of two.
+static unsigned ExactLog2(unsigned Val) {
+  if (Val == 0 || (Val & (Val-1))) return 0;
+  unsigned Count = 0;
+  while (Val != 1) {
+    Val >>= 1;
+    ++Count;
+  }
+  return Count;
+}
+
 /// canUseAsImmediateForOpcode - This method returns a value indicating whether
 /// the ConstantSDNode N can be used as an immediate to Opcode.  The return
 /// values are either 0, 1 or 2.  0 indicates that either N is not a
@@ -502,12 +525,16 @@ static unsigned canUseAsImmediateForOpcode(SDOperand N, unsigned Opcode,
     if ((v & 0x0000FFFF) == 0) { Imm = v >> 16; return 2; }
     break;
   case ISD::MUL:
+  case ISD::SUB:
     if (v <= 32767 && v >= -32768) { Imm = v & 0xFFFF; return 1; }
     break;
   case ISD::SETCC:
     if (U && (v >= 0 && v <= 65535)) { Imm = v & 0xFFFF; return 1; }
     if (!U && (v <= 32767 && v >= -32768)) { Imm = v & 0xFFFF; return 1; }
     break;
+  case ISD::SDIV:
+    if (0 != ExactLog2(v)) { Imm = ExactLog2(v); return 1; }
+    break;
   }
   return 0;
 }
@@ -771,7 +798,44 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
       .addMBB(copy0MBB).addReg(TrueValue).addMBB(thisMBB);
     return Result;
   }
+
+  case ISD::FNEG:
+    if (!NoExcessFPPrecision && 
+        ISD::ADD == N.getOperand(0).getOpcode() &&
+        N.getOperand(0).Val->hasOneUse() &&
+        ISD::MUL == N.getOperand(0).getOperand(0).getOpcode() &&
+        N.getOperand(0).getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(0).getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FNMADD : PPC::FNMADDS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+    } else if (!NoExcessFPPrecision && 
+        ISD::SUB == N.getOperand(0).getOpcode() &&
+        N.getOperand(0).Val->hasOneUse() &&
+        ISD::MUL == N.getOperand(0).getOperand(0).getOpcode() &&
+        N.getOperand(0).getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(0).getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FNMSUB : PPC::FNMSUBS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+    } else if (ISD::FABS == N.getOperand(0).getOpcode()) {
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+      BuildMI(BB, PPC::FNABS, 1, Result).addReg(Tmp1);
+    } else {
+      Tmp1 = SelectExpr(N.getOperand(0));
+      BuildMI(BB, PPC::FNEG, 1, Result).addReg(Tmp1);
+    }
+    return Result;
     
+  case ISD::FABS:
+    Tmp1 = SelectExpr(N.getOperand(0));
+    BuildMI(BB, PPC::FABS, 1, Result).addReg(Tmp1);
+    return Result;
+
   case ISD::FP_ROUND:
     assert (DestType == MVT::f32 && 
             N.getOperand(0).getValueType() == MVT::f64 && 
@@ -801,14 +865,44 @@ unsigned ISel::SelectExprFP(SDOperand N, unsigned Result)
     return Result;
   }
     
-  case ISD::MUL:
   case ISD::ADD:
+    if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::MUL &&
+        N.getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FMADD : PPC::FMADDS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+      return Result;
+    }
+    Opc = DestType == MVT::f64 ? PPC::FADD : PPC::FADDS;
+    Tmp1 = SelectExpr(N.getOperand(0));
+    Tmp2 = SelectExpr(N.getOperand(1));
+    BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
+    return Result;
+
   case ISD::SUB:
+    if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::MUL &&
+        N.getOperand(0).Val->hasOneUse()) {
+      ++FusedFP; // Statistic
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
+      Tmp3 = SelectExpr(N.getOperand(1));
+      Opc = DestType == MVT::f64 ? PPC::FMSUB : PPC::FMSUBS;
+      BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
+      return Result;
+    }
+    Opc = DestType == MVT::f64 ? PPC::FSUB : PPC::FSUBS;
+    Tmp1 = SelectExpr(N.getOperand(0));
+    Tmp2 = SelectExpr(N.getOperand(1));
+    BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
+    return Result;
+
+  case ISD::MUL:
   case ISD::SDIV:
     switch( opcode ) {
     case ISD::MUL:  Opc = DestType == MVT::f64 ? PPC::FMUL : PPC::FMULS; break;
-    case ISD::ADD:  Opc = DestType == MVT::f64 ? PPC::FADD : PPC::FADDS; break;
-    case ISD::SUB:  Opc = DestType == MVT::f64 ? PPC::FSUB : PPC::FSUBS; break;
     case ISD::SDIV: Opc = DestType == MVT::f64 ? PPC::FDIV : PPC::FDIVS; break;
     };
     Tmp1 = SelectExpr(N.getOperand(0));
@@ -883,40 +977,50 @@ unsigned ISel::SelectExpr(SDOperand N) {
   unsigned &Reg = ExprMap[N];
   if (Reg) return Reg;
 
-  if (N.getOpcode() != ISD::CALL && N.getOpcode() != ISD::ADD_PARTS &&
-      N.getOpcode() != ISD::SUB_PARTS)
+  switch (N.getOpcode()) {
+  default:
     Reg = Result = (N.getValueType() != MVT::Other) ?
-      MakeReg(N.getValueType()) : 1;
-  else {
+                            MakeReg(N.getValueType()) : 1;
+    break;
+  case ISD::CALL:
     // If this is a call instruction, make sure to prepare ALL of the result
     // values as well as the chain.
-    if (N.getOpcode() == ISD::CALL) {
-      if (Node->getNumValues() == 1)
-        Reg = Result = 1;  // Void call, just a chain.
-      else {
-        Result = MakeReg(Node->getValueType(0));
-        ExprMap[N.getValue(0)] = Result;
-        for (unsigned i = 1, e = N.Val->getNumValues()-1; i != e; ++i)
-          ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i));
-        ExprMap[SDOperand(Node, Node->getNumValues()-1)] = 1;
-      }
-    } else {
+    if (Node->getNumValues() == 1)
+      Reg = Result = 1;  // Void call, just a chain.
+    else {
       Result = MakeReg(Node->getValueType(0));
       ExprMap[N.getValue(0)] = Result;
-      for (unsigned i = 1, e = N.Val->getNumValues(); i != e; ++i)
+      for (unsigned i = 1, e = N.Val->getNumValues()-1; i != e; ++i)
         ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i));
+      ExprMap[SDOperand(Node, Node->getNumValues()-1)] = 1;
     }
+    break;
+  case ISD::ADD_PARTS:
+  case ISD::SUB_PARTS:
+  case ISD::SHL_PARTS:
+  case ISD::SRL_PARTS:
+  case ISD::SRA_PARTS:
+    Result = MakeReg(Node->getValueType(0));
+    ExprMap[N.getValue(0)] = Result;
+    for (unsigned i = 1, e = N.Val->getNumValues(); i != e; ++i)
+      ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i));
+    break;
   }
 
+  if (ISD::CopyFromReg == opcode)
+    DestType = N.getValue(0).getValueType();
+    
   if (DestType == MVT::f64 || DestType == MVT::f32)
-    if (ISD::LOAD != opcode && ISD::EXTLOAD != opcode)
+    if (ISD::LOAD != opcode && ISD::EXTLOAD != opcode && ISD::UNDEF != opcode)
       return SelectExprFP(N, Result);
 
   switch (opcode) {
   default:
     Node->dump();
     assert(0 && "Node not handled!\n");
+  case ISD::UNDEF:
+    BuildMI(BB, PPC::IMPLICIT_DEF, 0, Result);
+    return Result;
   case ISD::DYNAMIC_STACKALLOC:
     // Generate both result values.  FIXME: Need a better commment here?
     if (Result != 1)
@@ -1020,26 +1124,70 @@ unsigned ISel::SelectExpr(SDOperand N) {
   }
     
   case ISD::CALL: {
+    unsigned GPR_idx = 0, FPR_idx = 0;
+    static const unsigned GPR[] = { 
+      PPC::R3, PPC::R4, PPC::R5, PPC::R6,
+      PPC::R7, PPC::R8, PPC::R9, PPC::R10,
+    };
+    static const unsigned FPR[] = {
+      PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
+      PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13
+    };
+
     // Lower the chain for this call.
     Select(N.getOperand(0));
     ExprMap[N.getValue(Node->getNumValues()-1)] = 1;
 
-    for(int i = 2, e = Node->getNumOperands(); i < e; ++i)
-      Select(N.getOperand(i));
-      
+    MachineInstr *CallMI;
     // Emit the correct call instruction based on the type of symbol called.
     if (GlobalAddressSDNode *GASD = 
         dyn_cast<GlobalAddressSDNode>(N.getOperand(1))) {
-      BuildMI(BB, PPC::CALLpcrel, 1).addGlobalAddress(GASD->getGlobal(), true);
+      CallMI = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(GASD->getGlobal(), 
+                                                           true);
     } else if (ExternalSymbolSDNode *ESSDN = 
                dyn_cast<ExternalSymbolSDNode>(N.getOperand(1))) {
-      BuildMI(BB, PPC::CALLpcrel, 1).addExternalSymbol(ESSDN->getSymbol(), true);
+      CallMI = BuildMI(PPC::CALLpcrel, 1).addExternalSymbol(ESSDN->getSymbol(), 
+                                                            true);
     } else {
       Tmp1 = SelectExpr(N.getOperand(1));
       BuildMI(BB, PPC::OR, 2, PPC::R12).addReg(Tmp1).addReg(Tmp1);
       BuildMI(BB, PPC::MTCTR, 1).addReg(PPC::R12);
-      BuildMI(BB, PPC::CALLindirect, 3).addImm(20).addImm(0).addReg(PPC::R12);
+      CallMI = BuildMI(PPC::CALLindirect, 3).addImm(20).addImm(0)
+        .addReg(PPC::R12);
+    }
+       
+    // Load the register args to virtual regs
+    std::vector<unsigned> ArgVR;
+    for(int i = 2, e = Node->getNumOperands(); i < e; ++i)
+      ArgVR.push_back(SelectExpr(N.getOperand(i)));
+
+    // Copy the virtual registers into the appropriate argument register
+    for(int i = 0, e = ArgVR.size(); i < e; ++i) {
+      switch(N.getOperand(i+2).getValueType()) {
+      default: Node->dump(); assert(0 && "Unknown value type for call");
+      case MVT::i1:
+      case MVT::i8:
+      case MVT::i16:
+      case MVT::i32:
+        assert(GPR_idx < 8 && "Too many int args");
+        if (N.getOperand(i+2).getOpcode() != ISD::UNDEF) {
+          BuildMI(BB, PPC::OR,2,GPR[GPR_idx]).addReg(ArgVR[i]).addReg(ArgVR[i]);
+          CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
+        }
+        ++GPR_idx;
+        break;
+      case MVT::f64:
+      case MVT::f32:
+        assert(FPR_idx < 13 && "Too many fp args");
+        BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgVR[i]);
+        CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use);
+        ++FPR_idx;
+        break;
+      }
     }
+    
+    // Put the call instruction in the correct place in the MachineBasicBlock
+    BB->push_back(CallMI);
 
     switch (Node->getValueType(0)) {
     default: assert(0 && "Unknown value type for call result!");
@@ -1048,9 +1196,12 @@ unsigned ISel::SelectExpr(SDOperand N) {
     case MVT::i8:
     case MVT::i16:
     case MVT::i32:
-      BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R3).addReg(PPC::R3);
-      if (Node->getValueType(1) == MVT::i32)
-        BuildMI(BB, PPC::OR, 2, Result+1).addReg(PPC::R4).addReg(PPC::R4);
+      if (Node->getValueType(1) == MVT::i32) {
+        BuildMI(BB, PPC::OR, 2, Result+1).addReg(PPC::R3).addReg(PPC::R3);
+        BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R4).addReg(PPC::R4);
+      } else {
+        BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R3).addReg(PPC::R3);
+      }
       break;
     case MVT::f32:
     case MVT::f64:
@@ -1151,8 +1302,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
 
   case ISD::AND:
   case ISD::OR:
-  case ISD::XOR:
-    assert (DestType == MVT::i32 && "Only do arithmetic on i32s!");
     Tmp1 = SelectExpr(N.getOperand(0));
     switch(canUseAsImmediateForOpcode(N.getOperand(1), opcode, Tmp2)) {
       default: assert(0 && "unhandled result code");
@@ -1161,7 +1310,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
         switch (opcode) {
         case ISD::AND: Opc = PPC::AND; break;
         case ISD::OR:  Opc = PPC::OR;  break;
-        case ISD::XOR: Opc = PPC::XOR; break;
         }
         BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
         break;
@@ -1169,7 +1317,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
         switch (opcode) {
         case ISD::AND: Opc = PPC::ANDIo; break;
         case ISD::OR:  Opc = PPC::ORI;   break;
-        case ISD::XOR: Opc = PPC::XORI;  break;
         }
         BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addImm(Tmp2);
         break;
@@ -1177,22 +1324,73 @@ unsigned ISel::SelectExpr(SDOperand N) {
         switch (opcode) {
         case ISD::AND: Opc = PPC::ANDISo;  break;
         case ISD::OR:  Opc = PPC::ORIS;    break;
-        case ISD::XOR: Opc = PPC::XORIS;   break;
         }
         BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addImm(Tmp2);
         break;
     }
     return Result;
 
-  case ISD::SUB:
-    assert (DestType == MVT::i32 && "Only do arithmetic on i32s!");
+  case ISD::XOR: {
+    // Check for EQV: xor, (xor a, -1), b
+    if (N.getOperand(0).getOpcode() == ISD::XOR &&
+        N.getOperand(0).getOperand(1).getOpcode() == ISD::Constant &&
+        cast<ConstantSDNode>(N.getOperand(0).getOperand(1))->isAllOnesValue()) {
+      ++NotLogic;
+      Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(1));
+      BuildMI(BB, PPC::EQV, 2, Result).addReg(Tmp1).addReg(Tmp2);
+      return Result;
+    }
+    // Check for NOT, NOR, and NAND: xor (copy, or, and), -1
+    if (N.getOperand(1).getOpcode() == ISD::Constant &&
+        cast<ConstantSDNode>(N.getOperand(1))->isAllOnesValue()) {
+      ++NotLogic;
+      switch(N.getOperand(0).getOpcode()) {
+      case ISD::OR:
+        Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+        Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
+        BuildMI(BB, PPC::NOR, 2, Result).addReg(Tmp1).addReg(Tmp2);
+        break;
+      case ISD::AND:
+        Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+        Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
+        BuildMI(BB, PPC::NAND, 2, Result).addReg(Tmp1).addReg(Tmp2);
+        break;
+      default:
+        Tmp1 = SelectExpr(N.getOperand(0));
+        BuildMI(BB, PPC::NOR, 2, Result).addReg(Tmp1).addReg(Tmp1);
+        break;
+      }
+      return Result;
+    }
     Tmp1 = SelectExpr(N.getOperand(0));
+    switch(canUseAsImmediateForOpcode(N.getOperand(1), opcode, Tmp2)) {
+      default: assert(0 && "unhandled result code");
+      case 0: // No immediate
+        Tmp2 = SelectExpr(N.getOperand(1));
+        BuildMI(BB, PPC::XOR, 2, Result).addReg(Tmp1).addReg(Tmp2);
+        break;
+      case 1: // Low immediate
+        BuildMI(BB, PPC::XORI, 2, Result).addReg(Tmp1).addImm(Tmp2);
+        break;
+      case 2: // Shifted immediate
+        BuildMI(BB, PPC::XORIS, 2, Result).addReg(Tmp1).addImm(Tmp2);
+        break;
+    }
+    return Result;
+  }
+
+  case ISD::SUB:
     Tmp2 = SelectExpr(N.getOperand(1));
-    BuildMI(BB, PPC::SUBF, 2, Result).addReg(Tmp2).addReg(Tmp1);
+    if (1 == canUseAsImmediateForOpcode(N.getOperand(0), opcode, Tmp1))
+      BuildMI(BB, PPC::SUBFIC, 2, Result).addReg(Tmp2).addSImm(Tmp1);
+    else {
+      Tmp1 = SelectExpr(N.getOperand(0));
+      BuildMI(BB, PPC::SUBF, 2, Result).addReg(Tmp2).addReg(Tmp1);
+    }
     return Result;
     
   case ISD::MUL:
-    assert (DestType == MVT::i32 && "Only do arithmetic on i32s!");
     Tmp1 = SelectExpr(N.getOperand(0));
     if (1 == canUseAsImmediateForOpcode(N.getOperand(1), opcode, Tmp2))
       BuildMI(BB, PPC::MULLI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
@@ -1204,7 +1402,13 @@ unsigned ISel::SelectExpr(SDOperand N) {
 
   case ISD::SDIV:
   case ISD::UDIV:
-    assert (DestType == MVT::i32 && "Only do arithmetic on i32s!");
+    if (1 == canUseAsImmediateForOpcode(N.getOperand(1), opcode, Tmp3)) {
+      Tmp1 = MakeReg(MVT::i32);
+      Tmp2 = SelectExpr(N.getOperand(0));
+      BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3);
+      BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp1);
+      return Result;
+    }
     Tmp1 = SelectExpr(N.getOperand(0));
     Tmp2 = SelectExpr(N.getOperand(1));
     Opc = (ISD::UDIV == opcode) ? PPC::DIVWU : PPC::DIVW;
@@ -1213,7 +1417,6 @@ unsigned ISel::SelectExpr(SDOperand N) {
 
   case ISD::UREM:
   case ISD::SREM: {
-    assert (DestType == MVT::i32 && "Only do arithmetic on i32s!");
     Tmp1 = SelectExpr(N.getOperand(0));
     Tmp2 = SelectExpr(N.getOperand(1));
     Tmp3 = MakeReg(MVT::i32);
@@ -1234,11 +1437,71 @@ unsigned ISel::SelectExpr(SDOperand N) {
     for (unsigned i = 0, e = N.getNumOperands(); i != e; ++i)
       InVals.push_back(SelectExpr(N.getOperand(i)));
     if (N.getOpcode() == ISD::ADD_PARTS) {
-      BuildMI(BB, PPC::ADDC, 2, Result+1).addReg(InVals[0]).addReg(InVals[2]);
-      BuildMI(BB, PPC::ADDE, 2, Result).addReg(InVals[1]).addReg(InVals[3]);
+      BuildMI(BB, PPC::ADDC, 2, Result).addReg(InVals[0]).addReg(InVals[2]);
+      BuildMI(BB, PPC::ADDE, 2, Result+1).addReg(InVals[1]).addReg(InVals[3]);
     } else {
-      BuildMI(BB, PPC::SUBFC, 2, Result+1).addReg(InVals[2]).addReg(InVals[0]);
-      BuildMI(BB, PPC::SUBFE, 2, Result).addReg(InVals[3]).addReg(InVals[1]);
+      BuildMI(BB, PPC::SUBFC, 2, Result).addReg(InVals[2]).addReg(InVals[0]);
+      BuildMI(BB, PPC::SUBFE, 2, Result+1).addReg(InVals[3]).addReg(InVals[1]);
+    }
+    return Result+N.ResNo;
+  }
+
+  case ISD::SHL_PARTS:
+  case ISD::SRA_PARTS:
+  case ISD::SRL_PARTS: {
+    assert(N.getNumOperands() == 3 && N.getValueType() == MVT::i32 &&
+           "Not an i64 shift!");
+    unsigned ShiftOpLo = SelectExpr(N.getOperand(0));
+    unsigned ShiftOpHi = SelectExpr(N.getOperand(1));
+    unsigned SHReg = SelectExpr(N.getOperand(2));
+    Tmp1 = MakeReg(MVT::i32);  
+    Tmp2 = MakeReg(MVT::i32);  
+    Tmp3 = MakeReg(MVT::i32);
+    unsigned Tmp4 = MakeReg(MVT::i32);
+    unsigned Tmp5 = MakeReg(MVT::i32);
+    unsigned Tmp6 = MakeReg(MVT::i32);
+    BuildMI(BB, PPC::SUBFIC, 2, Tmp1).addReg(SHReg).addSImm(32);
+    if (ISD::SHL_PARTS == opcode) {
+      BuildMI(BB, PPC::SLW, 2, Tmp2).addReg(ShiftOpHi).addReg(SHReg);
+      BuildMI(BB, PPC::SRW, 2, Tmp3).addReg(ShiftOpLo).addReg(Tmp1);
+      BuildMI(BB, PPC::OR, 2, Tmp4).addReg(Tmp2).addReg(Tmp3);
+      BuildMI(BB, PPC::ADDI, 2, Tmp5).addReg(SHReg).addSImm(-32);
+      BuildMI(BB, PPC::SLW, 2, Tmp6).addReg(ShiftOpLo).addReg(Tmp5);
+      BuildMI(BB, PPC::OR, 2, Result+1).addReg(Tmp4).addReg(Tmp6);
+      BuildMI(BB, PPC::SLW, 2, Result).addReg(ShiftOpLo).addReg(SHReg);
+    } else if (ISD::SRL_PARTS == opcode) {
+      BuildMI(BB, PPC::SRW, 2, Tmp2).addReg(ShiftOpLo).addReg(SHReg);
+      BuildMI(BB, PPC::SLW, 2, Tmp3).addReg(ShiftOpHi).addReg(Tmp1);
+      BuildMI(BB, PPC::OR, 2, Tmp4).addReg(Tmp2).addReg(Tmp3);
+      BuildMI(BB, PPC::ADDI, 2, Tmp5).addReg(SHReg).addSImm(-32);
+      BuildMI(BB, PPC::SRW, 2, Tmp6).addReg(ShiftOpHi).addReg(Tmp5);
+      BuildMI(BB, PPC::OR, 2, Result).addReg(Tmp4).addReg(Tmp6);
+      BuildMI(BB, PPC::SRW, 2, Result+1).addReg(ShiftOpHi).addReg(SHReg);
+    } else {
+      MachineBasicBlock *TmpMBB = new MachineBasicBlock(BB->getBasicBlock());
+      MachineBasicBlock *PhiMBB = new MachineBasicBlock(BB->getBasicBlock());
+      MachineBasicBlock *OldMBB = BB;
+      MachineFunction *F = BB->getParent();
+      ilist<MachineBasicBlock>::iterator It = BB; ++It;
+      F->getBasicBlockList().insert(It, TmpMBB);
+      F->getBasicBlockList().insert(It, PhiMBB);
+      BB->addSuccessor(TmpMBB);
+      BB->addSuccessor(PhiMBB);
+      BuildMI(BB, PPC::SRW, 2, Tmp2).addReg(ShiftOpLo).addReg(SHReg);
+      BuildMI(BB, PPC::SLW, 2, Tmp3).addReg(ShiftOpHi).addReg(Tmp1);
+      BuildMI(BB, PPC::OR, 2, Tmp4).addReg(Tmp2).addReg(Tmp3);
+      BuildMI(BB, PPC::ADDICo, 2, Tmp5).addReg(SHReg).addSImm(-32);
+      BuildMI(BB, PPC::SRAW, 2, Tmp6).addReg(ShiftOpHi).addReg(Tmp5);
+      BuildMI(BB, PPC::SRAW, 2, Result+1).addReg(ShiftOpHi).addReg(SHReg);
+      BuildMI(BB, PPC::BLE, 2).addReg(PPC::CR0).addMBB(PhiMBB);
+      // Select correct least significant half if the shift amount > 32
+      BB = TmpMBB;
+      unsigned Tmp7 = MakeReg(MVT::i32);
+      BuildMI(BB, PPC::OR, 2, Tmp7).addReg(Tmp6).addReg(Tmp6);
+      TmpMBB->addSuccessor(PhiMBB);
+      BB = PhiMBB;
+      BuildMI(BB, PPC::PHI, 4, Result).addReg(Tmp4).addMBB(OldMBB)
+        .addReg(Tmp7).addMBB(TmpMBB);
     }
     return Result+N.ResNo;
   }
@@ -1498,8 +1761,8 @@ void ISel::Select(SDOperand N) {
       Select(N.getOperand(0));
       Tmp1 = SelectExpr(N.getOperand(1));
       Tmp2 = SelectExpr(N.getOperand(2));
-      BuildMI(BB, PPC::OR, 2, PPC::R3).addReg(Tmp1).addReg(Tmp1);
-      BuildMI(BB, PPC::OR, 2, PPC::R4).addReg(Tmp2).addReg(Tmp2);
+      BuildMI(BB, PPC::OR, 2, PPC::R3).addReg(Tmp2).addReg(Tmp2);
+      BuildMI(BB, PPC::OR, 2, PPC::R4).addReg(Tmp1).addReg(Tmp1);
       break;
     case 2:
       Select(N.getOperand(0));