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 27 matching lines...) Expand all Loading... | |
68 ModifiedModule(false) {} | 70 ModifiedModule(false) {} |
69 ~AtomicVisitor() {} | 71 ~AtomicVisitor() {} |
70 bool modifiedModule() const { return ModifiedModule; } | 72 bool modifiedModule() const { return ModifiedModule; } |
71 | 73 |
72 void visitLoadInst(LoadInst &I); | 74 void visitLoadInst(LoadInst &I); |
73 void visitStoreInst(StoreInst &I); | 75 void visitStoreInst(StoreInst &I); |
74 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); | 76 void visitAtomicCmpXchgInst(AtomicCmpXchgInst &I); |
75 void visitAtomicRMWInst(AtomicRMWInst &I); | 77 void visitAtomicRMWInst(AtomicRMWInst &I); |
76 void visitFenceInst(FenceInst &I); | 78 void visitFenceInst(FenceInst &I); |
77 | 79 |
80 SmallVectorImpl<Function*>& getFunsWithExtraRMWOps() { return FunsWithExtraRMW Ops; } | |
81 | |
78 private: | 82 private: |
79 Module &M; | 83 Module &M; |
80 LLVMContext &C; | 84 LLVMContext &C; |
81 const DataLayout TD; | 85 const DataLayout TD; |
82 NaCl::AtomicIntrinsics AI; | 86 NaCl::AtomicIntrinsics AI; |
83 bool ModifiedModule; | 87 bool ModifiedModule; |
84 | 88 |
89 /// These functions have atomic instructions which we expand with | |
90 /// -atomic-expand. We collect them here so we don't have to check every | |
91 /// instruction of every basicblock of every function in the module twice over | |
92 /// the coarse of the pass (under the assumption that atomic operations are | |
93 /// the expection rather than the rule). | |
JF
2015/07/23 22:44:38
"exception"
| |
94 SmallVector<Function*, 32> FunsWithExtraRMWOps; | |
95 | |
85 AtomicVisitor() = delete; | 96 AtomicVisitor() = delete; |
86 AtomicVisitor(const AtomicVisitor &) = delete; | 97 AtomicVisitor(const AtomicVisitor &) = delete; |
87 AtomicVisitor &operator=(const AtomicVisitor &) = delete; | 98 AtomicVisitor &operator=(const AtomicVisitor &) = delete; |
88 | 99 |
89 /// Create an integer constant holding a NaCl::MemoryOrder that can be | 100 /// Create an integer constant holding a NaCl::MemoryOrder that can be |
90 /// passed as an argument to one of the @llvm.nacl.atomic.* | 101 /// passed as an argument to one of the @llvm.nacl.atomic.* |
91 /// intrinsics. This function may strengthen the ordering initially | 102 /// intrinsics. This function may strengthen the ordering initially |
92 /// specified by the instruction \p I for stability purpose. | 103 /// specified by the instruction \p I for stability purpose. |
93 template <class Instruction> | 104 template <class Instruction> |
94 ConstantInt *freezeMemoryOrder(const Instruction &I, AtomicOrdering O) const; | 105 ConstantInt *freezeMemoryOrder(const Instruction &I, AtomicOrdering O) const; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 }; | 166 }; |
156 } | 167 } |
157 | 168 |
158 char RewriteAtomics::ID = 0; | 169 char RewriteAtomics::ID = 0; |
159 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", | 170 INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", |
160 "rewrite atomics, volatiles and fences into stable " | 171 "rewrite atomics, volatiles and fences into stable " |
161 "@llvm.nacl.atomics.* intrinsics", | 172 "@llvm.nacl.atomics.* intrinsics", |
162 false, false) | 173 false, false) |
163 | 174 |
164 bool RewriteAtomics::runOnModule(Module &M) { | 175 bool RewriteAtomics::runOnModule(Module &M) { |
176 // rewrite nand, (u)max, (u)min rmw atomics: | |
177 // First we need a target machine to appease its lordship: | |
178 | |
179 // Get the target specific parser. | |
180 std::string Error; | |
181 Triple TheTriple = Triple("i686-none-nacl"); | |
182 const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, | |
183 Error); | |
184 if (!TheTarget) { | |
185 errs() << "Looking up 'i686-none-nacl':" << ": " << Error; | |
186 report_fatal_error("Did you forget to initialize the x86 target?"); | |
187 } | |
188 | |
189 // Create the target machine: | |
190 std::unique_ptr<TargetMachine> Target( | |
191 TheTarget->createTargetMachine(TheTriple.getTriple(), "generic", "", | |
192 TargetOptions(), Reloc::Default, | |
193 CodeModel::Default, CodeGenOpt::Default)); | |
194 assert(Target != nullptr); | |
195 | |
196 std::unique_ptr<FunctionPass> AtomicRMWExpander | |
197 (createAtomicExpandPass(Target.get())); | |
198 | |
199 | |
165 AtomicVisitor AV(M, *this); | 200 AtomicVisitor AV(M, *this); |
166 AV.visit(M); | 201 AV.visit(M); |
167 return AV.modifiedModule(); | 202 |
203 bool Changed = AV.modifiedModule(); | |
204 | |
205 // Expand any leftover RMW atomics: | |
206 // This is done after because otherwise -atomic-expand will expand stuff we're | |
207 // capable of expanding, leaving us with less efficient code. | |
208 const size_t PrevLen = AV.getFunsWithExtraRMWOps().size(); | |
209 for(auto *F : AV.getFunsWithExtraRMWOps()) { | |
210 const bool Expanded = AtomicRMWExpander->runOnFunction(*F); | |
211 (void)Expanded; | |
212 assert(Expanded); | |
213 // revisit the function, rewriting cmpxchg to the corresponding | |
214 // llvm.nacl.etc.etc. | |
215 AV.visit(*F); | |
216 Changed = true; | |
217 } | |
218 // assert that -atomic-expand didn't leave things we can't expand. | |
219 (void)PrevLen; | |
220 assert(PrevLen == AV.getFunsWithExtraRMWOps().size()); | |
221 | |
222 return Changed; | |
168 } | 223 } |
169 | 224 |
170 template <class Instruction> | 225 template <class Instruction> |
171 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I, | 226 ConstantInt *AtomicVisitor::freezeMemoryOrder(const Instruction &I, |
172 AtomicOrdering O) const { | 227 AtomicOrdering O) const { |
173 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid; | 228 NaCl::MemoryOrder AO = NaCl::MemoryOrderInvalid; |
174 | 229 |
175 // TODO Volatile load/store are promoted to sequentially consistent | 230 // TODO Volatile load/store are promoted to sequentially consistent |
176 // for now. We could do something weaker. | 231 // for now. We could do something weaker. |
177 if (const LoadInst *L = dyn_cast<LoadInst>(&I)) { | 232 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, | 395 replaceInstructionWithIntrinsicCall(I, Intrinsic, PH.OriginalPET, PH.PET, |
341 Args); | 396 Args); |
342 } | 397 } |
343 | 398 |
344 /// %res = atomicrmw OP T* %ptr, T %val memory_order | 399 /// %res = atomicrmw OP T* %ptr, T %val memory_order |
345 /// becomes: | 400 /// becomes: |
346 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order) | 401 /// %res = call T @llvm.nacl.atomic.rmw.i<size>(OP, %ptr, %val, memory_order) |
347 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { | 402 void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { |
348 NaCl::AtomicRMWOperation Op; | 403 NaCl::AtomicRMWOperation Op; |
349 switch (I.getOperation()) { | 404 switch (I.getOperation()) { |
350 default: report_fatal_error("unsupported atomicrmw operation: " + ToStr(I)); | 405 default: { |
406 // delegate to -atomic-expand | |
407 FunsWithExtraRMWOps.push_back(I.getParent()->getParent()); | |
408 return; | |
409 } | |
351 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; | 410 case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; |
352 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; | 411 case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; |
353 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; | 412 case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; |
354 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break; | 413 case AtomicRMWInst::Or: Op = NaCl::AtomicOr; break; |
355 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break; | 414 case AtomicRMWInst::Xor: Op = NaCl::AtomicXor; break; |
356 case AtomicRMWInst::Xchg: Op = NaCl::AtomicExchange; break; | 415 case AtomicRMWInst::Xchg: Op = NaCl::AtomicExchange; break; |
357 } | 416 } |
358 PointerHelper<AtomicRMWInst> PH(*this, I); | 417 PointerHelper<AtomicRMWInst> PH(*this, I); |
359 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = | 418 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = |
360 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET); | 419 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_rmw, PH.PET); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 ArrayRef<Value *>()); | 479 ArrayRef<Value *>()); |
421 } else { | 480 } else { |
422 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = | 481 const NaCl::AtomicIntrinsics::AtomicIntrinsic *Intrinsic = |
423 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T); | 482 findAtomicIntrinsic(I, Intrinsic::nacl_atomic_fence, T); |
424 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())}; | 483 Value *Args[] = {freezeMemoryOrder(I, I.getOrdering())}; |
425 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args); | 484 replaceInstructionWithIntrinsicCall(I, Intrinsic, T, T, Args); |
426 } | 485 } |
427 } | 486 } |
428 | 487 |
429 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); } | 488 ModulePass *llvm::createRewriteAtomicsPass() { return new RewriteAtomics(); } |
OLD | NEW |