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 static cl::opt<bool> PNaClMemoryOrderSeqCstOnly( | 39 static cl::opt<bool> PNaClMemoryOrderSeqCstOnly( |
38 "pnacl-memory-order-seq-cst-only", | 40 "pnacl-memory-order-seq-cst-only", |
39 cl::desc("PNaCl should upgrade all atomic memory orders to seq_cst"), | 41 cl::desc("PNaCl should upgrade all atomic memory orders to seq_cst"), |
40 cl::init(false)); | 42 cl::init(false)); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 }; | 157 }; |
156 } | 158 } |
157 | 159 |
158 char RewriteAtomics::ID = 0; | 160 char RewriteAtomics::ID = 0; |
159 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", | 161 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", |
160 "rewrite atomics, volatiles and fences into stable " | 162 "rewrite atomics, volatiles and fences into stable " |
161 "@llvm.nacl.atomics.* intrinsics", | 163 "@llvm.nacl.atomics.* intrinsics", |
162 false, false) | 164 false, false) |
163 | 165 |
164 bool RewriteAtomics::runOnModule(Module &M) { | 166 bool RewriteAtomics::runOnModule(Module &M) { |
167 // rewrite nand, (u)max, (u)min rmw atomics: | |
168 // First we need a target machine to appease its lordship: | |
169 | |
170 // Get the target specific parser. | |
171 std::string Error; | |
172 Triple TheTriple = Triple("i686-none-nacl"); | |
173 const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, | |
174 Error); | |
175 if (!TheTarget) { | |
176 errs() << "Looking up 'i686-none-nacl':" << ": " << Error; | |
177 report_fatal_error("Did you forget to initialize the x86 target?"); | |
178 } | |
179 | |
180 // Create the target machine: | |
181 std::unique_ptr<TargetMachine> Target( | |
182 TheTarget->createTargetMachine(TheTriple.getTriple(), "generic", "", | |
183 TargetOptions(), Reloc::Default, | |
184 CodeModel::Default, CodeGenOpt::Default)); | |
185 assert(Target != nullptr); | |
186 | |
187 std::unique_ptr<FunctionPass> AtomicRMWExpander | |
188 (createAtomicExpandPass(Target.get())); | |
JF
2015/07/10 18:07:32
Could the pass instead go in lib/Transforms/NaCl/P
Richard Diamond
2015/07/10 21:08:17
No, because -atomic-expand will expand stuff that
| |
189 | |
190 | |
165 AtomicVisitor AV(M, *this); | 191 AtomicVisitor AV(M, *this); |
166 AV.visit(M); | 192 AV.visit(M); |
167 return AV.modifiedModule(); | 193 |
194 bool Changed = AV.modifiedModule(); | |
195 | |
196 // Expand any leftover RMW atomics: | |
197 // This is done after because otherwise -atomic-expand will expand stuff we're | |
198 // capable of expanding, leaving us with less efficient code. | |
199 for(auto &F : M.functions()) { | |
200 if (AtomicRMWExpander->runOnFunction(F)) { | |
201 // revisit the function, rewriting cmpxchg to the corresponding | |
202 // llvm.nacl.etc.etc. | |
203 AV.visit(F); | |
204 Changed = true; | |
205 } | |
206 } | |
207 return Changed; | |
168 } | 208 } |
169 | 209 |
170 template <class Instruction> | 210 template <class Instruction> |
171 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I, | 211 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I, |
172 AtomicOrdering O) const { | 212 AtomicOrdering O) const { |
173 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid; | 213 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid; |
174 | 214 |
175 // TODO Volatile load/store are promoted to sequentially consistent | 215 // TODO Volatile load/store are promoted to sequentially consistent |
176 // for now. We could do something weaker. | 216 // for now. We could do something weaker. |
177 if (const LoadInst *L = dyn_cast<LoadInst>(&I)) { | 217 if (const LoadInst *L = dyn_cast<LoadInst>(&I)) { |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
340 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, | 380 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, |
341 Args); | 381 Args); |
342 } | 382 } |
343 | 383 |
344 /// %res = atomicrmw OP T* %ptr, T %val memory_order | 384 /// %res = atomicrmw OP T* %ptr, T %val memory_order |
345 /// becomes: | 385 /// becomes: |
346 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order) | 386 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order) |
347 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { | 387 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { |
348 NaCl::AtomicRMWOperation Op; | 388 NaCl::AtomicRMWOperation Op; |
349 switch (I.getOperation()) { | 389 switch (I.getOperation()) { |
350 default: report_fatal_error("unsupported atomicrmw operation: " + ToStr(I)); | 390 default: return; // -atomic-expand will handle it. |
351 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; | 391 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; |
352 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; | 392 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; |
353 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; | 393 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; |
354 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break; | 394 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break; |
355 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break; | 395 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break; |
356 case AtomicRMWInst::Xchg: Op = NaCl::AtomicExchange; break; | 396 case AtomicRMWInst::Xchg: Op = NaCl::AtomicExchange; break; |
357 } | 397 } |
358 PointerHelper<AtomicRMWInst> PH(*this, I); | 398 PointerHelper<AtomicRMWInst> PH(*this, I); |
359 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = | 399 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = |
360 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET); | 400 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 ArrayRef<Value *>()); | 460 ArrayRef<Value *>()); |
421 } else { | 461 } else { |
422 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = | 462 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = |
423 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T); | 463 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T); |
424 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())}; | 464 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())}; |
425 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args); | 465 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args); |
426 } | 466 } |
427 } | 467 } |
428 | 468 |
429 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); } | 469 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); } |
OLD | NEW |