Implement the AddPrototypes method
[oota-llvm.git] / lib / VMCore / 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/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   return new CallInst(FCache, Operands, Name, CI);
73 }
74
75 void DefaultIntrinsicLowering::AddPrototypes(Module &M) {
76   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
77     if (I->isExternal() && !I->use_empty())
78       switch (I->getIntrinsicID()) {
79       default: break;
80       case Intrinsic::setjmp:
81         EnsureFunctionExists(M, "setjmp", I->abegin(), I->aend(), Type::IntTy);
82         break;
83       case Intrinsic::longjmp:
84         EnsureFunctionExists(M, "longjmp", I->abegin(), I->aend(),Type::VoidTy);
85         break;
86       case Intrinsic::siglongjmp:
87         EnsureFunctionExists(M, "abort", I->aend(), I->aend(), Type::VoidTy);
88         break;
89       case Intrinsic::memcpy:
90         EnsureFunctionExists(M, "memcpy", I->abegin(), --I->aend(),
91                              I->abegin()->getType());
92         break;
93       case Intrinsic::memmove:
94         EnsureFunctionExists(M, "memmove", I->abegin(), --I->aend(),
95                              I->abegin()->getType());
96         break;
97       case Intrinsic::memset:
98         EnsureFunctionExists(M, "memset", I->abegin(), --I->aend(),
99                              I->abegin()->getType());
100         break;
101
102       }
103
104 }
105
106 void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
107   Function *Callee = CI->getCalledFunction();
108   assert(Callee && "Cannot lower an indirect call!");
109   
110   Module *M = Callee->getParent();
111
112   switch (Callee->getIntrinsicID()) {
113   case Intrinsic::not_intrinsic:
114     std::cerr << "Cannot lower a call to a non-intrinsic function '"
115               << Callee->getName() << "'!\n";
116     abort();
117   default:
118     std::cerr << "Error: Code generator does not support intrinsic function '"
119               << Callee->getName() << "'!\n";
120     abort();
121
122     // The setjmp/longjmp intrinsics should only exist in the code if it was
123     // never optimized (ie, right out of the CFE), or if it has been hacked on
124     // by the lowerinvoke pass.  In both cases, the right thing to do is to
125     // convert the call to an explicit setjmp or longjmp call.
126   case Intrinsic::setjmp: {
127     static Function *SetjmpFCache = 0;
128     Value *V = ReplaceCallWith("setjmp", CI, CI->op_begin()+1, CI->op_end(),
129                                Type::IntTy, SetjmpFCache);
130     if (CI->getType() != Type::VoidTy)
131       CI->replaceAllUsesWith(V);
132     break;
133   }
134   case Intrinsic::sigsetjmp: 
135      if (CI->getType() != Type::VoidTy)
136        CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
137      break;
138
139   case Intrinsic::longjmp:
140     static Function *LongjmpFCache = 0;
141     ReplaceCallWith("longjmp", CI, CI->op_begin()+1, CI->op_end(),
142                     Type::VoidTy, LongjmpFCache);
143     break;
144
145   case Intrinsic::siglongjmp:
146     // Insert the call to abort
147     static Function *AbortFCache = 0;
148     ReplaceCallWith("abort", CI, CI->op_end(), CI->op_end(), Type::VoidTy,
149                     AbortFCache);
150     break;
151
152   case Intrinsic::returnaddress:
153   case Intrinsic::frameaddress:
154     std::cerr << "WARNING: this target does not support the llvm."
155               << (Callee->getIntrinsicID() == Intrinsic::returnaddress ? 
156                   "return" : "frame") << "address intrinsic.\n";
157     CI->replaceAllUsesWith(ConstantPointerNull::get(
158                                             cast<PointerType>(CI->getType())));
159     break;
160
161   case Intrinsic::dbg_stoppoint:
162   case Intrinsic::dbg_region_start:
163   case Intrinsic::dbg_region_end:
164   case Intrinsic::dbg_declare:
165   case Intrinsic::dbg_func_start:
166     if (CI->getType() != Type::VoidTy)
167       CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
168     break;    // Simply strip out debugging intrinsics
169
170   case Intrinsic::memcpy:
171     // The memcpy intrinsic take an extra alignment argument that the memcpy
172     // libc function does not.
173     static Function *MemcpyFCache = 0;
174     ReplaceCallWith("memcpy", CI, CI->op_begin()+1, CI->op_end()-1,
175                     (*(CI->op_begin()+1))->getType(), MemcpyFCache);
176     break;
177   case Intrinsic::memmove:
178     // The memmove intrinsic take an extra alignment argument that the memmove
179     // libc function does not.
180     static Function *MemmoveFCache = 0;
181     ReplaceCallWith("memmove", CI, CI->op_begin()+1, CI->op_end()-1,
182                     (*(CI->op_begin()+1))->getType(), MemmoveFCache);
183     break;
184   case Intrinsic::memset:
185     // The memset intrinsic take an extra alignment argument that the memset
186     // libc function does not.
187     static Function *MemsetFCache = 0;
188     ReplaceCallWith("memset", CI, CI->op_begin()+1, CI->op_end()-1,
189                     (*(CI->op_begin()+1))->getType(), MemsetFCache);
190     break;
191   }
192   
193   assert(CI->use_empty() &&
194          "Lowering should have eliminated any uses of the intrinsic call!");
195   CI->getParent()->getInstList().erase(CI);
196 }