IntrinsicLowering.cpp revision 30483737486d00e5c1c37f51138419aa08d8b5e3
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"
19using namespace llvm;
20
21template <class ArgIt>
22static 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.
37template <class ArgIt>
38static 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
82void 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
115void 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}
215