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 // 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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 |