OLD | NEW |
---|---|
1 //===- ResolvePNaClIntrinsics.cpp - Resolve calls to PNaCl intrinsics ----====// | 1 //===- ResolvePNaClIntrinsics.cpp - Resolve calls to PNaCl intrinsics ----====// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // This pass resolves calls to PNaCl stable bitcode intrinsics. It is | 10 // This pass resolves calls to PNaCl stable bitcode intrinsics. It is |
11 // normally run in the PNaCl translator. | 11 // normally run in the PNaCl translator. |
12 // | 12 // |
13 // Running AddPNaClExternalDeclsPass is a precondition for running this pass. | 13 // Running AddPNaClExternalDeclsPass is a precondition for running this |
14 // They are separate because one is a ModulePass and the other is a | 14 // pass. They are separate because one is a ModulePass and the other is |
15 // FunctionPass. | 15 // a FunctionPass. |
16 // | 16 // |
17 //===----------------------------------------------------------------------===// | 17 //===----------------------------------------------------------------------===// |
18 | 18 |
19 #include "llvm/ADT/SmallVector.h" | 19 #include "llvm/ADT/SmallVector.h" |
20 #include "llvm/IR/Constant.h" | |
20 #include "llvm/IR/Instructions.h" | 21 #include "llvm/IR/Instructions.h" |
22 #include "llvm/IR/IntrinsicInst.h" | |
21 #include "llvm/IR/Intrinsics.h" | 23 #include "llvm/IR/Intrinsics.h" |
22 #include "llvm/IR/Module.h" | 24 #include "llvm/IR/Module.h" |
25 #include "llvm/IR/NaClAtomicIntrinsics.h" | |
26 #include "llvm/IR/Value.h" | |
23 #include "llvm/Pass.h" | 27 #include "llvm/Pass.h" |
28 #include "llvm/Support/Compiler.h" | |
29 #include "llvm/Support/MathExtras.h" | |
24 #include "llvm/Transforms/NaCl.h" | 30 #include "llvm/Transforms/NaCl.h" |
25 | 31 |
26 using namespace llvm; | 32 using namespace llvm; |
27 | 33 |
28 namespace { | 34 namespace { |
29 class ResolvePNaClIntrinsics : public FunctionPass { | 35 class ResolvePNaClIntrinsics : public FunctionPass { |
36 public: | |
37 ResolvePNaClIntrinsics() : FunctionPass(ID) { | |
38 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); | |
39 } | |
40 | |
41 static char ID; | |
42 virtual bool runOnFunction(Function &F); | |
43 | |
44 /// Interface specifying how intrinsic calls should be resolved. Each | |
45 /// intrinsic call handled by the implementor will be visited by the | |
46 /// DoResolve method. | |
47 class CallResolver { | |
30 public: | 48 public: |
31 ResolvePNaClIntrinsics() : FunctionPass(ID) { | 49 /// Called once per \p Call to the intrinsic in the module. |
32 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); | 50 bool Resolve(IntrinsicInst *Call) { |
eliben
2013/07/09 17:17:19
Explain what Resolve (and DoResolve) returns
JF
2013/07/11 00:17:18
Done.
| |
33 } | 51 // To be a well-behaving FunctionPass, don't touch uses in other |
34 | 52 // functions. These will be handled when the pass manager gets to |
35 static char ID; | 53 // those functions. |
36 virtual bool runOnFunction(Function &F); | 54 if (Call->getParent()->getParent() == &F) |
55 return DoResolve(Call); | |
56 return false; | |
57 } | |
58 Function *getDeclaration() const { return DoGetDeclaration(); } | |
59 std::string getName() { return Intrinsic::getName(IntrinsicID); } | |
60 | |
61 protected: | |
62 Function &F; | |
63 Module *M; | |
64 Intrinsic::ID IntrinsicID; | |
65 | |
66 CallResolver(Function &F, Intrinsic::ID IntrinsicID) | |
67 : F(F), M(F.getParent()), IntrinsicID(IntrinsicID) {} | |
68 virtual ~CallResolver() {} | |
69 | |
70 /// The following pure virtual methods must be defined by | |
71 /// implementors, and will be called once per intrinsic call. | |
72 virtual Function *DoGetDeclaration() const = 0; | |
eliben
2013/07/09 17:17:19
I've just noticed that the naming convention is in
JF
2013/07/11 00:17:18
Done.
| |
73 virtual bool DoResolve(IntrinsicInst *Call) = 0; | |
74 | |
37 private: | 75 private: |
38 // Some intrinsic calls are resolved simply by replacing the call with a | 76 CallResolver(const CallResolver &) LLVM_DELETED_FUNCTION; |
39 // call to an alternative function with exactly the same type. | 77 CallResolver &operator=(const CallResolver &) LLVM_DELETED_FUNCTION; |
40 bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID, | |
41 const char *TargetFunctionName); | |
42 }; | 78 }; |
79 | |
80 private: | |
81 /// Visit all calls matching the \p Resolver's declaration, and invoke | |
82 /// the CallResolver methods on each of them. | |
83 bool visitCalls(CallResolver &Resolver); | |
84 }; | |
85 | |
86 /// Rewrite intrinsic calls to another function. | |
87 class SimpleCallResolver : public ResolvePNaClIntrinsics::CallResolver { | |
88 public: | |
89 SimpleCallResolver(Function &F, Intrinsic::ID IntrinsicID, | |
90 const char *TargetFunctionName) | |
91 : CallResolver(F, IntrinsicID), | |
92 TargetFunction(M->getFunction(TargetFunctionName)) { | |
93 // Expect to find the target function for this intrinsic already | |
94 // declared, even if it is never used. | |
95 if (!TargetFunction) | |
96 report_fatal_error( | |
97 std::string("Expected to find external declaration of ") + | |
98 TargetFunctionName); | |
99 } | |
100 virtual ~SimpleCallResolver() {} | |
101 | |
102 private: | |
103 Function *TargetFunction; | |
104 | |
105 virtual Function *DoGetDeclaration() const { | |
106 return Intrinsic::getDeclaration(M, IntrinsicID); | |
107 } | |
108 | |
109 virtual bool DoResolve(IntrinsicInst *Call) { | |
110 Call->setCalledFunction(TargetFunction); | |
111 return true; | |
112 } | |
113 | |
114 SimpleCallResolver(const SimpleCallResolver &) LLVM_DELETED_FUNCTION; | |
115 SimpleCallResolver &operator=( | |
116 const SimpleCallResolver &) LLVM_DELETED_FUNCTION; | |
117 }; | |
118 | |
119 /// Rewrite atomic intrinsics to LLVM IR instructions. | |
120 class AtomicCallResolver : public ResolvePNaClIntrinsics::CallResolver { | |
121 public: | |
122 AtomicCallResolver(Function &F, | |
123 const NaCl::AtomicIntrinsics::AtomicIntrinsic *I) | |
124 : CallResolver(F, I->ID), I(I) {} | |
125 virtual ~AtomicCallResolver() {} | |
126 | |
127 private: | |
128 const NaCl::AtomicIntrinsics::AtomicIntrinsic *I; | |
129 | |
130 virtual Function *DoGetDeclaration() const { return I->getDeclaration(M); } | |
131 | |
132 virtual bool DoResolve(IntrinsicInst *Call) { | |
133 // Assume the @llvm.nacl.atomic.* intrinsics follow the PNaCl ABI: | |
134 // this should have been checked by the verifier. | |
135 bool isVolatile = false; | |
136 SynchronizationScope SS = CrossThread; | |
137 Instruction *I; | |
138 | |
139 switch (Call->getIntrinsicID()) { | |
140 default: | |
141 llvm_unreachable("unknown atomic intrinsic"); | |
142 case Intrinsic::nacl_atomic_load: | |
143 I = new LoadInst(Call->getArgOperand(0), "", isVolatile, | |
144 alignmentFromPointer(Call->getArgOperand(0)), | |
145 thawMemoryOrder(Call->getArgOperand(1)), SS, Call); | |
146 break; | |
147 case Intrinsic::nacl_atomic_store: | |
148 I = new StoreInst(Call->getArgOperand(0), Call->getArgOperand(1), | |
149 isVolatile, | |
150 alignmentFromPointer(Call->getArgOperand(1)), | |
151 thawMemoryOrder(Call->getArgOperand(2)), SS, Call); | |
152 break; | |
153 case Intrinsic::nacl_atomic_rmw: | |
154 I = new AtomicRMWInst(thawRMWOperation(Call->getArgOperand(0)), | |
155 Call->getArgOperand(1), Call->getArgOperand(2), | |
156 thawMemoryOrder(Call->getArgOperand(3)), SS, Call); | |
157 break; | |
158 case Intrinsic::nacl_atomic_cmpxchg: | |
159 // TODO LLVM currently doesn't support specifying separate memory | |
160 // orders for compare exchange's success and failure cases: | |
161 // LLVM IR implicitly drops the Release part of the specified | |
162 // memory order on failure. It is therefore correct to map | |
163 // the success memory order onto the LLVM IR and ignore the | |
164 // failure one. | |
165 I = new AtomicCmpXchgInst(Call->getArgOperand(0), Call->getArgOperand(1), | |
166 Call->getArgOperand(2), | |
167 thawMemoryOrder(Call->getArgOperand(3)), SS, | |
168 Call); | |
169 break; | |
170 case Intrinsic::nacl_atomic_fence: | |
171 I = new FenceInst(M->getContext(), | |
172 thawMemoryOrder(Call->getArgOperand(0)), SS, Call); | |
173 break; | |
174 } | |
175 I->setName(Call->getName()); | |
176 I->setDebugLoc(Call->getDebugLoc()); | |
177 Call->replaceAllUsesWith(I); | |
178 Call->eraseFromParent(); | |
179 | |
180 return true; | |
181 } | |
182 | |
183 unsigned alignmentFromPointer(const Value *Ptr) const { | |
184 unsigned BitWidth = cast<IntegerType>( | |
eliben
2013/07/09 17:17:19
It's very hard to see what the casts refer to here
JF
2013/07/11 00:17:18
Done.
| |
185 cast<PointerType>(Ptr->getType())->getElementType())->getBitWidth(); | |
186 return 1 << (CountTrailingZeros_32(BitWidth) - 3); | |
eliben
2013/07/09 17:17:19
Comment to explain the computation being done here
JF
2013/07/11 00:17:18
Done.
| |
187 } | |
188 | |
189 AtomicOrdering thawMemoryOrder(const Value *MemoryOrder) const { | |
190 NaCl::MemoryOrder MO = (NaCl::MemoryOrder)cast<Constant>(MemoryOrder) | |
191 ->getUniqueInteger().getLimitedValue(); | |
192 switch (MO) { | |
193 // Only valid values should pass validation. | |
194 default: llvm_unreachable("unknown memory order"); | |
195 case NaCl::MemoryOrderRelaxed: return Monotonic; | |
196 // TODO Consume is unspecified by LLVM's internal IR. | |
197 case NaCl::MemoryOrderConsume: return SequentiallyConsistent; | |
198 case NaCl::MemoryOrderAcquire: return Acquire; | |
199 case NaCl::MemoryOrderRelease: return Release; | |
200 case NaCl::MemoryOrderAcquireRelease: return AcquireRelease; | |
201 case NaCl::MemoryOrderSequentiallyConsistent: return SequentiallyConsistent; | |
202 } | |
203 } | |
204 | |
205 AtomicRMWInst::BinOp thawRMWOperation(const Value *Operation) const { | |
206 NaCl::AtomicRMWOperation Op = | |
207 (NaCl::AtomicRMWOperation)cast<Constant>(Operation)->getUniqueInteger() | |
208 .getLimitedValue(); | |
209 switch (Op) { | |
210 // Only valid values should pass validation. | |
211 default: llvm_unreachable("unknown atomic RMW operation"); | |
212 case NaCl::AtomicAdd: return AtomicRMWInst::Add; | |
213 case NaCl::AtomicSub: return AtomicRMWInst::Sub; | |
214 case NaCl::AtomicOr: return AtomicRMWInst::Or; | |
215 case NaCl::AtomicAnd: return AtomicRMWInst::And; | |
216 case NaCl::AtomicXor: return AtomicRMWInst::Xor; | |
217 case NaCl::AtomicExchange: return AtomicRMWInst::Xchg; | |
218 } | |
219 } | |
220 | |
221 AtomicCallResolver(const AtomicCallResolver &); | |
222 AtomicCallResolver &operator=(const AtomicCallResolver &); | |
223 }; | |
43 } | 224 } |
44 | 225 |
45 bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, | 226 bool ResolvePNaClIntrinsics::visitCalls( |
46 Intrinsic::ID IntrinsicID, | 227 ResolvePNaClIntrinsics::CallResolver &Resolver) { |
47 const char *TargetFunctionName) { | |
48 Module *M = F.getParent(); | |
49 bool Changed = false; | 228 bool Changed = false; |
50 Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); | 229 Function *IntrinsicFunction = Resolver.getDeclaration(); |
51 | 230 if (!IntrinsicFunction) |
52 if (!IntrinsicFunction) { | |
53 return false; | 231 return false; |
54 } | |
55 | |
56 // Expect to find the target function for this intrinsic already declared | |
57 Function *TargetFunction = M->getFunction(TargetFunctionName); | |
58 if (!TargetFunction) { | |
59 report_fatal_error( | |
60 std::string("Expected to find external declaration of ") + | |
61 TargetFunctionName); | |
62 } | |
63 | 232 |
64 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), | 233 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), |
65 UE = IntrinsicFunction->use_end(); UI != UE;) { | 234 UE = IntrinsicFunction->use_end(); |
235 UI != UE;) { | |
66 // At this point, the only uses of the intrinsic can be calls, since | 236 // At this point, the only uses of the intrinsic can be calls, since |
67 // we assume this pass runs on bitcode that passed ABI verification. | 237 // we assume this pass runs on bitcode that passed ABI verification. |
68 CallInst *Call = dyn_cast<CallInst>(*UI++); | 238 IntrinsicInst *Call = dyn_cast<IntrinsicInst>(*UI++); |
69 | 239 if (!Call) |
70 if (!Call) { | 240 report_fatal_error("Expected use of intrinsic to be a call: " + |
71 report_fatal_error( | 241 Resolver.getName()); |
72 std::string("Expected use of intrinsic to be a call: ") + | 242 |
73 Intrinsic::getName(IntrinsicID)); | 243 Changed |= Resolver.Resolve(Call); |
74 } | |
75 | |
76 // To be a well-behaving FunctionPass, don't touch uses in other | |
77 // functions. These will be handled when the pass manager gets to those | |
78 // functions. | |
79 if (Call->getParent()->getParent() == &F) { | |
80 Call->setCalledFunction(TargetFunction); | |
81 Changed = true; | |
82 } | |
83 } | 244 } |
84 | 245 |
85 return Changed; | 246 return Changed; |
86 } | 247 } |
87 | 248 |
88 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { | 249 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { |
89 bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); | 250 bool Changed = false; |
90 Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); | 251 |
252 SimpleCallResolver SetJmpResolver(F, Intrinsic::nacl_setjmp, "setjmp"); | |
253 SimpleCallResolver LongJmpResolver(F, Intrinsic::nacl_longjmp, "longjmp"); | |
254 Changed |= visitCalls(SetJmpResolver); | |
255 Changed |= visitCalls(LongJmpResolver); | |
256 | |
257 NaCl::AtomicIntrinsics AI(F.getParent()->getContext()); | |
258 NaCl::AtomicIntrinsics::View V = AI.allIntrinsicsAndOverloads(); | |
259 for (NaCl::AtomicIntrinsics::View::iterator I = V.begin(), E = V.end(); | |
260 I != E; ++I) { | |
261 AtomicCallResolver AtomicResolver(F, I); | |
262 Changed |= visitCalls(AtomicResolver); | |
263 } | |
264 | |
91 return Changed; | 265 return Changed; |
92 } | 266 } |
93 | 267 |
94 char ResolvePNaClIntrinsics::ID = 0; | 268 char ResolvePNaClIntrinsics::ID = 0; |
95 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", | 269 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", |
96 "Resolve PNaCl intrinsic calls", false, false) | 270 "Resolve PNaCl intrinsic calls", false, false) |
97 | 271 |
98 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { | 272 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { |
99 return new ResolvePNaClIntrinsics(); | 273 return new ResolvePNaClIntrinsics(); |
100 } | 274 } |
OLD | NEW |