Index: lib/Transforms/NaCl/RewriteAtomics.cpp |
diff --git a/lib/Transforms/NaCl/RewriteAtomics.cpp b/lib/Transforms/NaCl/RewriteAtomics.cpp |
index 652635ab0a2c85028e055476f90f6fa231af639a..858a4d7ca861d1ee0bbe3d0918cd9c18cf752d12 100644 |
--- a/lib/Transforms/NaCl/RewriteAtomics.cpp |
+++ b/lib/Transforms/NaCl/RewriteAtomics.cpp |
@@ -15,6 +15,7 @@ |
// |
//===----------------------------------------------------------------------===// |
+#include "llvm/ADT/Triple.h" |
#include "llvm/ADT/Twine.h" |
#include "llvm/IR/DataLayout.h" |
#include "llvm/IR/Function.h" |
@@ -28,6 +29,7 @@ |
#include "llvm/Support/CommandLine.h" |
#include "llvm/Support/Compiler.h" |
#include "llvm/Support/raw_ostream.h" |
+#include "llvm/Support/TargetRegistry.h" |
#include "llvm/Transforms/NaCl.h" |
#include <climits> |
#include <string> |
@@ -75,6 +77,8 @@ public: |
void visitAtomicRMWInst(AtomicRMWInst &I); |
void visitFenceInst(FenceInst &I); |
+ SmallVectorImpl<Function*>& getFunsWithExtraRMWOps() { return FunsWithExtraRMWOps; } |
+ |
private: |
Module &M; |
LLVMContext &C; |
@@ -82,6 +86,13 @@ private: |
NaCl::AtomicIntrinsics AI; |
bool ModifiedModule; |
+ /// These functions have atomic instructions which we expand with |
+ /// -atomic-expand. We collect them here so we don't have to check every |
+ /// instruction of every basicblock of every function in the module twice over |
+ /// the coarse of the pass (under the assumption that atomic operations are |
+ /// the expection rather than the rule). |
JF
2015/07/23 22:44:38
"exception"
|
+ SmallVector<Function*, 32> FunsWithExtraRMWOps; |
+ |
AtomicVisitor() = delete; |
AtomicVisitor(const AtomicVisitor &) = delete; |
AtomicVisitor &operator=(const AtomicVisitor &) = delete; |
@@ -162,9 +173,53 @@ INITIALIZE_PASS(RewriteAtomics, "nacl-rewrite-atomics", |
false, false) |
bool RewriteAtomics::runOnModule(Module &M) { |
+ // rewrite nand, (u)max, (u)min rmw atomics: |
+ // First we need a target machine to appease its lordship: |
+ |
+ // Get the target specific parser. |
+ std::string Error; |
+ Triple TheTriple = Triple("i686-none-nacl"); |
+ const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, |
+ Error); |
+ if (!TheTarget) { |
+ errs() << "Looking up 'i686-none-nacl':" << ": " << Error; |
+ report_fatal_error("Did you forget to initialize the x86 target?"); |
+ } |
+ |
+ // Create the target machine: |
+ std::unique_ptr<TargetMachine> Target( |
+ TheTarget->createTargetMachine(TheTriple.getTriple(), "generic", "", |
+ TargetOptions(), Reloc::Default, |
+ CodeModel::Default, CodeGenOpt::Default)); |
+ assert(Target != nullptr); |
+ |
+ std::unique_ptr<FunctionPass> AtomicRMWExpander |
+ (createAtomicExpandPass(Target.get())); |
+ |
+ |
AtomicVisitor AV(M, *this); |
AV.visit(M); |
- return AV.modifiedModule(); |
+ |
+ bool Changed = AV.modifiedModule(); |
+ |
+ // Expand any leftover RMW atomics: |
+ // This is done after because otherwise -atomic-expand will expand stuff we're |
+ // capable of expanding, leaving us with less efficient code. |
+ const size_t PrevLen = AV.getFunsWithExtraRMWOps().size(); |
+ for(auto *F : AV.getFunsWithExtraRMWOps()) { |
+ const bool Expanded = AtomicRMWExpander->runOnFunction(*F); |
+ (void)Expanded; |
+ assert(Expanded); |
+ // revisit the function, rewriting cmpxchg to the corresponding |
+ // llvm.nacl.etc.etc. |
+ AV.visit(*F); |
+ Changed = true; |
+ } |
+ // assert that -atomic-expand didn't leave things we can't expand. |
+ (void)PrevLen; |
+ assert(PrevLen == AV.getFunsWithExtraRMWOps().size()); |
+ |
+ return Changed; |
} |
template <class Instruction> |
@@ -347,7 +402,11 @@ void AtomicVisitor::visitStoreInst(StoreInst &I) { |
void AtomicVisitor::visitAtomicRMWInst(AtomicRMWInst &I) { |
NaCl::AtomicRMWOperation Op; |
switch (I.getOperation()) { |
- default: report_fatal_error("unsupported atomicrmw operation: " + ToStr(I)); |
+ default: { |
+ // delegate to -atomic-expand |
+ FunsWithExtraRMWOps.push_back(I.getParent()->getParent()); |
+ return; |
+ } |
case AtomicRMWInst::Add: Op = NaCl::AtomicAdd; break; |
case AtomicRMWInst::Sub: Op = NaCl::AtomicSub; break; |
case AtomicRMWInst::And: Op = NaCl::AtomicAnd; break; |