6af333e79a59abefd5255f287256c1e882af7c89
[oota-llvm.git] / lib / CodeGen / IntrinsicLowering.cpp
1 //===-- IntrinsicLowering.cpp - Intrinsic Lowering default implementation -===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the default intrinsic lowering implementation.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/CodeGen/IntrinsicLowering.h"
15 #include "llvm/Constants.h"
16 #include "llvm/DerivedTypes.h"
17 #include "llvm/Module.h"
18 #include "llvm/iOther.h"
19 using namespace llvm;
20
21 template <class ArgIt>
22 static Function *EnsureFunctionExists(Module &M, const char *Name,
23                                       ArgIt ArgBegin, ArgIt ArgEnd,
24                                       const Type *RetTy) {
25   if (Function *F = M.getNamedFunction(Name)) return F;
26   // It doesn't already exist in the program, insert a new definition now.
27   std::vector<const Type *> ParamTys;
28   for (ArgIt I = ArgBegin; I != ArgEnd; ++I)
29     ParamTys.push_back(I->getType());
30   return M.getOrInsertFunction(Name, FunctionType::get(RetTy, ParamTys, false));
31 }
32
33 /// ReplaceCallWith - This function is used when we want to lower an intrinsic
34 /// call to a call of an external function.  This handles hard cases such as
35 /// when there was already a prototype for the external function, and if that
36 /// prototype doesn't match the arguments we expect to pass in.
37 template <class ArgIt>
38 static CallInst *ReplaceCallWith(const char *NewFn, CallInst *CI,
39                                  ArgIt ArgBegin, ArgIt ArgEnd,
40                                  const Type *RetTy, Function *&FCache) {
41   if (!FCache) {
42     // If we haven't already looked up this function, check to see if the
43     // program already contains a function with this name.
44     Module *M = CI->getParent()->getParent()->getParent();
45     FCache = M->getNamedFunction(NewFn);
46     if (!FCache) {
47       // It doesn't already exist in the program, insert a new definition now.
48       std::vector<const Type *> ParamTys;
49       for (ArgIt I = ArgBegin; I != ArgEnd; ++I)
50         ParamTys.push_back((*I)->getType());
51       FCache = M->getOrInsertFunction(NewFn,
52                                      FunctionType::get(RetTy, ParamTys, false));
53     }
54    }
55
56   const FunctionType *FT = FCache->getFunctionType();
57   std::vector<Value*> Operands;
58   unsigned ArgNo = 0;
59   for (ArgIt I = ArgBegin; I != ArgEnd && ArgNo != FT->getNumParams();
60        ++I, ++ArgNo) {
61     Value *Arg = *I;
62     if (Arg->getType() != FT->getParamType(ArgNo))
63       Arg = new CastInst(Arg, FT->getParamType(ArgNo), Arg->getName(), CI);
64     Operands.push_back(Arg);
65   }
66   // Pass nulls into any additional arguments...
67   for (; ArgNo != FT->getNumParams(); ++ArgNo)
68     Operands.push_back(Constant::getNullValue(FT->getParamType(ArgNo)));
69
70   std::string Name = CI->getName(); CI->setName("");
71   if (FT->getReturnType() == Type::VoidTy) Name.clear();
72   CallInst *NewCI = new CallInst(FCache, Operands, Name, CI);
73   if (!CI->use_empty()) {
74     Value *V = NewCI;
75     if (CI->getType() != NewCI->getType())
76       V = new CastInst(NewCI, CI->getType(), Name, CI);
77     CI->replaceAllUsesWith(V);
78   }
79   return NewCI;
80 }
81
82 void DefaultIntrinsicLowering::AddPrototypes(Module &M) {
83   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
84     if (I->isExternal() && !I->use_empty())
85       switch (I->getIntrinsicID()) {
86       default: break;
87       case Intrinsic::setjmp:
88         EnsureFunctionExists(M, "setjmp", I->abegin(), I->aend(), Type::IntTy);
89         break;
90       case Intrinsic::longjmp:
91         EnsureFunctionExists(M, "longjmp", I->abegin(), I->aend(),Type::VoidTy);
92         break;
93       case Intrinsic::siglongjmp:
94         EnsureFunctionExists(M, "abort", I->aend(), I->aend(), Type::VoidTy);
95         break;
96       case Intrinsic::memcpy:
97         EnsureFunctionExists(M, "memcpy", I->abegin(), --I->aend(),
98                              I->abegin()->getType());
99         break;
100       case Intrinsic::memmove:
101         EnsureFunctionExists(M, "memmove", I->abegin(), --I->aend(),
102                              I->abegin()->getType());
103         break;
104       case Intrinsic::memset:
105         EnsureFunctionExists(M, "memset", I->abegin(), --I->aend(),
106                              I->abegin()->getType());
107         break;
108       case Intrinsic::isunordered:
109         EnsureFunctionExists(M, "isunordered", I->abegin(), I->aend(), Type::BoolTy);
110         break;
111       }
112
113 }
114
115 void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
116   Function *Callee = CI->getCalledFunction();
117   assert(Callee && "Cannot lower an indirect call!");
118   
119   switch (Callee->getIntrinsicID()) {
120   case Intrinsic::not_intrinsic:
121     std::cerr << "Cannot lower a call to a non-intrinsic function '"
122               << Callee->getName() << "'!\n";
123     abort();
124   default:
125     std::cerr << "Error: Code generator does not support intrinsic function '"
126               << Callee->getName() << "'!\n";
127     abort();
128
129     // The setjmp/longjmp intrinsics should only exist in the code if it was
130     // never optimized (ie, right out of the CFE), or if it has been hacked on
131     // by the lowerinvoke pass.  In both cases, the right thing to do is to
132     // convert the call to an explicit setjmp or longjmp call.
133   case Intrinsic::setjmp: {
134     static Function *SetjmpFCache = 0;
135     Value *V = ReplaceCallWith("setjmp", CI, CI->op_begin()+1, CI->op_end(),
136                                Type::IntTy, SetjmpFCache);
137     if (CI->getType() != Type::VoidTy)
138       CI->replaceAllUsesWith(V);
139     break;
140   }
141   case Intrinsic::sigsetjmp: 
142      if (CI->getType() != Type::VoidTy)
143        CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
144      break;
145
146   case Intrinsic::longjmp: {
147     static Function *LongjmpFCache = 0;
148     ReplaceCallWith("longjmp", CI, CI->op_begin()+1, CI->op_end(),
149                     Type::VoidTy, LongjmpFCache);
150     break;
151   }
152
153   case Intrinsic::siglongjmp: {
154     // Insert the call to abort
155     static Function *AbortFCache = 0;
156     ReplaceCallWith("abort", CI, CI->op_end(), CI->op_end(), Type::VoidTy,
157                     AbortFCache);
158     break;
159   }
160
161   case Intrinsic::returnaddress:
162   case Intrinsic::frameaddress:
163     std::cerr << "WARNING: this target does not support the llvm."
164               << (Callee->getIntrinsicID() == Intrinsic::returnaddress ? 
165                   "return" : "frame") << "address intrinsic.\n";
166     CI->replaceAllUsesWith(ConstantPointerNull::get(
167                                             cast<PointerType>(CI->getType())));
168     break;
169
170   case Intrinsic::dbg_stoppoint:
171   case Intrinsic::dbg_region_start:
172   case Intrinsic::dbg_region_end:
173   case Intrinsic::dbg_declare:
174   case Intrinsic::dbg_func_start:
175     if (CI->getType() != Type::VoidTy)
176       CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
177     break;    // Simply strip out debugging intrinsics
178
179   case Intrinsic::memcpy: {
180     // The memcpy intrinsic take an extra alignment argument that the memcpy
181     // libc function does not.
182     static Function *MemcpyFCache = 0;
183     ReplaceCallWith("memcpy", CI, CI->op_begin()+1, CI->op_end()-1,
184                     (*(CI->op_begin()+1))->getType(), MemcpyFCache);
185     break;
186   }
187   case Intrinsic::memmove: {
188     // The memmove intrinsic take an extra alignment argument that the memmove
189     // libc function does not.
190     static Function *MemmoveFCache = 0;
191     ReplaceCallWith("memmove", CI, CI->op_begin()+1, CI->op_end()-1,
192                     (*(CI->op_begin()+1))->getType(), MemmoveFCache);
193     break;
194   }
195   case Intrinsic::memset: {
196     // The memset intrinsic take an extra alignment argument that the memset
197     // libc function does not.
198     static Function *MemsetFCache = 0;
199     ReplaceCallWith("memset", CI, CI->op_begin()+1, CI->op_end()-1,
200                     (*(CI->op_begin()+1))->getType(), MemsetFCache);
201     break;
202   }
203   case Intrinsic::isunordered: {
204     static Function *isunorderedFCache = 0;
205     ReplaceCallWith("isunordered", CI, CI->op_begin()+1, CI->op_end(),
206                     Type::BoolTy, isunorderedFCache);
207     break;
208   }
209   }
210   
211   assert(CI->use_empty() &&
212          "Lowering should have eliminated any uses of the intrinsic call!");
213   CI->getParent()->getInstList().erase(CI);
214 }