Chromium Code Reviews| 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 |