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

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

Issue 17777004: Concurrency support for PNaCl ABI (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Fix bad merge. Created 7 years, 5 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
« no previous file with comments | « lib/Transforms/NaCl/ReplacePtrsWithInts.cpp ('k') | lib/Transforms/NaCl/RewriteAtomics.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
24 #include "llvm/Transforms/NaCl.h" 29 #include "llvm/Transforms/NaCl.h"
25 30
26 using namespace llvm; 31 using namespace llvm;
27 32
28 namespace { 33 namespace {
29 class ResolvePNaClIntrinsics : public FunctionPass { 34 class ResolvePNaClIntrinsics : public FunctionPass {
35 public:
36 ResolvePNaClIntrinsics() : FunctionPass(ID) {
37 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry());
38 }
39
40 static char ID;
41 virtual bool runOnFunction(Function &F);
42
43 /// Interface specifying how intrinsic calls should be resolved. Each
44 /// intrinsic call handled by the implementor will be visited by the
45 /// doResolve method.
46 class CallResolver {
30 public: 47 public:
31 ResolvePNaClIntrinsics() : FunctionPass(ID) { 48 /// Called once per \p Call to the intrinsic in the module.
32 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); 49 /// Returns true if the Function was changed.
33 } 50 bool resolve(IntrinsicInst *Call) {
34 51 // To be a well-behaving FunctionPass, don't touch uses in other
35 static char ID; 52 // functions. These will be handled when the pass manager gets to
36 virtual bool runOnFunction(Function &F); 53 // those functions.
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;
73 /// Returns true if the Function was changed.
74 virtual bool doResolve(IntrinsicInst *Call) = 0;
75
37 private: 76 private:
38 // Some intrinsic calls are resolved simply by replacing the call with a 77 CallResolver(const CallResolver &) LLVM_DELETED_FUNCTION;
39 // call to an alternative function with exactly the same type. 78 CallResolver &operator=(const CallResolver &) LLVM_DELETED_FUNCTION;
40 bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID,
41 const char *TargetFunctionName);
42 }; 79 };
80
81 private:
82 /// Visit all calls matching the \p Resolver's declaration, and invoke
83 /// the CallResolver methods on each of them.
84 bool visitCalls(CallResolver &Resolver);
85 };
86
87 /// Rewrite intrinsic calls to another function.
88 class SimpleCallResolver : public ResolvePNaClIntrinsics::CallResolver {
89 public:
90 SimpleCallResolver(Function &F, Intrinsic::ID IntrinsicID,
91 const char *TargetFunctionName)
92 : CallResolver(F, IntrinsicID),
93 TargetFunction(M->getFunction(TargetFunctionName)) {
94 // Expect to find the target function for this intrinsic already
95 // declared, even if it is never used.
96 if (!TargetFunction)
97 report_fatal_error(
98 std::string("Expected to find external declaration of ") +
99 TargetFunctionName);
100 }
101 virtual ~SimpleCallResolver() {}
102
103 private:
104 Function *TargetFunction;
105
106 virtual Function *doGetDeclaration() const {
107 return Intrinsic::getDeclaration(M, IntrinsicID);
108 }
109
110 virtual bool doResolve(IntrinsicInst *Call) {
111 Call->setCalledFunction(TargetFunction);
112 return true;
113 }
114
115 SimpleCallResolver(const SimpleCallResolver &) LLVM_DELETED_FUNCTION;
116 SimpleCallResolver &operator=(
117 const SimpleCallResolver &) LLVM_DELETED_FUNCTION;
118 };
119
120 /// Rewrite atomic intrinsics to LLVM IR instructions.
121 class AtomicCallResolver : public ResolvePNaClIntrinsics::CallResolver {
122 public:
123 AtomicCallResolver(Function &F,
124 const NaCl::AtomicIntrinsics::AtomicIntrinsic *I)
125 : CallResolver(F, I->ID), I(I) {}
126 virtual ~AtomicCallResolver() {}
127
128 private:
129 const NaCl::AtomicIntrinsics::AtomicIntrinsic *I;
130
131 virtual Function *doGetDeclaration() const { return I->getDeclaration(M); }
132
133 virtual bool doResolve(IntrinsicInst *Call) {
134 // Assume the @llvm.nacl.atomic.* intrinsics follow the PNaCl ABI:
135 // this should have been checked by the verifier.
136 bool isVolatile = false;
137 SynchronizationScope SS = CrossThread;
138 Instruction *I;
139
140 switch (Call->getIntrinsicID()) {
141 default:
142 llvm_unreachable("unknown atomic intrinsic");
143 case Intrinsic::nacl_atomic_load:
144 I = new LoadInst(Call->getArgOperand(0), "", isVolatile,
145 alignmentFromPointer(Call->getArgOperand(0)),
146 thawMemoryOrder(Call->getArgOperand(1)), SS, Call);
147 break;
148 case Intrinsic::nacl_atomic_store:
149 I = new StoreInst(Call->getArgOperand(0), Call->getArgOperand(1),
150 isVolatile,
151 alignmentFromPointer(Call->getArgOperand(1)),
152 thawMemoryOrder(Call->getArgOperand(2)), SS, Call);
153 break;
154 case Intrinsic::nacl_atomic_rmw:
155 I = new AtomicRMWInst(thawRMWOperation(Call->getArgOperand(0)),
156 Call->getArgOperand(1), Call->getArgOperand(2),
157 thawMemoryOrder(Call->getArgOperand(3)), SS, Call);
158 break;
159 case Intrinsic::nacl_atomic_cmpxchg:
160 // TODO LLVM currently doesn't support specifying separate memory
161 // orders for compare exchange's success and failure cases:
162 // LLVM IR implicitly drops the Release part of the specified
163 // memory order on failure. It is therefore correct to map
164 // the success memory order onto the LLVM IR and ignore the
165 // failure one.
166 I = new AtomicCmpXchgInst(Call->getArgOperand(0), Call->getArgOperand(1),
167 Call->getArgOperand(2),
168 thawMemoryOrder(Call->getArgOperand(3)), SS,
169 Call);
170 break;
171 case Intrinsic::nacl_atomic_fence:
172 I = new FenceInst(M->getContext(),
173 thawMemoryOrder(Call->getArgOperand(0)), SS, Call);
174 break;
175 }
176 I->setName(Call->getName());
177 I->setDebugLoc(Call->getDebugLoc());
178 Call->replaceAllUsesWith(I);
179 Call->eraseFromParent();
180
181 return true;
182 }
183
184 unsigned alignmentFromPointer(const Value *Ptr) const {
185 const PointerType *PtrType = cast<PointerType>(Ptr->getType());
186 unsigned BitWidth = PtrType->getElementType()->getIntegerBitWidth();
187 return BitWidth / 8;
188 }
189
190 AtomicOrdering thawMemoryOrder(const Value *MemoryOrder) const {
191 NaCl::MemoryOrder MO = (NaCl::MemoryOrder)cast<Constant>(MemoryOrder)
192 ->getUniqueInteger().getLimitedValue();
193 switch (MO) {
194 // Only valid values should pass validation.
195 default: llvm_unreachable("unknown memory order");
196 case NaCl::MemoryOrderRelaxed: return Monotonic;
197 // TODO Consume is unspecified by LLVM's internal IR.
198 case NaCl::MemoryOrderConsume: return SequentiallyConsistent;
199 case NaCl::MemoryOrderAcquire: return Acquire;
200 case NaCl::MemoryOrderRelease: return Release;
201 case NaCl::MemoryOrderAcquireRelease: return AcquireRelease;
202 case NaCl::MemoryOrderSequentiallyConsistent: return SequentiallyConsistent;
203 }
204 }
205
206 AtomicRMWInst::BinOp thawRMWOperation(const Value *Operation) const {
207 NaCl::AtomicRMWOperation Op =
208 (NaCl::AtomicRMWOperation)cast<Constant>(Operation)->getUniqueInteger()
209 .getLimitedValue();
210 switch (Op) {
211 // Only valid values should pass validation.
212 default: llvm_unreachable("unknown atomic RMW operation");
213 case NaCl::AtomicAdd: return AtomicRMWInst::Add;
214 case NaCl::AtomicSub: return AtomicRMWInst::Sub;
215 case NaCl::AtomicOr: return AtomicRMWInst::Or;
216 case NaCl::AtomicAnd: return AtomicRMWInst::And;
217 case NaCl::AtomicXor: return AtomicRMWInst::Xor;
218 case NaCl::AtomicExchange: return AtomicRMWInst::Xchg;
219 }
220 }
221
222 AtomicCallResolver(const AtomicCallResolver &);
223 AtomicCallResolver &operator=(const AtomicCallResolver &);
224 };
43 } 225 }
44 226
45 bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, 227 bool ResolvePNaClIntrinsics::visitCalls(
46 Intrinsic::ID IntrinsicID, 228 ResolvePNaClIntrinsics::CallResolver &Resolver) {
47 const char *TargetFunctionName) {
48 Module *M = F.getParent();
49 bool Changed = false; 229 bool Changed = false;
50 Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); 230 Function *IntrinsicFunction = Resolver.getDeclaration();
51 231 if (!IntrinsicFunction)
52 if (!IntrinsicFunction) {
53 return false; 232 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 233
64 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), 234 for (Value::use_iterator UI = IntrinsicFunction->use_begin(),
65 UE = IntrinsicFunction->use_end(); UI != UE;) { 235 UE = IntrinsicFunction->use_end();
236 UI != UE;) {
66 // At this point, the only uses of the intrinsic can be calls, since 237 // 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. 238 // we assume this pass runs on bitcode that passed ABI verification.
68 CallInst *Call = dyn_cast<CallInst>(*UI++); 239 IntrinsicInst *Call = dyn_cast<IntrinsicInst>(*UI++);
69 240 if (!Call)
70 if (!Call) { 241 report_fatal_error("Expected use of intrinsic to be a call: " +
71 report_fatal_error( 242 Resolver.getName());
72 std::string("Expected use of intrinsic to be a call: ") + 243
73 Intrinsic::getName(IntrinsicID)); 244 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 } 245 }
84 246
85 return Changed; 247 return Changed;
86 } 248 }
87 249
88 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { 250 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) {
89 bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); 251 bool Changed = false;
90 Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); 252
253 SimpleCallResolver SetJmpResolver(F, Intrinsic::nacl_setjmp, "setjmp");
254 SimpleCallResolver LongJmpResolver(F, Intrinsic::nacl_longjmp, "longjmp");
255 Changed |= visitCalls(SetJmpResolver);
256 Changed |= visitCalls(LongJmpResolver);
257
258 NaCl::AtomicIntrinsics AI(F.getParent()->getContext());
259 NaCl::AtomicIntrinsics::View V = AI.allIntrinsicsAndOverloads();
260 for (NaCl::AtomicIntrinsics::View::iterator I = V.begin(), E = V.end();
261 I != E; ++I) {
262 AtomicCallResolver AtomicResolver(F, I);
263 Changed |= visitCalls(AtomicResolver);
264 }
265
91 return Changed; 266 return Changed;
92 } 267 }
93 268
94 char ResolvePNaClIntrinsics::ID = 0; 269 char ResolvePNaClIntrinsics::ID = 0;
95 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", 270 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics",
96 "Resolve PNaCl intrinsic calls", false, false) 271 "Resolve PNaCl intrinsic calls", false, false)
97 272
98 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { 273 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() {
99 return new ResolvePNaClIntrinsics(); 274 return new ResolvePNaClIntrinsics();
100 } 275 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/ReplacePtrsWithInts.cpp ('k') | lib/Transforms/NaCl/RewriteAtomics.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698