Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp

Issue 14617017: Adding a pass - RewritePNaClLibraryCalls, that replaces known library calls with stable bitcode int… (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Added llvm.nacl.{set|long}jmp to the list of whitelisted intrinsics for ABI Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //===- RewritePNaClLibraryCalls.cpp - PNaCl library calls to intrinsics ---===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass replaces calls to known library functions with calls to intrinsics
11 // that are part of the PNaCl stable bitcode ABI.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/Twine.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/Intrinsics.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/Pass.h"
21 #include "llvm/Transforms/NaCl.h"
22
23 using namespace llvm;
24
25 namespace {
26 class RewritePNaClLibraryCalls : public ModulePass {
27 public:
28 static char ID;
29 RewritePNaClLibraryCalls() :
30 ModulePass(ID), TheModule(NULL) {
31 // This is a module pass because it may have to introduce
32 // intrinsic declarations into the module and modify a global function.
33 initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry());
34 }
35
36 virtual bool runOnModule(Module &M);
37 private:
38 /// Rewrites the given \p Call of setjmp to a direct intrinsic call.
39 void rewriteSetjmpCall(CallInst *Call);
40
41 /// Rewrites the given \p Call of longjmp to a direct intrinsic call.
42 void rewriteLongjmpCall(CallInst *Call);
43
44 /// Populates the body of longjmp as a wrapper of the intrinsic call.
45 /// Should only be called once. Modifies the given \p LongjmpFunc.
46 void populateLongjmpWrapper(Function *LongjmpFunc);
47
48 /// The module this pass runs on.
49 Module *TheModule;
50 };
51 }
52
53 static const char *LONGJMP_NAME = "longjmp";
Mark Seaborn 2013/05/13 23:39:58 I don't think LLVM uses NAMES_IN_CAPS for non-#def
eliben 2013/05/14 17:38:58 These constants are now just used in a single plac
54 static const char *SETJMP_NAME = "setjmp";
55
56 char RewritePNaClLibraryCalls::ID = 0;
57 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls",
58 "Rewrite PNaCl library calls to stable intrinsics",
59 false, false)
60
61 bool RewritePNaClLibraryCalls::runOnModule(Module &M) {
62 TheModule = &M;
63 bool Changed = false;
64
65 // Iterate over all uses of the setjmp, if it exists in the module with
66 // external linkage. If it exists but the linkage is not external, this may
67 // come from code that defines its own function named setjmp and doesn't
68 // include <setjmp.h>. In such a case we leave the code as it is.
69 //
70 // The calls are replaced with intrinsics. All other uses
71 // of setjmp are disallowed (taking the address of setjmp is disallowed in
Mark Seaborn 2013/05/13 23:39:58 Re-wrap (partly fits on previous line)
eliben 2013/05/14 17:38:58 Done.
72 // C and C++).
73 Function *SetjmpFunc = TheModule->getFunction(SETJMP_NAME);
74 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) {
75 for (Value::use_iterator UI = SetjmpFunc->use_begin(),
76 UE = SetjmpFunc->use_end(); UI != UE;) {
77 Value *Use = *UI++;
78 if (CallInst *Call = dyn_cast<CallInst>(Use)) {
79 rewriteSetjmpCall(Call);
80 Changed = true;
81 } else {
82 report_fatal_error("Taking the address of setjmp is invalid");
83 }
84 }
85 }
86
87 // For longjmp things are a little more complicated, since longjmp's address
88 // can be taken. Therefore, longjmp can appear in a variety of Uses. The
89 // common case is still a direct call and we want that to be as efficient as
90 // possible, so we rewrite it into a direct intrinsic call. If there are other
91 // uses, the actual body of longjmp is populated with a wrapper that calls
92 // the intrinsic.
93 Function *LongjmpFunc = TheModule->getFunction(LONGJMP_NAME);
94 bool LongjmpHasNoncallUses = false;
95
96 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) {
97 for (Value::use_iterator UI = LongjmpFunc->use_begin(),
98 UE = LongjmpFunc->use_end(); UI != UE;) {
99 Value *Use = *UI++;
100 if (CallInst *Call = dyn_cast<CallInst>(Use)) {
101 rewriteLongjmpCall(Call);
102 Changed = true;
103 } else {
104 LongjmpHasNoncallUses = true;
105 }
106 }
107 }
108
109 if (LongjmpHasNoncallUses) {
Mark Seaborn 2013/05/13 23:39:58 Could just do: if (!LongjmpFunc->use_empty()) th
eliben 2013/05/14 17:38:58 Done.
110 populateLongjmpWrapper(LongjmpFunc);
111 Changed = true;
112 }
113
114 return Changed;
115 }
116
117 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
118 FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
119
120 // Sanity check on the setjmp call.
121 if (FTy->getNumParams() != 1 ||
122 !FTy->getReturnType()->isIntegerTy() ||
123 !FTy->getParamType(0)->isPointerTy()) {
124 report_fatal_error(Twine("Wrong signature of function ") +
125 Call->getCalledFunction()->getName());
126 }
127 const DebugLoc &DLoc = Call->getDebugLoc();
128
129 // Find the intrinsic function.
130 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule,
131 Intrinsic::nacl_setjmp);
132 // Cast the jmp_buf argument to the type NaClSetjmpCall expects.
133 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
134 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
135 "jmp_buf_i8", Call);
136 JmpBufCast->setDebugLoc(DLoc);
137
138 // Emit the updated call.
139 SmallVector<Value *, 1> Args;
140 Args.push_back(JmpBufCast);
141 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
142 NaClSetjmpCall->setDebugLoc(DLoc);
143 NaClSetjmpCall->takeName(Call);
144
145 // Replace the original call.
146 Call->replaceAllUsesWith(NaClSetjmpCall);
147 Call->eraseFromParent();
148 }
149
150 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
151 FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
152
153 // Sanity check on the longjmp call.
154 if (FTy->getNumParams() != 2 ||
155 !FTy->getReturnType()->isVoidTy() ||
156 !FTy->getParamType(0)->isPointerTy()) {
157 report_fatal_error(Twine("Wrong signature of function ") +
158 Call->getCalledFunction()->getName());
159 }
160 const DebugLoc &DLoc = Call->getDebugLoc();
161
162 // Find the intrinsic function.
163 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
164 TheModule, Intrinsic::nacl_longjmp);
165 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
166 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
167 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
168 "jmp_buf_i8", Call);
169 JmpBufCast->setDebugLoc(DLoc);
170
171 // Emit the call.
172 SmallVector<Value *, 2> Args;
173 Args.push_back(JmpBufCast);
174 Args.push_back(Call->getArgOperand(1));
175 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
176 NaClLongjmpCall->setDebugLoc(DLoc);
177 // No takeName here since longjmp is a void call that does not get assigned to
178 // a value.
179
180 // Remove the original call. There's no need for RAUW because longjmp
181 // returns void.
182 Call->eraseFromParent();
183 }
184
185 void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) {
186 assert(LongjmpFunc->size() == 0 &&
187 "Expected to be called when longjmp has an empty body");
188
189 // Populate longjmp with code.
190 LLVMContext &Context = TheModule->getContext();
191 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc);
192
193 Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin();
Mark Seaborn 2013/05/13 23:39:58 Also do a sanity check on this function's args, as
eliben 2013/05/14 17:38:58 Refactored
194 Value *EnvArg = LongjmpArgs++;
195 EnvArg->setName("env");
196 Value *ValArg = LongjmpArgs++;
197 ValArg->setName("val");
198
199 // Insert an unreachable instruction to terminate this function since longjmp
200 // does not return.
201 Instruction *End = new UnreachableInst(Context, BB);
Mark Seaborn 2013/05/13 23:39:58 Nit: It would be a little more obvious to add the
eliben 2013/05/14 17:38:58 Done.
202
203 // Find the intrinsic function.
204 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
205 TheModule, Intrinsic::nacl_longjmp);
206 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
207 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
208 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", End);
209
210 // Emit the call.
211 SmallVector<Value *, 2> Args;
212 Args.push_back(JmpBufCast);
213 Args.push_back(ValArg);
214 CallInst::Create(NaClLongjmpFunc, Args, "", End);
215
216 // Finally, set the linkage to internal
217 LongjmpFunc->setLinkage(Function::InternalLinkage);
218 }
219
220 ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
221 return new RewritePNaClLibraryCalls();
222 }
223
Mark Seaborn 2013/05/13 23:39:58 Nit: don't put empty lines at the end of the file
eliben 2013/05/14 17:38:58 Done.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698