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

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: Fixing for Jan's comments 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),
Mark Seaborn 2013/05/13 20:09:00 Indent by 2 more spaces so that this is more inden
eliben 2013/05/13 22:07:18 Done.
33 LongjmpFunc(0), LongjmpWrapperFunc(0) {
Mark Seaborn 2013/05/13 20:09:00 0 -> NULL?
eliben 2013/05/13 22:07:18 Done.
34 // This is a module pass because it may have to introduce
35 // intrinsic declarations into the module, and rewrite global
36 // initializers.
37 initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry());
38 }
39
40 virtual bool runOnModule(Module &M);
41 private:
42 /// Rewrites the given \p Call to setjmp.
43 void rewriteSetjmpCall(CallInst *Call);
44
45 /// Rewrites the given \p Call to longjmp.
46 void rewriteLongjmpCall(CallInst *Call);
47
48 /// Rewrites the given \p Store instruction that stores a pointer to
Mark Seaborn 2013/05/13 20:09:00 Why are you checking specifically for Store instru
49 /// longjmp.
50 void rewriteLongjmpStore(StoreInst *Store);
51
52 void rewriteAddrOfLongjmpInGlobal(GlobalVariable *Global);
Mark Seaborn 2013/05/13 20:09:00 This also doesn't make sense. You should handle a
53
54 /// Creates the longjmp wrapper on-demand.
55 Function *getOrCreateLongjmpWrapper();
56
57 /// The module this pass runs on.
58 Module *TheModule;
59
60 /// Global longjmp function the original code calls. NULL if it's not in
61 /// the module.
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
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 Function *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);
96 Changed = true;
97 } else if (isa<StoreInst>(Use) || isa<GlobalVariable>(Use)) {
98 report_fatal_error("Taking the address of setjmp is invalid");
99 } else {
100 report_fatal_error("Invalid use of setjmp");
101 }
102 }
103 }
104
105 LongjmpFunc = TheModule->getFunction(LONGJMP_NAME);
106 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) {
107 for (Value::use_iterator UI = LongjmpFunc->use_begin(),
108 UE = LongjmpFunc->use_end(); UI != UE;) {
109 Value *Use = *UI++;
110 if (CallInst *Call = dyn_cast<CallInst>(Use)) {
111 rewriteLongjmpCall(Call);
112 Changed = true;
113 } else if (StoreInst *Store = dyn_cast<StoreInst>(Use)) {
114 rewriteLongjmpStore(Store);
115 Changed = true;
116 } else if (GlobalVariable *Global = dyn_cast<GlobalVariable>(Use)) {
117 rewriteAddrOfLongjmpInGlobal(Global);
118 Changed = true;
119 } else {
120 report_fatal_error("Invalid use of longjmp");
121 }
122 }
123 }
124
125 return Changed;
126 }
127
128 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
129 FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
130
131 // Sanity check on the setjmp call.
132 if (FTy->getNumParams() != 1 ||
133 !FTy->getReturnType()->isIntegerTy() ||
134 !FTy->getParamType(0)->isPointerTy()) {
135 report_fatal_error(Twine("Wrong signature of function ") +
136 Call->getCalledFunction()->getName());
137 }
138 const DebugLoc &DLoc = Call->getDebugLoc();
139
140 // Find the intrinsic function.
141 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule,
142 Intrinsic::nacl_setjmp);
143 // Cast the jmp_buf argument to the type NaClSetjmpCall expects.
144 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
145 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
146 "jmp_buf_i8", Call);
147 JmpBufCast->setDebugLoc(DLoc);
148
149 // Emit the updated call.
150 SmallVector<Value *, 2> Args;
Mark Seaborn 2013/05/13 20:20:42 Nit: 1 will do here instead of 2
eliben 2013/05/13 22:07:18 Done.
151 Args.push_back(JmpBufCast);
152 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
153 NaClSetjmpCall->setDebugLoc(DLoc);
154 NaClSetjmpCall->takeName(Call);
155
156 // Replace the original call.
157 Call->replaceAllUsesWith(NaClSetjmpCall);
158 Call->eraseFromParent();
159 }
160
161 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
162 FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
163
164 // Sanity check on the longjmp call.
165 if (FTy->getNumParams() != 2 ||
166 !FTy->getReturnType()->isVoidTy() ||
167 !FTy->getParamType(0)->isPointerTy()) {
168 report_fatal_error(Twine("Wrong signature of function ") +
169 Call->getCalledFunction()->getName());
170 }
171 const DebugLoc &DLoc = Call->getDebugLoc();
172
173 // Find the intrinsic function.
174 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
175 TheModule, Intrinsic::nacl_longjmp);
176 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
177 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
178 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
179 "jmp_buf_i8", Call);
180 JmpBufCast->setDebugLoc(DLoc);
181
182 // Emit the call.
183 SmallVector<Value *, 2> Args;
184 Args.push_back(JmpBufCast);
185 Args.push_back(Call->getArgOperand(1));
186 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
187 NaClLongjmpCall->setDebugLoc(DLoc);
188 // No takeName here since longjmp is a void call that does not get assigned to
189 // a value.
190
191 // Remove the original call. There's no need for RAUW because longjmp
192 // returns void.
193 Call->eraseFromParent();
194 }
195
196 void RewritePNaClLibraryCalls::rewriteLongjmpStore(StoreInst *Store) {
197 // Sanity check: this method was called for a store that uses a function
198 // pointer to setjmp.
199 Function *CalledFunc = dyn_cast_or_null<Function>(Store->getValueOperand());
200 if (CalledFunc != LongjmpFunc) {
201 report_fatal_error(Twine("Badly formed store of ") +
202 LongjmpFunc->getName());
203 }
204
205 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper();
206
207 // Replace Store by a new store that stores a pointer to the wrapper.
Mark Seaborn 2013/05/13 20:20:42 You should bitcast your wrapper function rather th
208 StoreInst *WrapperStore = new StoreInst(LongjmpWrapperFunc,
209 Store->getPointerOperand(),
210 Store);
211 WrapperStore->setDebugLoc(Store->getDebugLoc());
212 WrapperStore->takeName(Store);
213 Store->replaceAllUsesWith(WrapperStore);
214 Store->eraseFromParent();
215 }
216
217 void RewritePNaClLibraryCalls::rewriteAddrOfLongjmpInGlobal(
218 GlobalVariable *Global) {
219 if (!Global->hasUniqueInitializer()) {
220 report_fatal_error(Twine("Badly formed assignment to global ") +
221 Global->getName());
222 }
223
224 Function *LongjmpWrapperFunc = getOrCreateLongjmpWrapper();
225
226 GlobalVariable *NewGlobal = new GlobalVariable(
227 /* M */ *TheModule,
228 /* Ty */ LongjmpWrapperFunc->getType(),
229 /* isConstant */ Global->isConstant(),
230 /* Linkage */ GlobalValue::PrivateLinkage,
231 /* Initializer */ LongjmpWrapperFunc,
232 /* Name */ "",
233 /* InsertBefore */ Global,
234 /* ThreadLocalMode */ Global->getThreadLocalMode());
235 NewGlobal->setAlignment(Global->getAlignment());
236 // Using takeName instead of assigning Name in the constructor of
237 // GlobalVariable because otherwise a numeric suffix is added to the name,
238 // while we want it to stay exactly the same.
239 NewGlobal->takeName(Global);
240 Global->eraseFromParent();
241 }
242
243 Function *RewritePNaClLibraryCalls::getOrCreateLongjmpWrapper() {
244 if (LongjmpWrapperFunc)
245 return LongjmpWrapperFunc;
246
247 // A wrapper function is created that has the same type as longjmp; it
Mark Seaborn 2013/05/13 20:20:42 You actually don't need to create a new function.
eliben 2013/05/13 22:07:18 Done.
248 // redirects the call to the intrinsic after casting pointer argument.
249 FunctionType *WrapFuncTy = LongjmpFunc->getFunctionType();
250 SmallString<32> Name(WRAP_FUNC_PREFIX); Name.append(LONGJMP_NAME);
Mark Seaborn 2013/05/13 20:20:42 Split onto separate lines.
eliben 2013/05/13 22:07:18 Function removed.
251 Function *LongjmpWrapperFunc = dyn_cast<Function>(
252 TheModule->getOrInsertFunction(Name, WrapFuncTy));
253 LongjmpWrapperFunc->setLinkage(Function::PrivateLinkage);
254
255 // This function has just been created. Fill its contents.
256 LLVMContext &Context = TheModule->getContext();
257 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpWrapperFunc);
258
259 Function::arg_iterator LongjmpArgs = LongjmpWrapperFunc->arg_begin();
260 Value *EnvArg = LongjmpArgs++;
261 EnvArg->setName("env");
262 Value *ValArg = LongjmpArgs++;
263 ValArg->setName("val");
264
265 // Insert a return instruction
Mark Seaborn 2013/05/13 20:20:42 Nit: could insert 'unreachable' instead
eliben 2013/05/13 22:07:18 Done.
266 Instruction *Ret = ReturnInst::Create(Context, 0, BB);
267
268 // Find the intrinsic function.
269 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
270 TheModule, Intrinsic::nacl_longjmp);
271 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
272 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
273 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", Ret);
274
275 // Emit the call.
276 SmallVector<Value *, 2> Args;
277 Args.push_back(JmpBufCast);
278 Args.push_back(ValArg);
279 CallInst::Create(NaClLongjmpFunc, Args, "", Ret);
280
281 return LongjmpWrapperFunc;
282 }
283
284 ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
285 return new RewritePNaClLibraryCalls();
286 }
287
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698