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

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: Addressed latest review 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/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 /// Sanity check that the types of these functions are what we expect them
49 /// to be.
50 void sanityCheckSetjmpFunc(Function *SetjmpFunc);
51 void sanityCheckLongjmpFunc(Function *LongjmpFunc);
52
53 /// The module this pass runs on.
54 Module *TheModule;
55 };
56 }
57
58 char RewritePNaClLibraryCalls::ID = 0;
59 INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls",
60 "Rewrite PNaCl library calls to stable intrinsics",
61 false, false)
62
63 bool RewritePNaClLibraryCalls::runOnModule(Module &M) {
64 TheModule = &M;
65 bool Changed = false;
66
67 // Iterate over all uses of the setjmp, if it exists in the module with
68 // external linkage. If it exists but the linkage is not external, this may
69 // come from code that defines its own function named setjmp and doesn't
70 // include <setjmp.h>. In such a case we leave the code as it is.
71 //
72 // The calls are replaced with intrinsics. All other uses of setjmp are
73 // disallowed (taking the address of setjmp is disallowed in C and C++).
74 Function *SetjmpFunc = TheModule->getFunction("setjmp");
75
76 if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) {
77 sanityCheckSetjmpFunc(SetjmpFunc);
78
79 for (Value::use_iterator UI = SetjmpFunc->use_begin(),
80 UE = SetjmpFunc->use_end(); UI != UE;) {
81 Value *Use = *UI++;
82 if (CallInst *Call = dyn_cast<CallInst>(Use)) {
83 rewriteSetjmpCall(Call);
84 Changed = true;
85 } else {
86 report_fatal_error("Taking the address of setjmp is invalid");
87 }
88 }
89 }
90
91 // For longjmp things are a little more complicated, since longjmp's address
92 // can be taken. Therefore, longjmp can appear in a variety of Uses. The
93 // common case is still a direct call and we want that to be as efficient as
94 // possible, so we rewrite it into a direct intrinsic call. If there are other
95 // uses, the actual body of longjmp is populated with a wrapper that calls
96 // the intrinsic.
97 Function *LongjmpFunc = TheModule->getFunction("longjmp");
98
99 if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) {
100 sanityCheckLongjmpFunc(LongjmpFunc);
101
102 for (Value::use_iterator UI = LongjmpFunc->use_begin(),
103 UE = LongjmpFunc->use_end(); UI != UE;) {
104 Value *Use = *UI++;
105 if (CallInst *Call = dyn_cast<CallInst>(Use)) {
106 rewriteLongjmpCall(Call);
107 Changed = true;
108 }
109 }
110
111 // If additional uses remain, these aren't calls; populate the wrapper.
112 if (!LongjmpFunc->use_empty()) {
113 populateLongjmpWrapper(LongjmpFunc);
114 Changed = true;
115 }
116 }
117
118 return Changed;
119 }
120
121 void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
122 // Find the intrinsic function.
123 Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule,
124 Intrinsic::nacl_setjmp);
125 // Cast the jmp_buf argument to the type NaClSetjmpCall expects.
126 Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
127 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
128 "jmp_buf_i8", Call);
129 const DebugLoc &DLoc = Call->getDebugLoc();
130 JmpBufCast->setDebugLoc(DLoc);
131
132 // Emit the updated call.
133 SmallVector<Value *, 1> Args;
134 Args.push_back(JmpBufCast);
135 CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
136 NaClSetjmpCall->setDebugLoc(DLoc);
137 NaClSetjmpCall->takeName(Call);
138
139 // Replace the original call.
140 Call->replaceAllUsesWith(NaClSetjmpCall);
141 Call->eraseFromParent();
142 }
143
144 void RewritePNaClLibraryCalls::sanityCheckLongjmpFunc(Function *LongjmpFunc) {
145 FunctionType *FTy = LongjmpFunc->getFunctionType();
146 if (!(FTy->getNumParams() == 2 &&
147 FTy->getReturnType()->isVoidTy() &&
148 FTy->getParamType(0)->isPointerTy() &&
149 FTy->getParamType(1)->isIntegerTy())) {
150 report_fatal_error("Wrong signature of longjmp");
151 }
152 }
153
154 void RewritePNaClLibraryCalls::sanityCheckSetjmpFunc(Function *SetjmpFunc) {
155 FunctionType *FTy = SetjmpFunc->getFunctionType();
156 if (!(FTy->getNumParams() == 1 &&
157 FTy->getReturnType()->isIntegerTy() &&
158 FTy->getParamType(0)->isPointerTy())) {
159 report_fatal_error("Wrong signature of setjmp");
160 }
161 }
162
163 void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
164 // Find the intrinsic function.
165 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
166 TheModule, Intrinsic::nacl_longjmp);
167 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
168 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
169 BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
170 "jmp_buf_i8", Call);
171 const DebugLoc &DLoc = Call->getDebugLoc();
172 JmpBufCast->setDebugLoc(DLoc);
173
174 // Emit the call.
175 SmallVector<Value *, 2> Args;
176 Args.push_back(JmpBufCast);
177 Args.push_back(Call->getArgOperand(1));
178 CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
179 NaClLongjmpCall->setDebugLoc(DLoc);
180 // No takeName here since longjmp is a void call that does not get assigned to
181 // a value.
182
183 // Remove the original call. There's no need for RAUW because longjmp
184 // returns void.
185 Call->eraseFromParent();
186 }
187
188 void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) {
189 assert(LongjmpFunc->size() == 0 &&
190 "Expected to be called when longjmp has an empty body");
191
192 // Populate longjmp with code.
193 LLVMContext &Context = TheModule->getContext();
194 BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc);
195
196 Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin();
197 Value *EnvArg = LongjmpArgs++;
198 EnvArg->setName("env");
199 Value *ValArg = LongjmpArgs++;
200 ValArg->setName("val");
201
202 // Find the intrinsic function.
203 Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
204 TheModule, Intrinsic::nacl_longjmp);
205 // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
206 Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
207 BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", BB);
208
209 // Emit the call.
210 SmallVector<Value *, 2> Args;
211 Args.push_back(JmpBufCast);
212 Args.push_back(ValArg);
213 CallInst::Create(NaClLongjmpFunc, Args, "", BB);
214
215 // Insert an unreachable instruction to terminate this function since longjmp
216 // does not return.
217 new UnreachableInst(Context, BB);
218
219 // Finally, set the linkage to internal
220 LongjmpFunc->setLinkage(Function::InternalLinkage);
221 }
222
223 ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
224 return new RewritePNaClLibraryCalls();
225 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698