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

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: Update PNaClLangRef to reflect the implementation work I will now go forward with. Created 7 years, 6 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
Index: lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
diff --git a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
index e4efeb67c3c3c24c5ca1103f960338dea0c134f6..8504a81f7e1a17fdf4afbdbab7b9952fa0b69149 100644
--- a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
+++ b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
@@ -17,77 +17,233 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Constant.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/NaClIntrinsics.h"
+#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
+#include "llvm/Support/MathExtras.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 calls should be resolved.
+ class CallResolver {
public:
- ResolvePNaClIntrinsics() : FunctionPass(ID) {
- initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry());
+ // Called once the intrinsic's declaration is found in the module.
+ void Init() { DoInit(); }
+ // Called once per call to the intrinsic in the module.
+ bool Resolve(CallInst *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 Intrinsic::getDeclaration(M, IntrinsicID);
+ }
+ 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() {}
+ virtual void DoInit() = 0;
+ virtual bool DoResolve(CallInst *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 &);
+ CallResolver &operator=(const CallResolver &);
};
-}
-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:
+ // Walk calls matching the resolver's declaration, and invoke the
+ // CallResolver methods on each of them.
+ bool walkCalls(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), TargetFunctionName(TargetFunctionName),
+ TargetFunction(NULL) {}
+ virtual ~SimpleCallResolver() {}
+
+private:
+ const char *TargetFunctionName;
+ Function *TargetFunction;
+
+ virtual void DoInit() {
+ // Expect to find the target function for this intrinsic already declared.
+ TargetFunction = M->getFunction(TargetFunctionName);
+ if (!TargetFunction)
+ report_fatal_error(std::string(
+ "Expected to find external declaration of ") + TargetFunctionName);
}
+ virtual bool DoResolve(CallInst *Call) {
+ Call->setCalledFunction(TargetFunction);
+ return true;
+ }
+
+ SimpleCallResolver(const SimpleCallResolver &);
+ SimpleCallResolver &operator=(const SimpleCallResolver &);
+};
+
+// Rewrite atomic intrinsics to LLVM IR instructions.
+class AtomicCallResolver : public ResolvePNaClIntrinsics::CallResolver {
+public:
+ AtomicCallResolver(Function &F, Intrinsic::ID IntrinsicID)
+ : CallResolver(F, IntrinsicID) {}
+ virtual ~AtomicCallResolver() {}
+
+private:
+ virtual void DoInit() {}
+ virtual bool DoResolve(CallInst *Call) {
+ // Assume the @llvm.nacl.atomic.<size> intrinsics follow the PNaCl
+ // ABI: this should have been checked by the verifier.
+ uint64_t Op(cast<Constant>(Call->getArgOperand(0))
+ ->getUniqueInteger().getLimitedValue());
+ Value *Ptr = Call->getArgOperand(1);
+ Value *Val = Call->getArgOperand(2);
+ Value *Old = Call->getArgOperand(3);
+ uint64_t MemoryOrder(cast<Constant>(Call->getArgOperand(4))
+ ->getUniqueInteger().getLimitedValue());
+
+ AtomicRMWInst::BinOp RMWOp;
+ switch (Op) {
+ default: RMWOp = AtomicRMWInst::BAD_BINOP; break;
+ case NaCl::AtomicAdd: RMWOp = AtomicRMWInst::Add; break;
+ case NaCl::AtomicSub: RMWOp = AtomicRMWInst::Sub; break;
+ case NaCl::AtomicOr: RMWOp = AtomicRMWInst::Or; break;
+ case NaCl::AtomicAnd: RMWOp = AtomicRMWInst::And; break;
+ case NaCl::AtomicXor: RMWOp = AtomicRMWInst::Xor; break;
+ case NaCl::AtomicXchg: RMWOp = AtomicRMWInst::Xchg; break;
+ }
+ AtomicOrdering Order;
+ switch (MemoryOrder) {
+ // Conservatively use the strongest ordering.
+ default: Order = SequentiallyConsistent; break;
+ case NaCl::MemoryOrderRelaxed: Order = Unordered; break;
+ // TODO Consume is unspecified by LLVM's internal IR.
+ case NaCl::MemoryOrderConsume: Order = SequentiallyConsistent; break;
+ case NaCl::MemoryOrderAcquire: Order = Acquire; break;
+ case NaCl::MemoryOrderRelease: Order = Release; break;
+ case NaCl::MemoryOrderAcquireRelease: Order = AcquireRelease; break;
+ case NaCl::MemoryOrderSequentiallyConsistent:
+ Order = SequentiallyConsistent; break;
+ }
+ const Twine Name("");
+ bool isVolatile = false;
+ SynchronizationScope SS = CrossThread;
+ bool hasUses;
+ Instruction *I;
+
+ for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) {
+ if (IntrinsicID != NaCl::AtomicIntrinsics[II].ID)
+ continue;
- // 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);
+ unsigned BitSize = NaCl::AtomicIntrinsics[II].BitSize;
+ unsigned Align = 1 << (CountTrailingZeros_32(BitSize) - 3);
+ switch (Op) {
+ default:
+ llvm_unreachable("invalid atomic operation");
+ case NaCl::AtomicLoad:
+ hasUses = true;
+ I = new LoadInst(Ptr, Name, isVolatile, Align, Order, SS, Call);
+ break;
+ case NaCl::AtomicStore:
+ hasUses = false;
+ I = new StoreInst(Val, Ptr, isVolatile, Align, Order, SS, Call);
+ break;
+ case NaCl::AtomicAdd:
+ case NaCl::AtomicSub:
+ case NaCl::AtomicOr:
+ case NaCl::AtomicAnd:
+ case NaCl::AtomicXor:
+ case NaCl::AtomicXchg:
+ hasUses = true;
+ I = new AtomicRMWInst(RMWOp, Ptr, Val, Order, SS, Call);
+ break;
+ case NaCl::AtomicCmpXchg:
+ hasUses = true;
+ I = new AtomicCmpXchgInst(Ptr, Old, Val, Order, SS, Call);
+ break;
+ case NaCl::AtomicFence:
+ hasUses = false;
+ I = new FenceInst(M->getContext(), Order, SS, Call);
+ break;
+ }
+ I->setDebugLoc(Call->getDebugLoc());
+ if (hasUses)
+ Call->replaceAllUsesWith(I);
+ Call->eraseFromParent();
+ }
+ return true;
}
+ AtomicCallResolver(const AtomicCallResolver &);
+ AtomicCallResolver &operator=(const AtomicCallResolver &);
+};
+}
+
+bool ResolvePNaClIntrinsics::walkCalls(
+ ResolvePNaClIntrinsics::CallResolver &Resolver) {
+ bool Changed = false;
+ Function *IntrinsicFunction = Resolver.getDeclaration();
+ if (!IntrinsicFunction)
+ return false;
+
+ Resolver.Init();
+
for (Value::use_iterator UI = IntrinsicFunction->use_begin(),
- UE = IntrinsicFunction->use_end(); UI != UE;) {
+ 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++);
+ if (!Call)
+ report_fatal_error("Expected use of intrinsic to be a call: " +
+ Resolver.getName());
- if (!Call) {
- report_fatal_error(
- std::string("Expected use of intrinsic to be a call: ") +
- Intrinsic::getName(IntrinsicID));
- }
-
- // 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;
- }
+ 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 |= walkCalls(SetJmpResolver);
+ Changed |= walkCalls(LongJmpResolver);
+
+ for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) {
+ AtomicCallResolver AtomicResolver(F, NaCl::AtomicIntrinsics[II].ID);
+ Changed |= walkCalls(AtomicResolver);
+ }
+
return Changed;
}

Powered by Google App Engine
This is Rietveld 408576698