Chromium Code Reviews| Index: lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp |
| diff --git a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp |
| index e4efeb67c3c3c24c5ca1103f960338dea0c134f6..39126f0fbe5c6b9c27dfc5b2b470cc86bb7704c0 100644 |
| --- a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp |
| +++ b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp |
| @@ -17,10 +17,14 @@ |
| //===----------------------------------------------------------------------===// |
| #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/NaCl.h" |
| +#include "llvm/IR/Value.h" |
| #include "llvm/Pass.h" |
| +#include "llvm/Support/MathExtras.h" |
| #include "llvm/Transforms/NaCl.h" |
| using namespace llvm; |
| @@ -37,14 +41,16 @@ namespace { |
| 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); |
| + bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID); |
| + // All atomic calls are rewritten to a single instruction, and the |
| + // call is removed. |
| + void rewriteAtomicCall(Module *M, Function &F, Intrinsic::ID IntrinsicID, |
| + CallInst *Call); |
| }; |
| } |
| bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, |
| - Intrinsic::ID IntrinsicID, |
| - const char *TargetFunctionName) { |
| + Intrinsic::ID IntrinsicID) { |
| Module *M = F.getParent(); |
| bool Changed = false; |
| Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); |
| @@ -53,12 +59,18 @@ bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, |
| return false; |
| } |
| - // 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); |
| + Function *TargetFunction = NULL; |
| + if (IntrinsicID == Intrinsic::nacl_setjmp || |
|
eliben
2013/06/26 16:20:57
No no no no no :-)
resolveSimpleCall's comment is
JF
2013/06/26 22:23:12
Done: rewrote to use one class per type of rewrite
|
| + IntrinsicID == Intrinsic::nacl_longjmp) { |
| + // Expect to find the target function for this intrinsic already declared. |
| + const char *TargetFunctionName = IntrinsicID == Intrinsic::nacl_setjmp |
| + ? "setjmp" : "longjmp"; |
| + TargetFunction = M->getFunction(TargetFunctionName); |
| + if (!TargetFunction) { |
| + report_fatal_error( |
| + std::string("Expected to find external declaration of ") + |
| + TargetFunctionName); |
| + } |
| } |
| for (Value::use_iterator UI = IntrinsicFunction->use_begin(), |
| @@ -77,7 +89,11 @@ bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, |
| // functions. These will be handled when the pass manager gets to those |
| // functions. |
| if (Call->getParent()->getParent() == &F) { |
| - Call->setCalledFunction(TargetFunction); |
| + if (IntrinsicID == Intrinsic::nacl_setjmp || |
| + IntrinsicID == Intrinsic::nacl_longjmp) |
| + Call->setCalledFunction(TargetFunction); |
| + else |
| + rewriteAtomicCall(M, F, IntrinsicID, Call); |
| Changed = true; |
| } |
| } |
| @@ -85,9 +101,97 @@ bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, |
| return Changed; |
| } |
| +void ResolvePNaClIntrinsics::rewriteAtomicCall(Module *M, Function &F, |
| + Intrinsic::ID IntrinsicID, |
| + CallInst *Call) { |
| + // Assume the @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)); |
|
Mark Seaborn
2013/06/26 14:33:41
Just write "Ptr = Call->getArgOperand(1)"? Using
JF
2013/06/26 15:52:29
Done.
|
| + 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) { |
| + default: |
| + // Conservatively use the strongest ordering. |
| + Order = SequentiallyConsistent; break; |
| + case NaCl::MemoryOrderRelaxed: Order = Unordered; break; |
| + case NaCl::MemoryOrderConsume: |
| + // TODO Unspecified by LLVM's internal IR. |
| + 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; |
| + |
| + 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) |
|
Mark Seaborn
2013/06/26 14:33:41
I think you can do the RAUW unconditionally
JF
2013/06/26 15:52:29
No:
assert(New->getType() == getType() &&
|
| + Call->replaceAllUsesWith(I); |
| + Call->eraseFromParent(); |
| + } |
| +} |
| + |
| bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { |
| - bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); |
| - Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); |
| + bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp); |
| + Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp); |
| + for (size_t II = 0; II != NaCl::NumAtomicIntrinsics; ++II) { |
| + Changed |= resolveSimpleCall(F, NaCl::AtomicIntrinsics[II].ID); |
| + } |
| return Changed; |
| } |