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

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

Powered by Google App Engine
This is Rietveld 408576698