Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(820)

Unified Diff: lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp

Issue 17777004: Concurrency support for PNaCl ABI (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Fix bad merge. Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Transforms/NaCl/ReplacePtrsWithInts.cpp ('k') | lib/Transforms/NaCl/RewriteAtomics.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
diff --git a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
index e4efeb67c3c3c24c5ca1103f960338dea0c134f6..9b526a102a00e291336ff87695d7a19c475bcb97 100644
--- a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
+++ b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
@@ -10,84 +10,259 @@
// This pass resolves calls to PNaCl stable bitcode intrinsics. It is
// normally run in the PNaCl translator.
//
-// Running AddPNaClExternalDeclsPass is a precondition for running this pass.
-// They are separate because one is a ModulePass and the other is a
-// FunctionPass.
+// Running AddPNaClExternalDeclsPass is a precondition for running this
+// pass. They are separate because one is a ModulePass and the other is
+// a FunctionPass.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Constant.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/NaClAtomicIntrinsics.h"
+#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Transforms/NaCl.h"
using namespace llvm;
namespace {
- class ResolvePNaClIntrinsics : public FunctionPass {
+class ResolvePNaClIntrinsics : public FunctionPass {
+public:
+ ResolvePNaClIntrinsics() : FunctionPass(ID) {
+ initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry());
+ }
+
+ static char ID;
+ virtual bool runOnFunction(Function &F);
+
+ /// Interface specifying how intrinsic calls should be resolved. Each
+ /// intrinsic call handled by the implementor will be visited by the
+ /// doResolve method.
+ class CallResolver {
public:
- ResolvePNaClIntrinsics() : FunctionPass(ID) {
- initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry());
+ /// Called once per \p Call to the intrinsic in the module.
+ /// Returns true if the Function was changed.
+ bool resolve(IntrinsicInst *Call) {
+ // To be a well-behaving FunctionPass, don't touch uses in other
+ // functions. These will be handled when the pass manager gets to
+ // those functions.
+ if (Call->getParent()->getParent() == &F)
+ return doResolve(Call);
+ return false;
}
+ Function *getDeclaration() const { return doGetDeclaration(); }
+ std::string getName() { return Intrinsic::getName(IntrinsicID); }
+
+ protected:
+ Function &F;
+ Module *M;
+ Intrinsic::ID IntrinsicID;
+
+ CallResolver(Function &F, Intrinsic::ID IntrinsicID)
+ : F(F), M(F.getParent()), IntrinsicID(IntrinsicID) {}
+ virtual ~CallResolver() {}
+
+ /// The following pure virtual methods must be defined by
+ /// implementors, and will be called once per intrinsic call.
+ virtual Function *doGetDeclaration() const = 0;
+ /// Returns true if the Function was changed.
+ virtual bool doResolve(IntrinsicInst *Call) = 0;
- static char ID;
- virtual bool runOnFunction(Function &F);
private:
- // Some intrinsic calls are resolved simply by replacing the call with a
- // call to an alternative function with exactly the same type.
- bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID,
- const char *TargetFunctionName);
+ CallResolver(const CallResolver &) LLVM_DELETED_FUNCTION;
+ CallResolver &operator=(const CallResolver &) LLVM_DELETED_FUNCTION;
};
-}
-bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F,
- Intrinsic::ID IntrinsicID,
- const char *TargetFunctionName) {
- Module *M = F.getParent();
- bool Changed = false;
- Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID);
+private:
+ /// Visit all calls matching the \p Resolver's declaration, and invoke
+ /// the CallResolver methods on each of them.
+ bool visitCalls(CallResolver &Resolver);
+};
- if (!IntrinsicFunction) {
- return false;
+/// Rewrite intrinsic calls to another function.
+class SimpleCallResolver : public ResolvePNaClIntrinsics::CallResolver {
+public:
+ SimpleCallResolver(Function &F, Intrinsic::ID IntrinsicID,
+ const char *TargetFunctionName)
+ : CallResolver(F, IntrinsicID),
+ TargetFunction(M->getFunction(TargetFunctionName)) {
+ // Expect to find the target function for this intrinsic already
+ // declared, even if it is never used.
+ if (!TargetFunction)
+ report_fatal_error(
+ std::string("Expected to find external declaration of ") +
+ TargetFunctionName);
+ }
+ virtual ~SimpleCallResolver() {}
+
+private:
+ Function *TargetFunction;
+
+ virtual Function *doGetDeclaration() const {
+ return Intrinsic::getDeclaration(M, IntrinsicID);
}
- // Expect to find the target function for this intrinsic already declared
- Function *TargetFunction = M->getFunction(TargetFunctionName);
- if (!TargetFunction) {
- report_fatal_error(
- std::string("Expected to find external declaration of ") +
- TargetFunctionName);
+ virtual bool doResolve(IntrinsicInst *Call) {
+ Call->setCalledFunction(TargetFunction);
+ return true;
}
- for (Value::use_iterator UI = IntrinsicFunction->use_begin(),
- UE = IntrinsicFunction->use_end(); UI != UE;) {
- // At this point, the only uses of the intrinsic can be calls, since
- // we assume this pass runs on bitcode that passed ABI verification.
- CallInst *Call = dyn_cast<CallInst>(*UI++);
+ SimpleCallResolver(const SimpleCallResolver &) LLVM_DELETED_FUNCTION;
+ SimpleCallResolver &operator=(
+ const SimpleCallResolver &) LLVM_DELETED_FUNCTION;
+};
- if (!Call) {
- report_fatal_error(
- std::string("Expected use of intrinsic to be a call: ") +
- Intrinsic::getName(IntrinsicID));
+/// Rewrite atomic intrinsics to LLVM IR instructions.
+class AtomicCallResolver : public ResolvePNaClIntrinsics::CallResolver {
+public:
+ AtomicCallResolver(Function &F,
+ const NaCl::AtomicIntrinsics::AtomicIntrinsic *I)
+ : CallResolver(F, I->ID), I(I) {}
+ virtual ~AtomicCallResolver() {}
+
+private:
+ const NaCl::AtomicIntrinsics::AtomicIntrinsic *I;
+
+ virtual Function *doGetDeclaration() const { return I->getDeclaration(M); }
+
+ virtual bool doResolve(IntrinsicInst *Call) {
+ // Assume the @llvm.nacl.atomic.* intrinsics follow the PNaCl ABI:
+ // this should have been checked by the verifier.
+ bool isVolatile = false;
+ SynchronizationScope SS = CrossThread;
+ Instruction *I;
+
+ switch (Call->getIntrinsicID()) {
+ default:
+ llvm_unreachable("unknown atomic intrinsic");
+ case Intrinsic::nacl_atomic_load:
+ I = new LoadInst(Call->getArgOperand(0), "", isVolatile,
+ alignmentFromPointer(Call->getArgOperand(0)),
+ thawMemoryOrder(Call->getArgOperand(1)), SS, Call);
+ break;
+ case Intrinsic::nacl_atomic_store:
+ I = new StoreInst(Call->getArgOperand(0), Call->getArgOperand(1),
+ isVolatile,
+ alignmentFromPointer(Call->getArgOperand(1)),
+ thawMemoryOrder(Call->getArgOperand(2)), SS, Call);
+ break;
+ case Intrinsic::nacl_atomic_rmw:
+ I = new AtomicRMWInst(thawRMWOperation(Call->getArgOperand(0)),
+ Call->getArgOperand(1), Call->getArgOperand(2),
+ thawMemoryOrder(Call->getArgOperand(3)), SS, Call);
+ break;
+ case Intrinsic::nacl_atomic_cmpxchg:
+ // TODO LLVM currently doesn't support specifying separate memory
+ // orders for compare exchange's success and failure cases:
+ // LLVM IR implicitly drops the Release part of the specified
+ // memory order on failure. It is therefore correct to map
+ // the success memory order onto the LLVM IR and ignore the
+ // failure one.
+ I = new AtomicCmpXchgInst(Call->getArgOperand(0), Call->getArgOperand(1),
+ Call->getArgOperand(2),
+ thawMemoryOrder(Call->getArgOperand(3)), SS,
+ Call);
+ break;
+ case Intrinsic::nacl_atomic_fence:
+ I = new FenceInst(M->getContext(),
+ thawMemoryOrder(Call->getArgOperand(0)), SS, Call);
+ break;
+ }
+ I->setName(Call->getName());
+ I->setDebugLoc(Call->getDebugLoc());
+ Call->replaceAllUsesWith(I);
+ Call->eraseFromParent();
+
+ return true;
+ }
+
+ unsigned alignmentFromPointer(const Value *Ptr) const {
+ const PointerType *PtrType = cast<PointerType>(Ptr->getType());
+ unsigned BitWidth = PtrType->getElementType()->getIntegerBitWidth();
+ return BitWidth / 8;
+ }
+
+ AtomicOrdering thawMemoryOrder(const Value *MemoryOrder) const {
+ NaCl::MemoryOrder MO = (NaCl::MemoryOrder)cast<Constant>(MemoryOrder)
+ ->getUniqueInteger().getLimitedValue();
+ switch (MO) {
+ // Only valid values should pass validation.
+ default: llvm_unreachable("unknown memory order");
+ case NaCl::MemoryOrderRelaxed: return Monotonic;
+ // TODO Consume is unspecified by LLVM's internal IR.
+ case NaCl::MemoryOrderConsume: return SequentiallyConsistent;
+ case NaCl::MemoryOrderAcquire: return Acquire;
+ case NaCl::MemoryOrderRelease: return Release;
+ case NaCl::MemoryOrderAcquireRelease: return AcquireRelease;
+ case NaCl::MemoryOrderSequentiallyConsistent: return SequentiallyConsistent;
}
+ }
- // To be a well-behaving FunctionPass, don't touch uses in other
- // functions. These will be handled when the pass manager gets to those
- // functions.
- if (Call->getParent()->getParent() == &F) {
- Call->setCalledFunction(TargetFunction);
- Changed = true;
+ AtomicRMWInst::BinOp thawRMWOperation(const Value *Operation) const {
+ NaCl::AtomicRMWOperation Op =
+ (NaCl::AtomicRMWOperation)cast<Constant>(Operation)->getUniqueInteger()
+ .getLimitedValue();
+ switch (Op) {
+ // Only valid values should pass validation.
+ default: llvm_unreachable("unknown atomic RMW operation");
+ case NaCl::AtomicAdd: return AtomicRMWInst::Add;
+ case NaCl::AtomicSub: return AtomicRMWInst::Sub;
+ case NaCl::AtomicOr: return AtomicRMWInst::Or;
+ case NaCl::AtomicAnd: return AtomicRMWInst::And;
+ case NaCl::AtomicXor: return AtomicRMWInst::Xor;
+ case NaCl::AtomicExchange: return AtomicRMWInst::Xchg;
}
}
+ AtomicCallResolver(const AtomicCallResolver &);
+ AtomicCallResolver &operator=(const AtomicCallResolver &);
+};
+}
+
+bool ResolvePNaClIntrinsics::visitCalls(
+ ResolvePNaClIntrinsics::CallResolver &Resolver) {
+ bool Changed = false;
+ Function *IntrinsicFunction = Resolver.getDeclaration();
+ if (!IntrinsicFunction)
+ return false;
+
+ for (Value::use_iterator UI = IntrinsicFunction->use_begin(),
+ UE = IntrinsicFunction->use_end();
+ UI != UE;) {
+ // At this point, the only uses of the intrinsic can be calls, since
+ // we assume this pass runs on bitcode that passed ABI verification.
+ IntrinsicInst *Call = dyn_cast<IntrinsicInst>(*UI++);
+ if (!Call)
+ report_fatal_error("Expected use of intrinsic to be a call: " +
+ Resolver.getName());
+
+ Changed |= Resolver.resolve(Call);
+ }
+
return Changed;
}
bool ResolvePNaClIntrinsics::runOnFunction(Function &F) {
- bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp");
- Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp");
+ bool Changed = false;
+
+ SimpleCallResolver SetJmpResolver(F, Intrinsic::nacl_setjmp, "setjmp");
+ SimpleCallResolver LongJmpResolver(F, Intrinsic::nacl_longjmp, "longjmp");
+ Changed |= visitCalls(SetJmpResolver);
+ Changed |= visitCalls(LongJmpResolver);
+
+ NaCl::AtomicIntrinsics AI(F.getParent()->getContext());
+ NaCl::AtomicIntrinsics::View V = AI.allIntrinsicsAndOverloads();
+ for (NaCl::AtomicIntrinsics::View::iterator I = V.begin(), E = V.end();
+ I != E; ++I) {
+ AtomicCallResolver AtomicResolver(F, I);
+ Changed |= visitCalls(AtomicResolver);
+ }
+
return Changed;
}
« no previous file with comments | « lib/Transforms/NaCl/ReplacePtrsWithInts.cpp ('k') | lib/Transforms/NaCl/RewriteAtomics.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698