OLD | NEW |
---|---|
1 //===- RewriteAtomics.cpp - Stabilize instructions used for concurrency ---===// | 1 //===- RewriteAtomics.cpp - Stabilize instructions used for concurrency ---===// |
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 encodes atomics, volatiles and fences using NaCl intrinsics | 10 // This pass encodes atomics, volatiles and fences using NaCl intrinsics |
11 // instead of LLVM's regular IR instructions. | 11 // instead of LLVM's regular IR instructions. |
12 // | 12 // |
13 // All of the above are transformed into one of the | 13 // All of the above are transformed into one of the |
14 // @llvm.nacl.atomic.* intrinsics. | 14 // @llvm.nacl.atomic.* intrinsics. |
15 // | 15 // |
16 //===----------------------------------------------------------------------===// | 16 //===----------------------------------------------------------------------===// |
17 | 17 |
18 #include "llvm/ADT/Triple.h" | |
18 #include "llvm/ADT/Twine.h" | 19 #include "llvm/ADT/Twine.h" |
19 #include "llvm/IR/DataLayout.h" | 20 #include "llvm/IR/DataLayout.h" |
20 #include "llvm/IR/Function.h" | 21 #include "llvm/IR/Function.h" |
21 #include "llvm/IR/InlineAsm.h" | 22 #include "llvm/IR/InlineAsm.h" |
22 #include "llvm/IR/InstVisitor.h" | 23 #include "llvm/IR/InstVisitor.h" |
23 #include "llvm/IR/Instructions.h" | 24 #include "llvm/IR/Instructions.h" |
24 #include "llvm/IR/Intrinsics.h" | 25 #include "llvm/IR/Intrinsics.h" |
25 #include "llvm/IR/Module.h" | 26 #include "llvm/IR/Module.h" |
26 #include "llvm/IR/NaClAtomicIntrinsics.h" | 27 #include "llvm/IR/NaClAtomicIntrinsics.h" |
27 #include "llvm/Pass.h" | 28 #include "llvm/Pass.h" |
28 #include "llvm/Support/CommandLine.h" | 29 #include "llvm/Support/CommandLine.h" |
29 #include "llvm/Support/Compiler.h" | 30 #include "llvm/Support/Compiler.h" |
30 #include "llvm/Support/raw_ostream.h" | 31 #include "llvm/Support/raw_ostream.h" |
32 #include "llvm/Support/TargetRegistry.h" | |
31 #include "llvm/Transforms/NaCl.h" | 33 #include "llvm/Transforms/NaCl.h" |
32 #include <climits> | 34 #include <climits> |
33 #include <string> | 35 #include <string> |
34 | 36 |
35 using namespace llvm; | 37 using namespace llvm; |
36 | 38 |
37 // TODO(jfb) Keep the default of this option to true for Chrome 42, and change | 39 // TODO(jfb) Keep the default of this option to true for Chrome 42, and change |
38 // it to false for Chrome 43. This allows the PNaCl translator to be | 40 // it to false for Chrome 43. This allows the PNaCl translator to be |
39 // updated before the SDK starts emitting atomic memory orders that | 41 // updated before the SDK starts emitting atomic memory orders that |
40 // the old translator rejected. | 42 // the old translator rejected. |
(...skipping 121 matching lines...) Loading... | |
162 }; | 164 }; |
163 } | 165 } |
164 | 166 |
165 char RewriteAtomics::ID = 0; | 167 char RewriteAtomics::ID = 0; |
166 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", | 168 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", |
167 "rewrite atomics, volatiles and fences into stable " | 169 "rewrite atomics, volatiles and fences into stable " |
168 "@llvm.nacl.atomics.* intrinsics", | 170 "@llvm.nacl.atomics.* intrinsics", |
169 false, false) | 171 false, false) |
170 | 172 |
171 bool RewriteAtomics::runOnModule(Module &M) { | 173 bool RewriteAtomics::runOnModule(Module &M) { |
174 // rewrite nand, (u)max, (u)min rmw atomics: | |
175 // First we need a target machine to appease its lordship: | |
176 | |
177 // Get the target specific parser. | |
178 std::string Error; | |
179 Triple TheTriple = Triple("i686-none-nacl"); | |
JF
2015/02/16 21:09:01
Does it need to be i686? Can you just have unknown
Richard Diamond
2015/02/16 23:36:31
The other option is `x86_64`. Arm expands into som
| |
180 const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, | |
181 Error); | |
182 if (!TheTarget) { | |
183 errs() << "Looking up 'i686-none-nacl':" << ": " << Error; | |
184 report_fatal_error("Did you forget to initialize the x86 target?"); | |
185 } | |
186 | |
187 // Create the target machine: | |
188 std::unique_ptr<TargetMachine> target( | |
189 TheTarget->createTargetMachine(TheTriple.getTriple(), "generic", "i686", | |
190 TargetOptions(), Reloc::Default, | |
191 CodeModel::Default, CodeGenOpt::Default)); | |
192 | |
193 std::unique_ptr<FunctionPass> AtomicRMWExpander | |
194 (createAtomicExpandPass(target.get())); | |
195 | |
196 | |
172 AtomicVisitor AV(M, *this); | 197 AtomicVisitor AV(M, *this); |
173 AV.visit(M); | 198 AV.visit(M); |
174 return AV.modifiedModule(); | 199 |
200 bool Changed = AV.modifiedModule(); | |
201 | |
202 // Expand any leftover RMW atomics: | |
203 // This is done after because otherwise -atomic-expand will expand stuff we're | |
204 // capable of expanding, leaving us with less efficient code. | |
205 for(auto &F : M.functions()) { | |
206 if (AtomicRMWExpander->runOnFunction(F)) { | |
207 // revisit the function, rewriting cmpxchg to the corresponding | |
208 // llvm.nacl.etc.etc. | |
209 AV.visit(F); | |
210 } | |
211 } | |
JF
2015/02/16 21:09:01
Could you invoke the -atomic-expand pass after thi
Richard Diamond
2015/02/16 23:36:31
No, because it would force this kluge onto users.
| |
212 return Changed; | |
175 } | 213 } |
176 | 214 |
177 template <class Instruction> | 215 template <class Instruction> |
178 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I, | 216 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I, |
179 AtomicOrdering O) const { | 217 AtomicOrdering O) const { |
180 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid; | 218 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid; |
181 | 219 |
182 // TODO Volatile load/store are promoted to sequentially consistent | 220 // TODO Volatile load/store are promoted to sequentially consistent |
183 // for now. We could do something weaker. | 221 // for now. We could do something weaker. |
184 if (const LoadInst *L = dyn_cast<LoadInst>(&I)) { | 222 if (const LoadInst *L = dyn_cast<LoadInst>(&I)) { |
(...skipping 162 matching lines...) Loading... | |
347 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, | 385 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, |
348 Args); | 386 Args); |
349 } | 387 } |
350 | 388 |
351 /// %res = atomicrmw OP T* %ptr, T %val memory_order | 389 /// %res = atomicrmw OP T* %ptr, T %val memory_order |
352 /// becomes: | 390 /// becomes: |
353 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order) | 391 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order) |
354 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { | 392 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { |
355 NaCl::AtomicRMWOperation Op; | 393 NaCl::AtomicRMWOperation Op; |
356 switch (I.getOperation()) { | 394 switch (I.getOperation()) { |
357 default: report_fatal_error("unsupported atomicrmw operation: " + ToStr(I)); | 395 default: return; // -atomic-expand will handle it. |
JF
2015/02/16 21:09:01
It would be good to assert that the second pass of
Richard Diamond
2015/02/16 23:36:31
The second pass never reaches this. The other RMW
| |
358 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; | 396 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; |
359 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; | 397 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; |
360 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; | 398 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; |
361 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break; | 399 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break; |
362 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break; | 400 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break; |
363 case AtomicRMWInst::Xchg: Op = NaCl::AtomicExchange; break; | 401 case AtomicRMWInst::Xchg: Op = NaCl::AtomicExchange; break; |
364 } | 402 } |
365 PointerHelper<AtomicRMWInst> PH(*this, I); | 403 PointerHelper<AtomicRMWInst> PH(*this, I); |
366 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = | 404 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = |
367 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET); | 405 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET); |
(...skipping 59 matching lines...) Loading... | |
427 ArrayRef<Value *>()); | 465 ArrayRef<Value *>()); |
428 } else { | 466 } else { |
429 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = | 467 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = |
430 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T); | 468 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T); |
431 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())}; | 469 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())}; |
432 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args); | 470 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args); |
433 } | 471 } |
434 } | 472 } |
435 | 473 |
436 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); } | 474 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); } |
OLD | NEW |