IntrinsicLowering.cpp revision f0a3e6c21cc24ebbec701bd8f6b1253b49498457
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"
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  return new CallInst(FCache, Operands, Name, CI);
73}
74
75void 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
106void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
107  Function *Callee = CI->getCalledFunction();
108  assert(Callee && "Cannot lower an indirect call!");
109
110  switch (Callee->getIntrinsicID()) {
111  case Intrinsic::not_intrinsic:
112    std::cerr << "Cannot lower a call to a non-intrinsic function '"
113              << Callee->getName() << "'!\n";
114    abort();
115  default:
116    std::cerr << "Error: Code generator does not support intrinsic function '"
117              << Callee->getName() << "'!\n";
118    abort();
119
120    // The setjmp/longjmp intrinsics should only exist in the code if it was
121    // never optimized (ie, right out of the CFE), or if it has been hacked on
122    // by the lowerinvoke pass.  In both cases, the right thing to do is to
123    // convert the call to an explicit setjmp or longjmp call.
124  case Intrinsic::setjmp: {
125    static Function *SetjmpFCache = 0;
126    Value *V = ReplaceCallWith("setjmp", CI, CI->op_begin()+1, CI->op_end(),
127                               Type::IntTy, SetjmpFCache);
128    if (CI->getType() != Type::VoidTy)
129      CI->replaceAllUsesWith(V);
130    break;
131  }
132  case Intrinsic::sigsetjmp:
133     if (CI->getType() != Type::VoidTy)
134       CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
135     break;
136
137  case Intrinsic::longjmp: {
138    static Function *LongjmpFCache = 0;
139    ReplaceCallWith("longjmp", CI, CI->op_begin()+1, CI->op_end(),
140                    Type::VoidTy, LongjmpFCache);
141    break;
142  }
143
144  case Intrinsic::siglongjmp: {
145    // Insert the call to abort
146    static Function *AbortFCache = 0;
147    ReplaceCallWith("abort", CI, CI->op_end(), CI->op_end(), Type::VoidTy,
148                    AbortFCache);
149    break;
150  }
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  }
178  case Intrinsic::memmove: {
179    // The memmove intrinsic take an extra alignment argument that the memmove
180    // libc function does not.
181    static Function *MemmoveFCache = 0;
182    ReplaceCallWith("memmove", CI, CI->op_begin()+1, CI->op_end()-1,
183                    (*(CI->op_begin()+1))->getType(), MemmoveFCache);
184    break;
185  }
186  case Intrinsic::memset: {
187    // The memset intrinsic take an extra alignment argument that the memset
188    // libc function does not.
189    static Function *MemsetFCache = 0;
190    ReplaceCallWith("memset", CI, CI->op_begin()+1, CI->op_end()-1,
191                    (*(CI->op_begin()+1))->getType(), MemsetFCache);
192    break;
193  }
194  }
195
196  assert(CI->use_empty() &&
197         "Lowering should have eliminated any uses of the intrinsic call!");
198  CI->getParent()->getInstList().erase(CI);
199}
200