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

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: Adding forgotten test 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/GlobalVariable.h"
18 #include "llvm/IR/Instructions.h"
19 #include "llvm/IR/Intrinsics.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/Pass.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "llvm/Transforms/NaCl.h"
24
25 using namespace llvm;
26
27 namespace {
28 class RewritePNaClLibraryCalls : public ModulePass {
29 public:
30 static char ID;
31 RewritePNaClLibraryCalls() :
32 ModulePass(ID), TheModule(0),
33 SetjmpFunc(0), LongjmpFunc(0), LongjmpWrapperFunc(0) {
34 // This is a module pass because it may have to introduce
35 // intrindic declarations into the module.
jvoung (off chromium) 2013/05/13 18:12:30 intrindic -> intrinsic Another reason (if you wan
eliben 2013/05/13 18:33:36 Done.
36 initializeExpandTlsPass(*PassRegistry::getPassRegistry());
jvoung (off chromium) 2013/05/13 18:12:30 initializeExpandTlsPass?
eliben 2013/05/13 18:33:36 Oops :-/ Thanks, fixed.
37 }
38
39 virtual bool runOnModule(Module &M);
40 private:
41 /// Rewrites the given \p Call to setjmp.
42 void rewriteSetjmpCall(CallInst *Call);
43
44 /// Rewrites the given \p Call to longjmp.
45 void rewriteLongjmpCall(CallInst *Call);
46
47 /// Rewrites the given \p Store instruction that stores a pointer to
48 /// longjmp.
49 void rewriteLongjmpStore(StoreInst *Store);
50
51 void rewriteAddrOfLongjmpInGlobal(GlobalVariable *Global);
52
53 /// Creates the longjmp wrapper on-demand.
54 Function *getOrCreateLongjmpWrapper();
55
56 /// The module this pass runs on.
57 Module *TheModule;
58
59 /// Global setjmp/longjmp functions the original code calls. NULL if they
60 /// are not in the module.
61 Function *SetjmpFunc;
jvoung (off chromium) 2013/05/13 18:12:30 Does SetjmpFunc really need to be a field? It loo
eliben 2013/05/13 18:33:36 Yeah, SetjmpFunc is definitely a leftover from ref
62 Function *LongjmpFunc;
63
64 /// The wrapper for longjmp is created on-demand and cached here.
65 Function *LongjmpWrapperFunc;
66 };
67 }
68
69 static const char *LONGJMP_NAME = "longjmp";
70 static const char *SETJMP_NAME = "setjmp";
71 static const char *WRAP_FUNC_PREFIX = "__nacl_wrap_";
72
73 char RewritePNaClLibraryCalls::ID = 0;
74 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls",
75 "Rewrite PNaCl library calls to stable intrinsics",
76 false, false)
77
78 bool RewritePNaClLibraryCalls::runOnModule(Module &M) {
79 TheModule = &M;
80 bool Changed = false;
81
82 // Iterate over all uses of the setjmp and longjmp functions, if they exist
83 // in the module with external linkage.
84 // For setjmp, calls are replaced by calls to intrinsics.
85 // For longjmp calls are also replaced; however, longjmp can have its
jvoung (off chromium) 2013/05/13 18:12:30 no need for two spaces between ";" and "however"?
eliben 2013/05/13 18:33:36 Done.
86 // address taken, so in these places an address of a wrapper function is
87 // stored instead (or used as an initializer in a global variable).
88 // The wrapper function calls the intrinsic with an appropriate cast.
89 SetjmpFunc = TheModule->getFunction(SETJMP_NAME);
90 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) {
91 for (Value::use_iterator UI = SetjmpFunc->use_begin(),
92 UE = SetjmpFunc->use_end(); UI != UE;) {
93 Value *Use = *UI++;
94 if (CallInst *Call = dyn_cast<CallInst>(Use)) {
95 rewriteSetjmpCall(Call);
jvoung (off chromium) 2013/05/13 18:12:30 Now that you aren't checking "Call->getCalledFunct
eliben 2013/05/13 18:33:36 Not sure what you mean. Only going over the uses o
jvoung (off chromium) 2013/05/13 19:52:07 I was wondering if you had IL like this: %call =
96 Changed = true;
97 } else if (isa<StoreInst>(Use)) {
98 report_fatal_error("Invalid store of setjmp's address");
99 }
jvoung (off chromium) 2013/05/13 18:12:30 Do we expect to see other uses of setjmp (else bra
eliben 2013/05/13 18:33:36 Done.
100 }
101 }
102
103 LongjmpFunc = TheModule->getFunction(LONGJMP_NAME);
104 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) {
105 for (Value::use_iterator UI = LongjmpFunc->use_begin(),
106 UE = LongjmpFunc->use_end(); UI != UE;) {
107 Value *Use = *UI++;
108 if (CallInst *Call = dyn_cast<CallInst>(Use)) {
109 rewriteLongjmpCall(Call);
110 Changed = true;
111 } else if (StoreInst *Store = dyn_cast<StoreInst>(Use)) {
112 rewriteLongjmpStore(Store);
113 Changed = true;
114 } else if (GlobalVariable *Global = dyn_cast<GlobalVariable>(Use)) {
115 rewriteAddrOfLongjmpInGlobal(Global);
116 Changed = true;
117 }
118 }
119 }
120
121 return Changed;
122 }
123
124 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
125 FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
126
127 // Sanity check on the setjmp call.
128 if (FTy->getNumParams() != 1 ||
129 !FTy->getReturnType()->isIntegerTy() ||
130 !FTy->getParamType(0)->isPointerTy()) {
131 report_fatal_error(Twine("Wrong signature of function ") +
132 Call->getCalledFunction()->getName());
133 }
134 const DebugLoc &DLoc = Call->getDebugLoc();
135
136 // Find the intrinsic function.
137 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule,
138 Intrinsic::nacl_setjmp);
139 // Cast the jmp_buf argument to the type NaClSetjmpCall expects.
140 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
141 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
142 "jmp_buf_i8", Call);
143 JmpBufCast->setDebugLoc(DLoc);
144
145 // Emit the updated call.
146 SmallVector<Value *, 2> Args;
147 Args.push_back(JmpBufCast);
148 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
149 NaClSetjmpCall->setDebugLoc(DLoc);
150 NaClSetjmpCall->takeName(Call);
151
152 // Replace the original call.
153 Call->replaceAllUsesWith(NaClSetjmpCall);
154 Call->eraseFromParent();
155 }
156
157 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
158 FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
159
160 // Sanity check on the longjmp call.
161 if (FTy->getNumParams() != 2 ||
162 !FTy->getReturnType()->isVoidTy() ||
163 !FTy->getParamType(0)->isPointerTy()) {
164 report_fatal_error(Twine("Wrong signature of function ") +
165 Call->getCalledFunction()->getName());
166 }
167 const DebugLoc &DLoc = Call->getDebugLoc();
168
169 // Find the intrinsic function.
170 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
171 TheModule, Intrinsic::nacl_longjmp);
172 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
173 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
174 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
175 "jmp_buf_i8", Call);
176 JmpBufCast->setDebugLoc(DLoc);
177
178 // Emit the call.
179 SmallVector<Value *, 2> Args;
180 Args.push_back(JmpBufCast);
181 Args.push_back(Call->getArgOperand(1));
182 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
183 NaClLongjmpCall->setDebugLoc(DLoc);
184 // No takeName here since longjmp is a void call that does not get assigned to
185 // a value.
186
187 // Remove the original call. There's no need for RAUW because longjmp
188 // returns void.
189 Call->eraseFromParent();
190 }
191
192 void RewritePNaClLibraryCalls::rewriteLongjmpStore(StoreInst *Store) {
193 // Sanity check: this method was called for a store that uses a function
194 // pointer to setjmp.
195 Function *CalledFunc = dyn_cast_or_null<Function>(Store->getValueOperand());
196 if (CalledFunc != LongjmpFunc) {
197 report_fatal_error(Twine("Badly formed store of ") +
198 LongjmpFunc->getName());
199 }
200
201 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper();
202
203 // Replace Store by a new store that stores a pointer to the wrapper.
204 StoreInst *WrapperStore = new StoreInst(LongjmpWrapperFunc,
205 Store->getPointerOperand(),
206 Store);
207 WrapperStore->setDebugLoc(Store->getDebugLoc());
208 WrapperStore->takeName(Store);
209 Store->replaceAllUsesWith(WrapperStore);
210 Store->eraseFromParent();
211 }
212
213 void RewritePNaClLibraryCalls::rewriteAddrOfLongjmpInGlobal(
214 GlobalVariable *Global) {
215 if (!Global->hasUniqueInitializer()) {
216 report_fatal_error(Twine("Badly formed assignment to global ") +
217 Global->getName());
218 }
219
220 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper();
221
222 GlobalVariable *NewGlobal = new GlobalVariable(
223 /* M */ *TheModule,
224 /* Ty */ LongjmpWrapperFunc->getType(),
225 /* isConstant */ Global->isConstant(),
226 /* Linkage */ GlobalValue::PrivateLinkage,
227 /* Initializer */ LongjmpWrapperFunc,
228 /* Name */ "",
229 /* InsertBefore */ Global,
230 /* ThreadLocalMode */ Global->getThreadLocalMode());
231 NewGlobal->setAlignment(Global->getAlignment());
232 // Using takeName instead of assigning Name in the constructor of
233 // GlobalVariable because otherwise a numeric suffix is added to the name,
234 // while we want it to stay exactly the same.
235 NewGlobal->takeName(Global);
236 Global->eraseFromParent();
237 }
238
239 Function *RewritePNaClLibraryCalls::getOrCreateLongjmpWrapper() {
240 if (LongjmpWrapperFunc)
241 return LongjmpWrapperFunc;
242
243 // A wrapper function is created that has the same type as longjmp; it
244 // redirects the call to the intrinsic after casting pointer argument.
245 FunctionType *WrapFuncTy = LongjmpFunc->getFunctionType();
246 SmallString<32> Name(WRAP_FUNC_PREFIX); Name.append(LONGJMP_NAME);
247 Function *LongjmpWrapperFunc = dyn_cast<Function>(
248 TheModule->getOrInsertFunction(Name, WrapFuncTy));
249 LongjmpWrapperFunc->setLinkage(Function::PrivateLinkage);
250
251 // This function has just been created. Fill its contents.
252 LLVMContext &Context = TheModule->getContext();
253 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpWrapperFunc);
254
255 Function::arg_iterator LongjmpArgs = LongjmpWrapperFunc->arg_begin();
256 Value *EnvArg = LongjmpArgs++;
257 EnvArg->setName("env");
258 Value *ValArg = LongjmpArgs++;
259 ValArg->setName("val");
260
261 // Insert a return instruction
262 Instruction *Ret = ReturnInst::Create(Context, 0, BB);
263
264 // Find the intrinsic function.
265 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
266 TheModule, Intrinsic::nacl_longjmp);
267 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
268 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
269 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", Ret);
270
271 // Emit the call.
272 SmallVector<Value *, 2> Args;
273 Args.push_back(JmpBufCast);
274 Args.push_back(ValArg);
275 CallInst::Create(NaClLongjmpFunc, Args, "", Ret);
276
277 return LongjmpWrapperFunc;
278 }
279
280 ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
281 return new RewritePNaClLibraryCalls();
282 }
283
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698