For PR1297:
[oota-llvm.git] / lib / CodeGen / IntrinsicLowering.cpp
index 41d48d947e5d977a32ab21f175841dae58e95e72..3cfa436935f9b73c8c5e22f46a1e5484e1b3f97e 100644 (file)
 #include "llvm/Type.h"
 #include "llvm/CodeGen/IntrinsicLowering.h"
 #include "llvm/Support/Streams.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/ADT/SmallVector.h"
 using namespace llvm;
 
 template <class ArgIt>
-static Function *EnsureFunctionExists(Module &M, const char *Name,
-                                      ArgIt ArgBegin, ArgIt ArgEnd,
-                                      const Type *RetTy) {
-  if (Function *F = M.getNamedFunction(Name)) return F;
-  // It doesn't already exist in the program, insert a new definition now.
+static void EnsureFunctionExists(Module &M, const char *Name,
+                                 ArgIt ArgBegin, ArgIt ArgEnd,
+                                 const Type *RetTy) {
+  // Insert a correctly-typed definition now.
   std::vector<const Type *> ParamTys;
   for (ArgIt I = ArgBegin; I != ArgEnd; ++I)
     ParamTys.push_back(I->getType());
-  return M.getOrInsertFunction(Name, FunctionType::get(RetTy, ParamTys, false));
+  M.getOrInsertFunction(Name, FunctionType::get(RetTy, ParamTys, false));
 }
 
 /// ReplaceCallWith - This function is used when we want to lower an intrinsic
@@ -38,59 +39,31 @@ static Function *EnsureFunctionExists(Module &M, const char *Name,
 /// prototype doesn't match the arguments we expect to pass in.
 template <class ArgIt>
 static CallInst *ReplaceCallWith(const char *NewFn, CallInst *CI,
-                                 ArgIt ArgBegin, ArgIt ArgEnd, bool isSigned,
-                                 const Type *RetTy, Function *&FCache) {
+                                 ArgIt ArgBegin, ArgIt ArgEnd,
+                                 const Type *RetTy, Constant *&FCache) {
   if (!FCache) {
     // If we haven't already looked up this function, check to see if the
     // program already contains a function with this name.
     Module *M = CI->getParent()->getParent()->getParent();
-    FCache = M->getNamedFunction(NewFn);
-    if (!FCache) {
-      // It doesn't already exist in the program, insert a new definition now.
-      std::vector<const Type *> ParamTys;
-      for (ArgIt I = ArgBegin; I != ArgEnd; ++I)
-        ParamTys.push_back((*I)->getType());
-      FCache = M->getOrInsertFunction(NewFn,
-                                     FunctionType::get(RetTy, ParamTys, false));
-    }
-   }
-
-  const FunctionType *FT = FCache->getFunctionType();
-  std::vector<Value*> Operands;
-  unsigned ArgNo = 0;
-  for (ArgIt I = ArgBegin; I != ArgEnd && ArgNo != FT->getNumParams(); 
-       ++I, ++ArgNo) {
-    Value *Arg = *I;
-    if (Arg->getType() != FT->getParamType(ArgNo)) {
-      Instruction::CastOps opcode = CastInst::getCastOpcode(Arg, isSigned,
-          FT->getParamType(ArgNo), isSigned);
-      Arg = CastInst::create(opcode, Arg, FT->getParamType(ArgNo), 
-                             Arg->getName(), CI);
-    }
-    Operands.push_back(Arg);
+    // Get or insert the definition now.
+    std::vector<const Type *> ParamTys;
+    for (ArgIt I = ArgBegin; I != ArgEnd; ++I)
+      ParamTys.push_back((*I)->getType());
+    FCache = M->getOrInsertFunction(NewFn,
+                                    FunctionType::get(RetTy, ParamTys, false));
   }
-  // Pass nulls into any additional arguments...
-  for (; ArgNo != FT->getNumParams(); ++ArgNo)
-    Operands.push_back(Constant::getNullValue(FT->getParamType(ArgNo)));
 
-  std::string Name = CI->getName(); CI->setName("");
-  if (FT->getReturnType() == Type::VoidTy) Name.clear();
-  CallInst *NewCI = new CallInst(FCache, Operands, Name, CI);
-  if (!CI->use_empty()) {
-    Value *V = NewCI;
-    if (CI->getType() != NewCI->getType()) {
-      Instruction::CastOps opcode = CastInst::getCastOpcode(NewCI, isSigned,
-          CI->getType(), isSigned);
-      V = CastInst::create(opcode, NewCI, CI->getType(), Name, CI);
-    }
-    CI->replaceAllUsesWith(V);
-  }
+  SmallVector<Value*, 8> Operands(ArgBegin, ArgEnd);
+  CallInst *NewCI = new CallInst(FCache, &Operands[0], Operands.size(),
+                                 CI->getName(), CI);
+  if (!CI->use_empty())
+    CI->replaceAllUsesWith(NewCI);
   return NewCI;
 }
 
 void IntrinsicLowering::AddPrototypes(Module &M) {
   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
-    if (I->isExternal() && !I->use_empty())
+    if (I->isDeclaration() && !I->use_empty())
       switch (I->getIntrinsicID()) {
       default: break;
       case Intrinsic::setjmp:
@@ -107,25 +80,23 @@ void IntrinsicLowering::AddPrototypes(Module &M) {
         break;
       case Intrinsic::memcpy_i32:
       case Intrinsic::memcpy_i64:
-        EnsureFunctionExists(M, "memcpy", I->arg_begin(), --I->arg_end(),
-                             I->arg_begin()->getType());
+        M.getOrInsertFunction("memcpy", PointerType::get(Type::Int8Ty),
+                              PointerType::get(Type::Int8Ty), 
+                              PointerType::get(Type::Int8Ty), 
+                              TD.getIntPtrType(), (Type *)0);
         break;
       case Intrinsic::memmove_i32:
       case Intrinsic::memmove_i64:
-        EnsureFunctionExists(M, "memmove", I->arg_begin(), --I->arg_end(),
-                             I->arg_begin()->getType());
+        M.getOrInsertFunction("memmove", PointerType::get(Type::Int8Ty),
+                              PointerType::get(Type::Int8Ty), 
+                              PointerType::get(Type::Int8Ty), 
+                              TD.getIntPtrType(), (Type *)0);
         break;
       case Intrinsic::memset_i32:
       case Intrinsic::memset_i64:
         M.getOrInsertFunction("memset", PointerType::get(Type::Int8Ty),
-                              PointerType::get(Type::Int8Ty),
-                              Type::Int32Ty, (--(--I->arg_end()))->getType(),
-                              (Type *)0);
-        break;
-      case Intrinsic::isunordered_f32:
-      case Intrinsic::isunordered_f64:
-        EnsureFunctionExists(M, "isunordered", I->arg_begin(), I->arg_end(),
-                             Type::BoolTy);
+                              PointerType::get(Type::Int8Ty), Type::Int32Ty, 
+                              TD.getIntPtrType(), (Type *)0);
         break;
       case Intrinsic::sqrt_f32:
       case Intrinsic::sqrt_f64:
@@ -149,22 +120,22 @@ static Value *LowerBSWAP(Value *V, Instruction *IP) {
   switch(BitSize) {
   default: assert(0 && "Unhandled type size of value to byteswap!");
   case 16: {
-    Value *Tmp1 = new ShiftInst(Instruction::Shl, V,
-                                ConstantInt::get(Type::Int8Ty,8),"bswap.2",IP);
-    Value *Tmp2 = new ShiftInst(Instruction::LShr, V,
-                                ConstantInt::get(Type::Int8Ty,8),"bswap.1",IP);
+    Value *Tmp1 = BinaryOperator::createShl(V,
+                                ConstantInt::get(V->getType(),8),"bswap.2",IP);
+    Value *Tmp2 = BinaryOperator::createLShr(V,
+                                ConstantInt::get(V->getType(),8),"bswap.1",IP);
     V = BinaryOperator::createOr(Tmp1, Tmp2, "bswap.i16", IP);
     break;
   }
   case 32: {
-    Value *Tmp4 = new ShiftInst(Instruction::Shl, V,
-                              ConstantInt::get(Type::Int8Ty,24),"bswap.4", IP);
-    Value *Tmp3 = new ShiftInst(Instruction::Shl, V,
-                              ConstantInt::get(Type::Int8Ty,8),"bswap.3",IP);
-    Value *Tmp2 = new ShiftInst(Instruction::LShr, V,
-                              ConstantInt::get(Type::Int8Ty,8),"bswap.2",IP);
-    Value *Tmp1 = new ShiftInst(Instruction::LShr, V,
-                              ConstantInt::get(Type::Int8Ty,24),"bswap.1", IP);
+    Value *Tmp4 = BinaryOperator::createShl(V,
+                              ConstantInt::get(V->getType(),24),"bswap.4", IP);
+    Value *Tmp3 = BinaryOperator::createShl(V,
+                              ConstantInt::get(V->getType(),8),"bswap.3",IP);
+    Value *Tmp2 = BinaryOperator::createLShr(V,
+                              ConstantInt::get(V->getType(),8),"bswap.2",IP);
+    Value *Tmp1 = BinaryOperator::createLShr(V,
+                              ConstantInt::get(V->getType(),24),"bswap.1", IP);
     Tmp3 = BinaryOperator::createAnd(Tmp3, 
                                      ConstantInt::get(Type::Int32Ty, 0xFF0000),
                                      "bswap.and3", IP);
@@ -177,22 +148,22 @@ static Value *LowerBSWAP(Value *V, Instruction *IP) {
     break;
   }
   case 64: {
-    Value *Tmp8 = new ShiftInst(Instruction::Shl, V,
-                              ConstantInt::get(Type::Int8Ty,56),"bswap.8", IP);
-    Value *Tmp7 = new ShiftInst(Instruction::Shl, V,
-                              ConstantInt::get(Type::Int8Ty,40),"bswap.7", IP);
-    Value *Tmp6 = new ShiftInst(Instruction::Shl, V,
-                              ConstantInt::get(Type::Int8Ty,24),"bswap.6", IP);
-    Value *Tmp5 = new ShiftInst(Instruction::Shl, V,
-                              ConstantInt::get(Type::Int8Ty,8),"bswap.5", IP);
-    Value* Tmp4 = new ShiftInst(Instruction::LShr, V,
-                              ConstantInt::get(Type::Int8Ty,8),"bswap.4", IP);
-    Value* Tmp3 = new ShiftInst(Instruction::LShr, V,
-                              ConstantInt::get(Type::Int8Ty,24),"bswap.3", IP);
-    Value* Tmp2 = new ShiftInst(Instruction::LShr, V,
-                              ConstantInt::get(Type::Int8Ty,40),"bswap.2", IP);
-    Value* Tmp1 = new ShiftInst(Instruction::LShr, V,
-                              ConstantInt::get(Type::Int8Ty,56),"bswap.1", IP);
+    Value *Tmp8 = BinaryOperator::createShl(V,
+                              ConstantInt::get(V->getType(),56),"bswap.8", IP);
+    Value *Tmp7 = BinaryOperator::createShl(V,
+                              ConstantInt::get(V->getType(),40),"bswap.7", IP);
+    Value *Tmp6 = BinaryOperator::createShl(V,
+                              ConstantInt::get(V->getType(),24),"bswap.6", IP);
+    Value *Tmp5 = BinaryOperator::createShl(V,
+                              ConstantInt::get(V->getType(),8),"bswap.5", IP);
+    Value* Tmp4 = BinaryOperator::createLShr(V,
+                              ConstantInt::get(V->getType(),8),"bswap.4", IP);
+    Value* Tmp3 = BinaryOperator::createLShr(V,
+                              ConstantInt::get(V->getType(),24),"bswap.3", IP);
+    Value* Tmp2 = BinaryOperator::createLShr(V,
+                              ConstantInt::get(V->getType(),40),"bswap.2", IP);
+    Value* Tmp1 = BinaryOperator::createLShr(V,
+                              ConstantInt::get(V->getType(),56),"bswap.1", IP);
     Tmp7 = BinaryOperator::createAnd(Tmp7,
                              ConstantInt::get(Type::Int64Ty, 
                                0xFF000000000000ULL),
@@ -241,8 +212,8 @@ static Value *LowerCTPOP(Value *V, Instruction *IP) {
   for (unsigned i = 1, ct = 0; i != BitSize; i <<= 1, ++ct) {
     Value *MaskCst = ConstantInt::get(V->getType(), MaskValues[ct]);
     Value *LHS = BinaryOperator::createAnd(V, MaskCst, "cppop.and1", IP);
-    Value *VShift = new ShiftInst(Instruction::LShr, V,
-                      ConstantInt::get(Type::Int8Ty, i), "ctpop.sh", IP);
+    Value *VShift = BinaryOperator::createLShr(V,
+                      ConstantInt::get(V->getType(), i), "ctpop.sh", IP);
     Value *RHS = BinaryOperator::createAnd(VShift, MaskCst, "cppop.and2", IP);
     V = BinaryOperator::createAdd(LHS, RHS, "ctpop.step", IP);
   }
@@ -256,8 +227,8 @@ static Value *LowerCTLZ(Value *V, Instruction *IP) {
 
   unsigned BitSize = V->getType()->getPrimitiveSizeInBits();
   for (unsigned i = 1; i != BitSize; i <<= 1) {
-    Value *ShVal = ConstantInt::get(Type::Int8Ty, i);
-    ShVal = new ShiftInst(Instruction::LShr, V, ShVal, "ctlz.sh", IP);
+    Value *ShVal = ConstantInt::get(V->getType(), i);
+    ShVal = BinaryOperator::createLShr(V, ShVal, "ctlz.sh", IP);
     V = BinaryOperator::createOr(V, ShVal, "ctlz.step", IP);
   }
 
@@ -286,10 +257,9 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
     // by the lowerinvoke pass.  In both cases, the right thing to do is to
     // convert the call to an explicit setjmp or longjmp call.
   case Intrinsic::setjmp: {
-    static Function *SetjmpFCache = 0;
-    static const unsigned castOpcodes[] = { Instruction::BitCast };
+    static Constant *SetjmpFCache = 0;
     Value *V = ReplaceCallWith("setjmp", CI, CI->op_begin()+1, CI->op_end(),
-                               castOpcodes, Type::Int32Ty, SetjmpFCache);
+                               Type::Int32Ty, SetjmpFCache);
     if (CI->getType() != Type::VoidTy)
       CI->replaceAllUsesWith(V);
     break;
@@ -300,21 +270,17 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
      break;
 
   case Intrinsic::longjmp: {
-    static Function *LongjmpFCache = 0;
-    static const unsigned castOpcodes[] = 
-      { Instruction::BitCast, 0 };
+    static Constant *LongjmpFCache = 0;
     ReplaceCallWith("longjmp", CI, CI->op_begin()+1, CI->op_end(),
-                    castOpcodes, Type::VoidTy, LongjmpFCache);
+                    Type::VoidTy, LongjmpFCache);
     break;
   }
 
   case Intrinsic::siglongjmp: {
     // Insert the call to abort
-    static Function *AbortFCache = 0;
-    static const unsigned castOpcodes[] =
-      { Instruction::BitCast, 0 };
+    static Constant *AbortFCache = 0;
     ReplaceCallWith("abort", CI, CI->op_end(), CI->op_end(), 
-                    castOpcodes, Type::VoidTy, AbortFCache);
+                    Type::VoidTy, AbortFCache);
     break;
   }
   case Intrinsic::ctpop_i8:
@@ -390,65 +356,79 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
   case Intrinsic::dbg_region_end:
   case Intrinsic::dbg_func_start:
   case Intrinsic::dbg_declare:
-    break;    // Simply strip out debugging intrinsics
+  case Intrinsic::eh_exception:
+  case Intrinsic::eh_selector:
+  case Intrinsic::eh_filter:
+    break;    // Simply strip out debugging and eh intrinsics
 
-  case Intrinsic::memcpy_i32: {
-    static Function *MemcpyFCache = 0;
-    ReplaceCallWith("memcpy", CI, CI->op_begin()+1, CI->op_end()-1,
-                    false, (*(CI->op_begin()+1))->getType(), MemcpyFCache);
-    break;
-  }
+  case Intrinsic::memcpy_i32:
   case Intrinsic::memcpy_i64: {
-    static Function *MemcpyFCache = 0;
-    ReplaceCallWith("memcpy", CI, CI->op_begin()+1, CI->op_end()-1,
-                     false, (*(CI->op_begin()+1))->getType(), MemcpyFCache);
-    break;
-  }
-  case Intrinsic::memmove_i32: {
-    static Function *MemmoveFCache = 0;
-    ReplaceCallWith("memmove", CI, CI->op_begin()+1, CI->op_end()-1,
-                    false, (*(CI->op_begin()+1))->getType(), MemmoveFCache);
+    static Constant *MemcpyFCache = 0;
+    Value *Size = CI->getOperand(3);
+    const Type *IntPtr = TD.getIntPtrType();
+    if (Size->getType()->getPrimitiveSizeInBits() <
+        IntPtr->getPrimitiveSizeInBits())
+      Size = new ZExtInst(Size, IntPtr, "", CI);
+    else if (Size->getType()->getPrimitiveSizeInBits() >
+             IntPtr->getPrimitiveSizeInBits())
+      Size = new TruncInst(Size, IntPtr, "", CI);
+    Value *Ops[3];
+    Ops[0] = CI->getOperand(1);
+    Ops[1] = CI->getOperand(2);
+    Ops[2] = Size;
+    ReplaceCallWith("memcpy", CI, Ops, Ops+3, CI->getOperand(1)->getType(),
+                    MemcpyFCache);
     break;
   }
+  case Intrinsic::memmove_i32: 
   case Intrinsic::memmove_i64: {
-    static Function *MemmoveFCache = 0;
-    ReplaceCallWith("memmove", CI, CI->op_begin()+1, CI->op_end()-1,
-                    false, (*(CI->op_begin()+1))->getType(), MemmoveFCache);
+    static Constant *MemmoveFCache = 0;
+    Value *Size = CI->getOperand(3);
+    const Type *IntPtr = TD.getIntPtrType();
+    if (Size->getType()->getPrimitiveSizeInBits() <
+        IntPtr->getPrimitiveSizeInBits())
+      Size = new ZExtInst(Size, IntPtr, "", CI);
+    else if (Size->getType()->getPrimitiveSizeInBits() >
+             IntPtr->getPrimitiveSizeInBits())
+      Size = new TruncInst(Size, IntPtr, "", CI);
+    Value *Ops[3];
+    Ops[0] = CI->getOperand(1);
+    Ops[1] = CI->getOperand(2);
+    Ops[2] = Size;
+    ReplaceCallWith("memmove", CI, Ops, Ops+3, CI->getOperand(1)->getType(),
+                    MemmoveFCache);
     break;
   }
-  case Intrinsic::memset_i32: {
-    static Function *MemsetFCache = 0;
-    ReplaceCallWith("memset", CI, CI->op_begin()+1, CI->op_end()-1,
-                    true, (*(CI->op_begin()+1))->getType(), MemsetFCache);
-  }
+  case Intrinsic::memset_i32:
   case Intrinsic::memset_i64: {
-    static Function *MemsetFCache = 0;
-    ReplaceCallWith("memset", CI, CI->op_begin()+1, CI->op_end()-1,
-                    true, (*(CI->op_begin()+1))->getType(), MemsetFCache);
-    break;
-  }
-  case Intrinsic::isunordered_f32:
-  case Intrinsic::isunordered_f64: {
-    Value *L = CI->getOperand(1);
-    Value *R = CI->getOperand(2);
-
-    Value *LIsNan = new FCmpInst(FCmpInst::FCMP_ONE, L, L, "LIsNan", CI);
-    Value *RIsNan = new FCmpInst(FCmpInst::FCMP_ONE, R, R, "RIsNan", CI);
-    CI->replaceAllUsesWith(
-      BinaryOperator::create(Instruction::Or, LIsNan, RIsNan,
-                             "isunordered", CI));
+    static Constant *MemsetFCache = 0;
+    Value *Size = CI->getOperand(3);
+    const Type *IntPtr = TD.getIntPtrType();
+    if (Size->getType()->getPrimitiveSizeInBits() <
+        IntPtr->getPrimitiveSizeInBits())
+      Size = new ZExtInst(Size, IntPtr, "", CI);
+    else if (Size->getType()->getPrimitiveSizeInBits() >
+             IntPtr->getPrimitiveSizeInBits())
+      Size = new TruncInst(Size, IntPtr, "", CI);
+    Value *Ops[3];
+    Ops[0] = CI->getOperand(1);
+    // Extend the amount to i32.
+    Ops[1] = new ZExtInst(CI->getOperand(2), Type::Int32Ty, "", CI);
+    Ops[2] = Size;
+    ReplaceCallWith("memset", CI, Ops, Ops+3, CI->getOperand(1)->getType(),
+                    MemsetFCache);
     break;
   }
   case Intrinsic::sqrt_f32: {
-    static Function *sqrtfFCache = 0;
+    static Constant *sqrtfFCache = 0;
     ReplaceCallWith("sqrtf", CI, CI->op_begin()+1, CI->op_end(),
-                    false, Type::FloatTy, sqrtfFCache);
+                    Type::FloatTy, sqrtfFCache);
     break;
   }
   case Intrinsic::sqrt_f64: {
-    static Function *sqrtFCache = 0;
+    static Constant *sqrtFCache = 0;
     ReplaceCallWith("sqrt", CI, CI->op_begin()+1, CI->op_end(),
-                    false, Type::DoubleTy, sqrtFCache);
+                    Type::DoubleTy, sqrtFCache);
     break;
   }
   }