Build constants using instructions mov/orr or mvn/eor.

llvm-svn: 33141
diff --git a/llvm/lib/Target/ARM/ARMCommon.cpp b/llvm/lib/Target/ARM/ARMCommon.cpp
new file mode 100644
index 0000000..fd37573
--- /dev/null
+++ b/llvm/lib/Target/ARM/ARMCommon.cpp
@@ -0,0 +1,84 @@
+//===-- ARMCommon.cpp - Define support functions for ARM --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the "Instituto Nokia de Tecnologia" and
+// is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//
+//===----------------------------------------------------------------------===//
+#include "ARMCommon.h"
+
+static inline unsigned rotateL(unsigned x, unsigned n){
+  return ((x << n) | (x  >> (32 - n)));
+}
+
+static inline unsigned rotateR(unsigned x, unsigned n){
+  return ((x >> n) | (x  << (32 - n)));
+}
+
+// finds the end position of largest sequence of zeros in binary representation
+// of 'immediate'.
+static int findLargestZeroSequence(unsigned immediate){
+  int max_zero_pos = 0;
+  int max_zero_length = 0;
+  int zero_pos;
+  int zero_length;
+  int pos = 0;
+  int end_pos;
+
+  while ((immediate & 0x3) == 0) {
+    immediate = rotateR(immediate, 2);
+    pos+=2;
+  }
+  end_pos = pos+32;
+
+  while (pos<end_pos){
+    while (((immediate & 0x3) != 0)&&(pos<end_pos)) {
+      immediate = rotateR(immediate, 2);
+      pos+=2;
+    }
+    zero_pos = pos;
+    while (((immediate & 0x3) == 0)&&(pos<end_pos)) {
+      immediate = rotateR(immediate, 2);
+      pos+=2;
+    }
+    zero_length = pos - zero_pos;
+    if (zero_length > max_zero_length){
+      max_zero_length = zero_length;
+      max_zero_pos = zero_pos % 32;
+    }
+
+  }
+
+  return (max_zero_pos + max_zero_length) % 32;
+}
+
+std::vector<unsigned> splitImmediate(unsigned immediate){
+  std::vector<unsigned> immediatePieces;
+
+  if (immediate == 0){
+    immediatePieces.push_back(0);
+  } else {
+    int start_pos = findLargestZeroSequence(immediate);
+    unsigned immediate_tmp = rotateR(immediate, start_pos);
+    int pos = 0;
+    while (pos < 32){
+      while(((immediate_tmp&0x3) == 0)&&(pos<32)){
+        immediate_tmp = rotateR(immediate_tmp,2);
+        pos+=2;
+      }
+      if (pos < 32){
+        immediatePieces.push_back(rotateL(immediate_tmp&0xFF,
+                                          (start_pos + pos) % 32 ));
+        immediate_tmp = rotateR(immediate_tmp,8);
+        pos+=8;
+      }
+    }
+  }
+  return immediatePieces;
+}
diff --git a/llvm/lib/Target/ARM/ARMCommon.h b/llvm/lib/Target/ARM/ARMCommon.h
new file mode 100644
index 0000000..c35150b
--- /dev/null
+++ b/llvm/lib/Target/ARM/ARMCommon.h
@@ -0,0 +1,22 @@
+//===-- ARMCommon.h - Define support functions for ARM ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the "Instituto Nokia de Tecnologia" and
+// is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ARM_COMMON_H
+#define ARM_COMMON_H
+
+#include <vector>
+
+std::vector<unsigned> splitImmediate(unsigned immediate);
+
+#endif
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index ef28a90..2a5f3e3 100644
--- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -13,6 +13,7 @@
 
 #include "ARM.h"
 #include "ARMTargetMachine.h"
+#include "ARMCommon.h"
 #include "llvm/CallingConv.h"
 #include "llvm/DerivedTypes.h"
 #include "llvm/Function.h"
@@ -27,6 +28,7 @@
 #include "llvm/CodeGen/SSARegMap.h"
 #include "llvm/Target/TargetLowering.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
 #include <vector>
 using namespace llvm;
 
@@ -103,8 +105,8 @@
   setOperationAction(ISD::VAEND,         MVT::Other, Expand);
   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
 
-  setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
-  setOperationAction(ISD::ConstantFP, MVT::f32, Expand);
+  setOperationAction(ISD::ConstantFP, MVT::f64, Custom);
+  setOperationAction(ISD::ConstantFP, MVT::f32, Custom);
 
   setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
   setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
@@ -543,6 +545,70 @@
   return CPI;
 }
 
+SDOperand LegalizeImmediate(uint32_t immediate, SelectionDAG &DAG,
+                            bool canReturnConstant){
+  SDOperand Shift = DAG.getTargetConstant(0, MVT::i32);
+  SDOperand ShiftType = DAG.getTargetConstant(ARMShift::LSL, MVT::i32);
+  std::vector<unsigned>immediatePieces = splitImmediate(immediate);
+  if (immediatePieces.size()>1){
+    unsigned movInst = ARM::MOV;
+    unsigned orInst = ARM::ORR;
+    SDNode *node;
+    //try mvn
+    std::vector<unsigned>immediateNegPieces = splitImmediate(~immediate);
+    if (immediatePieces.size() > immediateNegPieces.size()) {
+      //use mvn/eor
+      movInst = ARM::MVN;
+      orInst = ARM::EOR;
+      immediatePieces = immediateNegPieces;
+    }
+    SDOperand n = DAG.getTargetConstant(immediatePieces[0], MVT::i32);
+    node = DAG.getTargetNode(movInst, MVT::i32, n, Shift, ShiftType);
+    std::vector<unsigned>::iterator it;
+    for (it=immediatePieces.begin()+1; it != immediatePieces.end(); ++it){
+      n = DAG.getTargetConstant(*it, MVT::i32);
+      SDOperand ops[] = {SDOperand(node, 0), n, Shift, ShiftType};
+      node = DAG.getTargetNode(orInst, MVT::i32, ops, 4);
+    }
+    return SDOperand(node, 0);
+  } else {
+    if (canReturnConstant)
+      return DAG.getTargetConstant(immediate, MVT::i32);
+    else {
+      SDOperand n = DAG.getTargetConstant(immediate, MVT::i32);
+      SDNode *node = DAG.getTargetNode(ARM::MOV,  MVT::i32, n, Shift,
+                                       ShiftType);
+      return SDOperand(node, 0);
+    }
+  }
+}
+
+static SDOperand LowerConstantFP(SDOperand Op, SelectionDAG &DAG) {
+  MVT::ValueType VT = Op.getValueType();
+  SDOperand Shift     = DAG.getTargetConstant(0, MVT::i32);
+  SDOperand ShiftType = DAG.getTargetConstant(ARMShift::LSL, MVT::i32);
+  SDNode *node;
+  switch (VT) {
+  default: assert(0 && "VT!=f32 && VT!=f64");
+  case MVT::f32: {
+    float val = cast<ConstantFPSDNode>(Op)->getValue();
+    uint32_t i32_val = FloatToBits(val);
+    SDOperand c = LegalizeImmediate(i32_val, DAG, false);
+    node = DAG.getTargetNode(ARM::FMSR, MVT::f32, c);
+    break;
+  }
+  case MVT::f64: {
+    double val = cast<ConstantFPSDNode>(Op)->getValue();
+    uint64_t i64_val = DoubleToBits(val);
+    SDOperand hi = LegalizeImmediate(Hi_32(i64_val), DAG, false);
+    SDOperand lo = LegalizeImmediate(Lo_32(i64_val), DAG, false);
+    node = DAG.getTargetNode(ARM::FMDRR, MVT::f64, lo, hi);
+    break;
+  }
+  }
+  return SDOperand(node, 0);
+}
+
 static SDOperand LowerGlobalAddress(SDOperand Op,
 				    SelectionDAG &DAG) {
   GlobalValue  *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
@@ -849,6 +915,8 @@
     abort();
   case ISD::ConstantPool:
     return LowerConstantPool(Op, DAG);
+  case ISD::ConstantFP:
+    return LowerConstantFP(Op, DAG);
   case ISD::GlobalAddress:
     return LowerGlobalAddress(Op, DAG);
   case ISD::FP_TO_SINT:
@@ -942,26 +1010,12 @@
   switch(N.getOpcode()) {
   case ISD::Constant: {
     uint32_t val = cast<ConstantSDNode>(N)->getValue();
-    if(!isRotInt8Immediate(val)) {
-      SDOperand Z = CurDAG->getTargetConstant(0,     MVT::i32);
-      SDNode *n;
-      if (isRotInt8Immediate(~val)) {
-        SDOperand C = CurDAG->getTargetConstant(~val,  MVT::i32);
-        n           = CurDAG->getTargetNode(ARM::MVN,  MVT::i32, C, Z, Z);
-     } else {
-        Constant    *C = ConstantInt::get(Type::Int32Ty, val);
-        int  alignment = 2;
-        SDOperand Addr = CurDAG->getTargetConstantPool(C, MVT::i32, alignment);
-        n              = CurDAG->getTargetNode(ARM::LDR,  MVT::i32, Addr, Z);
-      }
-      Arg            = SDOperand(n, 0);
-    } else
-      Arg            = CurDAG->getTargetConstant(val,    MVT::i32);
-
-    Shift     = CurDAG->getTargetConstant(0,             MVT::i32);
-    ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32);
+    Shift        = CurDAG->getTargetConstant(0, MVT::i32);
+    ShiftType    = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32);
+    Arg = LegalizeImmediate(val, *CurDAG, true);
     return true;
   }
+
   case ISD::SRA:
     Arg       = N.getOperand(0);
     Shift     = N.getOperand(1);
diff --git a/llvm/lib/Target/ARM/ARMRegisterInfo.cpp b/llvm/lib/Target/ARM/ARMRegisterInfo.cpp
index 404ebee..4890e30 100644
--- a/llvm/lib/Target/ARM/ARMRegisterInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMRegisterInfo.cpp
@@ -14,6 +14,7 @@
 
 #include "ARM.h"
 #include "ARMRegisterInfo.h"
+#include "ARMCommon.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
@@ -35,82 +36,18 @@
   return NoFramePointerElim || MFI->hasVarSizedObjects();
 }
 
-static inline unsigned rotateL(unsigned x, unsigned n){
-  return ((x << n) | (x  >> (32 - n)));
-}
-
-static inline unsigned rotateR(unsigned x, unsigned n){
-  return ((x >> n) | (x  << (32 - n)));
-}
-
-// finds the end position of largest sequence of zeros in binary representation
-// of 'immediate'.
-static int findLargestZeroSequence(unsigned immediate){
-  int max_zero_pos;
-  int max_zero_length = 0;
-  int zero_pos;
-  int zero_length;
-  int pos = 0;
-  int end_pos;
-
-  while ((immediate & 0x3) == 0) {
-    immediate = rotateR(immediate, 2);
-    pos+=2;
-  }
-  end_pos = pos+32;
-
-  while (pos<end_pos){
-    while ((immediate & 0x3) != 0) {
-      immediate = rotateR(immediate, 2);
-      pos+=2;
-    }
-    zero_pos = pos;
-    while ((immediate & 0x3) == 0) {
-      immediate = rotateR(immediate, 2);
-      pos+=2;
-    }
-    zero_length = pos - zero_pos;
-    if (zero_length > max_zero_length){
-      max_zero_length = zero_length;
-      max_zero_pos = zero_pos % 32;
-    }
-
-  }
-
-  return (max_zero_pos + max_zero_length) % 32;
-}
-
 static void splitInstructionWithImmediate(MachineBasicBlock &BB,
 				       MachineBasicBlock::iterator I,
 				       const TargetInstrDescriptor &TID,
 				       unsigned DestReg,
 				       unsigned OrigReg,
 				       unsigned immediate){
-
-  if (immediate == 0){
-    BuildMI(BB, I, TID, DestReg).addReg(OrigReg).addImm(0)
-	.addImm(0).addImm(ARMShift::LSL);
-    return;
+  std::vector<unsigned> immediatePieces = splitImmediate(immediate);
+  std::vector<unsigned>::iterator it;
+  for (it=immediatePieces.begin(); it != immediatePieces.end(); ++it){
+    BuildMI(BB, I, TID, DestReg).addReg(OrigReg)
+	.addImm(*it).addImm(0).addImm(ARMShift::LSL);
   }
-
-  int start_pos = findLargestZeroSequence(immediate);
-  unsigned immediate_tmp = rotateR(immediate, start_pos);
-
-  int pos = 0;
-  while (pos < 32){
-    while(((immediate_tmp&0x3) == 0)&&(pos<32)){
-      immediate_tmp = rotateR(immediate_tmp,2);
-      pos+=2;
-    }
-    if (pos < 32){
-      BuildMI(BB, I, TID, DestReg).addReg(OrigReg)
-	.addImm(rotateL(immediate_tmp&0xFF, (start_pos + pos) % 32 ))
-	.addImm(0).addImm(ARMShift::LSL);
-      immediate_tmp = rotateR(immediate_tmp,8);
-      pos+=8;
-    }
-  }
-
 }
 
 ARMRegisterInfo::ARMRegisterInfo(const TargetInstrInfo &tii)