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

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: Update PNaClLangRef to reflect the implementation work I will now go forward with. 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 pass.
14 // They are separate because one is a ModulePass and the other is a 14 // They are separate because one is a ModulePass and the other is a
15 // FunctionPass. 15 // 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"
21 #include "llvm/IR/Intrinsics.h" 22 #include "llvm/IR/Intrinsics.h"
22 #include "llvm/IR/Module.h" 23 #include "llvm/IR/Module.h"
24 #include "llvm/IR/NaClIntrinsics.h"
25 #include "llvm/IR/Value.h"
23 #include "llvm/Pass.h" 26 #include "llvm/Pass.h"
27 #include "llvm/Support/MathExtras.h"
24 #include "llvm/Transforms/NaCl.h" 28 #include "llvm/Transforms/NaCl.h"
25 29
26 using namespace llvm; 30 using namespace llvm;
27 31
28 namespace { 32 namespace {
29 class ResolvePNaClIntrinsics : public FunctionPass { 33 class ResolvePNaClIntrinsics : public FunctionPass {
34 public:
35 ResolvePNaClIntrinsics() : FunctionPass(ID) {
36 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry());
37 }
38
39 static char ID;
40 virtual bool runOnFunction(Function &F);
41
42 // Interface specifying how calls should be resolved.
43 class CallResolver {
30 public: 44 public:
31 ResolvePNaClIntrinsics() : FunctionPass(ID) { 45 // Called once the intrinsic's declaration is found in the module.
32 initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); 46 void Init() { DoInit(); }
33 } 47 // Called once per call to the intrinsic in the module.
34 48 bool Resolve(CallInst *Call) {
35 static char ID; 49 // To be a well-behaving FunctionPass, don't touch uses in other
36 virtual bool runOnFunction(Function &F); 50 // functions. These will be handled when the pass manager gets
51 // to those functions.
52 if (Call->getParent()->getParent() == &F)
53 return DoResolve(Call);
54 return false;
55 }
56 Function *getDeclaration() const {
57 return Intrinsic::getDeclaration(M, IntrinsicID);
58 }
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 virtual void DoInit() = 0;
70 virtual bool DoResolve(CallInst *Call) = 0;
71
37 private: 72 private:
38 // Some intrinsic calls are resolved simply by replacing the call with a 73 CallResolver(const CallResolver &);
39 // call to an alternative function with exactly the same type. 74 CallResolver &operator=(const CallResolver &);
40 bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID,
41 const char *TargetFunctionName);
42 }; 75 };
76
77 private:
78 // Walk calls matching the resolver's declaration, and invoke the
79 // CallResolver methods on each of them.
80 bool walkCalls(CallResolver &Resolver);
81 };
82
83 // Rewrite intrinsic calls to another function.
84 class SimpleCallResolver : public ResolvePNaClIntrinsics::CallResolver {
85 public:
86 SimpleCallResolver(Function &F, Intrinsic::ID IntrinsicID,
87 const char *TargetFunctionName)
88 : CallResolver(F, IntrinsicID), TargetFunctionName(TargetFunctionName),
89 TargetFunction(NULL) {}
90 virtual ~SimpleCallResolver() {}
91
92 private:
93 const char *TargetFunctionName;
94 Function *TargetFunction;
95
96 virtual void DoInit() {
97 // Expect to find the target function for this intrinsic already declared.
98 TargetFunction = M->getFunction(TargetFunctionName);
99 if (!TargetFunction)
100 report_fatal_error(std::string(
101 "Expected to find external declaration of ") + TargetFunctionName);
102 }
103 virtual bool DoResolve(CallInst *Call) {
104 Call->setCalledFunction(TargetFunction);
105 return true;
106 }
107
108 SimpleCallResolver(const SimpleCallResolver &);
109 SimpleCallResolver &operator=(const SimpleCallResolver &);
110 };
111
112 // Rewrite atomic intrinsics to LLVM IR instructions.
113 class AtomicCallResolver : public ResolvePNaClIntrinsics::CallResolver {
114 public:
115 AtomicCallResolver(Function &F, Intrinsic::ID IntrinsicID)
116 : CallResolver(F, IntrinsicID) {}
117 virtual ~AtomicCallResolver() {}
118
119 private:
120 virtual void DoInit() {}
121 virtual bool DoResolve(CallInst *Call) {
122 // Assume the @llvm.nacl.atomic.<size> intrinsics follow the PNaCl
123 // ABI: this should have been checked by the verifier.
124 uint64_t Op(cast<Constant>(Call->getArgOperand(0))
125 ->getUniqueInteger().getLimitedValue());
126 Value *Ptr = Call->getArgOperand(1);
127 Value *Val = Call->getArgOperand(2);
128 Value *Old = Call->getArgOperand(3);
129 uint64_t MemoryOrder(cast<Constant>(Call->getArgOperand(4))
130 ->getUniqueInteger().getLimitedValue());
131
132 AtomicRMWInst::BinOp RMWOp;
133 switch (Op) {
134 default: RMWOp = AtomicRMWInst::BAD_BINOP; break;
135 case NaCl::AtomicAdd: RMWOp = AtomicRMWInst::Add; break;
136 case NaCl::AtomicSub: RMWOp = AtomicRMWInst::Sub; break;
137 case NaCl::AtomicOr: RMWOp = AtomicRMWInst::Or; break;
138 case NaCl::AtomicAnd: RMWOp = AtomicRMWInst::And; break;
139 case NaCl::AtomicXor: RMWOp = AtomicRMWInst::Xor; break;
140 case NaCl::AtomicXchg: RMWOp = AtomicRMWInst::Xchg; break;
141 }
142 AtomicOrdering Order;
143 switch (MemoryOrder) {
144 // Conservatively use the strongest ordering.
145 default: Order = SequentiallyConsistent; break;
146 case NaCl::MemoryOrderRelaxed: Order = Unordered; break;
147 // TODO Consume is unspecified by LLVM's internal IR.
148 case NaCl::MemoryOrderConsume: Order = SequentiallyConsistent; break;
149 case NaCl::MemoryOrderAcquire: Order = Acquire; break;
150 case NaCl::MemoryOrderRelease: Order = Release; break;
151 case NaCl::MemoryOrderAcquireRelease: Order = AcquireRelease; break;
152 case NaCl::MemoryOrderSequentiallyConsistent:
153 Order = SequentiallyConsistent; break;
154 }
155 const Twine Name("");
156 bool isVolatile = false;
157 SynchronizationScope SS = CrossThread;
158 bool hasUses;
159 Instruction *I;
160
161 for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) {
162 if (IntrinsicID != NaCl::AtomicIntrinsics[II].ID)
163 continue;
164
165 unsigned BitSize = NaCl::AtomicIntrinsics[II].BitSize;
166 unsigned Align = 1 << (CountTrailingZeros_32(BitSize) - 3);
167 switch (Op) {
168 default:
169 llvm_unreachable("invalid atomic operation");
170 case NaCl::AtomicLoad:
171 hasUses = true;
172 I = new LoadInst(Ptr, Name, isVolatile, Align, Order, SS, Call);
173 break;
174 case NaCl::AtomicStore:
175 hasUses = false;
176 I = new StoreInst(Val, Ptr, isVolatile, Align, Order, SS, Call);
177 break;
178 case NaCl::AtomicAdd:
179 case NaCl::AtomicSub:
180 case NaCl::AtomicOr:
181 case NaCl::AtomicAnd:
182 case NaCl::AtomicXor:
183 case NaCl::AtomicXchg:
184 hasUses = true;
185 I = new AtomicRMWInst(RMWOp, Ptr, Val, Order, SS, Call);
186 break;
187 case NaCl::AtomicCmpXchg:
188 hasUses = true;
189 I = new AtomicCmpXchgInst(Ptr, Old, Val, Order, SS, Call);
190 break;
191 case NaCl::AtomicFence:
192 hasUses = false;
193 I = new FenceInst(M->getContext(), Order, SS, Call);
194 break;
195 }
196 I->setDebugLoc(Call->getDebugLoc());
197 if (hasUses)
198 Call->replaceAllUsesWith(I);
199 Call->eraseFromParent();
200 }
201 return true;
202 }
203
204 AtomicCallResolver(const AtomicCallResolver &);
205 AtomicCallResolver &operator=(const AtomicCallResolver &);
206 };
43 } 207 }
44 208
45 bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, 209 bool ResolvePNaClIntrinsics::walkCalls(
46 Intrinsic::ID IntrinsicID, 210 ResolvePNaClIntrinsics::CallResolver &Resolver) {
47 const char *TargetFunctionName) {
48 Module *M = F.getParent();
49 bool Changed = false; 211 bool Changed = false;
50 Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); 212 Function *IntrinsicFunction = Resolver.getDeclaration();
51 213 if (!IntrinsicFunction)
52 if (!IntrinsicFunction) {
53 return false; 214 return false;
54 } 215
55 216 Resolver.Init();
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 217
64 for (Value::use_iterator UI = IntrinsicFunction->use_begin(), 218 for (Value::use_iterator UI = IntrinsicFunction->use_begin(),
65 UE = IntrinsicFunction->use_end(); UI != UE;) { 219 UE = IntrinsicFunction->use_end();
220 UI != UE;) {
66 // At this point, the only uses of the intrinsic can be calls, since 221 // 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. 222 // we assume this pass runs on bitcode that passed ABI verification.
68 CallInst *Call = dyn_cast<CallInst>(*UI++); 223 CallInst *Call = dyn_cast<CallInst>(*UI++);
69 224 if (!Call)
70 if (!Call) { 225 report_fatal_error("Expected use of intrinsic to be a call: " +
71 report_fatal_error( 226 Resolver.getName());
72 std::string("Expected use of intrinsic to be a call: ") + 227
73 Intrinsic::getName(IntrinsicID)); 228 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 } 229 }
84 230
85 return Changed; 231 return Changed;
86 } 232 }
87 233
88 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { 234 bool ResolvePNaClIntrinsics::runOnFunction(Function &F) {
89 bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); 235 bool Changed = false;
90 Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); 236
237 SimpleCallResolver SetJmpResolver(F, Intrinsic::nacl_setjmp, "setjmp");
238 SimpleCallResolver LongJmpResolver(F, Intrinsic::nacl_longjmp, "longjmp");
239 Changed |= walkCalls(SetJmpResolver);
240 Changed |= walkCalls(LongJmpResolver);
241
242 for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) {
243 AtomicCallResolver AtomicResolver(F, NaCl::AtomicIntrinsics[II].ID);
244 Changed |= walkCalls(AtomicResolver);
245 }
246
91 return Changed; 247 return Changed;
92 } 248 }
93 249
94 char ResolvePNaClIntrinsics::ID = 0; 250 char ResolvePNaClIntrinsics::ID = 0;
95 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", 251 INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics",
96 "Resolve PNaCl intrinsic calls", false, false) 252 "Resolve PNaCl intrinsic calls", false, false)
97 253
98 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { 254 FunctionPass *llvm::createResolvePNaClIntrinsicsPass() {
99 return new ResolvePNaClIntrinsics(); 255 return new ResolvePNaClIntrinsics();
100 } 256 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698