aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms
diff options
context:
space:
mode:
authorJF Bastien <jfb@chromium.org>2013-08-01 15:06:01 -0700
committerJF Bastien <jfb@chromium.org>2013-08-01 15:06:01 -0700
commita7665e96f34c4a981d59c78b0b872b8f0b100cb9 (patch)
treeaa05a7a1f915980654ae61c5a2f5952abfc7e561 /lib/Transforms
parentb9657234ee8b1951db5977a8ffb55a2e5df6d76c (diff)
Add Intrinsic::nacl_atomic_is_lock_free
This is part of a bigger CL to fix C++11 in PNaCl, to commit in the following order: - https://codereview.chromium.org/20552002 - https://codereview.chromium.org/20554002 - https://codereview.chromium.org/20560002 - https://codereview.chromium.org/20561002 This should be the last PNaCl ABI change for C11/C+11 atomic support. Note that Clang already has a builtin for lock-free, but it's partly resolved by Clang's ExprConstant.cpp and CGBuiltin.cpp, whereas what we want is a call that becomes a constant at translation-time. I made the translation part fairly general so it's easy to support architectures where ``true`` isn't always the right answer. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3475 TEST= ./scons run_synchronization_cpp11_test --verbose bitcode=1 platform=x86-64 TEST= ninja check-all R=dschuff@chromium.org Review URL: https://codereview.chromium.org/20554002
Diffstat (limited to 'lib/Transforms')
-rw-r--r--lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp113
1 files changed, 93 insertions, 20 deletions
diff --git a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
index 9b526a102a..d3e107f5f7 100644
--- a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
+++ b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
@@ -85,26 +85,28 @@ private:
};
/// Rewrite intrinsic calls to another function.
-class SimpleCallResolver : public ResolvePNaClIntrinsics::CallResolver {
+class IntrinsicCallToFunctionCall :
+ public ResolvePNaClIntrinsics::CallResolver {
public:
- SimpleCallResolver(Function &F, Intrinsic::ID IntrinsicID,
- const char *TargetFunctionName)
+ IntrinsicCallToFunctionCall(Function &F, Intrinsic::ID IntrinsicID,
+ const char *TargetFunctionName,
+ ArrayRef<Type *> Tys = None)
: CallResolver(F, IntrinsicID),
- TargetFunction(M->getFunction(TargetFunctionName)) {
+ TargetFunction(M->getFunction(TargetFunctionName)), Tys(Tys) {
// 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);
+ report_fatal_error(std::string(
+ "Expected to find external declaration of ") + TargetFunctionName);
}
- virtual ~SimpleCallResolver() {}
+ virtual ~IntrinsicCallToFunctionCall() {}
private:
Function *TargetFunction;
+ ArrayRef<Type *> Tys;
virtual Function *doGetDeclaration() const {
- return Intrinsic::getDeclaration(M, IntrinsicID);
+ return Intrinsic::getDeclaration(M, IntrinsicID, Tys);
}
virtual bool doResolve(IntrinsicInst *Call) {
@@ -112,9 +114,74 @@ private:
return true;
}
- SimpleCallResolver(const SimpleCallResolver &) LLVM_DELETED_FUNCTION;
- SimpleCallResolver &operator=(
- const SimpleCallResolver &) LLVM_DELETED_FUNCTION;
+ IntrinsicCallToFunctionCall(const IntrinsicCallToFunctionCall &)
+ LLVM_DELETED_FUNCTION;
+ IntrinsicCallToFunctionCall &operator=(const IntrinsicCallToFunctionCall &)
+ LLVM_DELETED_FUNCTION;
+};
+
+/// Rewrite intrinsic calls to a constant whose value is determined by a
+/// functor. This functor is called once per Call, and returns a
+/// Constant that should replace the Call.
+template <class Callable>
+class ConstantCallResolver : public ResolvePNaClIntrinsics::CallResolver {
+public:
+ ConstantCallResolver(Function &F, Intrinsic::ID IntrinsicID, Callable Functor,
+ ArrayRef<Type *> Tys = None)
+ : CallResolver(F, IntrinsicID), Functor(Functor) {}
+ virtual ~ConstantCallResolver() {}
+
+private:
+ Callable Functor;
+ ArrayRef<Type *> Tys;
+
+ virtual Function *doGetDeclaration() const {
+ return Intrinsic::getDeclaration(M, IntrinsicID, Tys);
+ }
+
+ virtual bool doResolve(IntrinsicInst *Call) {
+ Constant *C = Functor(Call);
+ Call->replaceAllUsesWith(C);
+ Call->eraseFromParent();
+ return true;
+ }
+
+ ConstantCallResolver(const ConstantCallResolver &) LLVM_DELETED_FUNCTION;
+ ConstantCallResolver &operator=(const ConstantCallResolver &)
+ LLVM_DELETED_FUNCTION;
+};
+
+/// Resolve __nacl_atomic_is_lock_free to true/false at translation
+/// time. PNaCl's currently supported platforms all support lock-free
+/// atomics at byte sizes {1,2,4,8}, and the alignment of the pointer is
+/// always expected to be natural (as guaranteed by C11 and
+/// C++11). PNaCl's Module-level ABI verification checks that the byte
+/// size is constant and in {1,2,4,8}.
+struct IsLockFreeToConstant {
+ Constant *operator()(CallInst *Call) {
+ const uint64_t MaxLockFreeByteSize = 8;
+ const APInt &ByteSize =
+ cast<Constant>(Call->getOperand(0))->getUniqueInteger();
+
+# if defined(__pnacl__)
+ switch (__builtin_nacl_target_arch()) {
+ case PnaclTargetArchitectureX86_32:
+ case PnaclTargetArchitectureX86_64:
+ case PnaclTargetArchitectureARM_32:
+ break;
+ default:
+ return false;
+ }
+# elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+ // Continue.
+# else
+# error "Unknown architecture"
+# endif
+
+ bool IsLockFree = ByteSize.ule(MaxLockFreeByteSize);
+ Constant *C = ConstantInt::get(Call->getType(), IsLockFree);
+ return C;
+ }
};
/// Rewrite atomic intrinsics to LLVM IR instructions.
@@ -188,8 +255,8 @@ private:
}
AtomicOrdering thawMemoryOrder(const Value *MemoryOrder) const {
- NaCl::MemoryOrder MO = (NaCl::MemoryOrder)cast<Constant>(MemoryOrder)
- ->getUniqueInteger().getLimitedValue();
+ NaCl::MemoryOrder MO = (NaCl::MemoryOrder)
+ cast<Constant>(MemoryOrder)->getUniqueInteger().getLimitedValue();
switch (MO) {
// Only valid values should pass validation.
default: llvm_unreachable("unknown memory order");
@@ -204,9 +271,8 @@ private:
}
AtomicRMWInst::BinOp thawRMWOperation(const Value *Operation) const {
- NaCl::AtomicRMWOperation Op =
- (NaCl::AtomicRMWOperation)cast<Constant>(Operation)->getUniqueInteger()
- .getLimitedValue();
+ 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");
@@ -248,14 +314,17 @@ bool ResolvePNaClIntrinsics::visitCalls(
}
bool ResolvePNaClIntrinsics::runOnFunction(Function &F) {
+ LLVMContext &C = F.getParent()->getContext();
bool Changed = false;
- SimpleCallResolver SetJmpResolver(F, Intrinsic::nacl_setjmp, "setjmp");
- SimpleCallResolver LongJmpResolver(F, Intrinsic::nacl_longjmp, "longjmp");
+ IntrinsicCallToFunctionCall SetJmpResolver(F, Intrinsic::nacl_setjmp,
+ "setjmp");
+ IntrinsicCallToFunctionCall LongJmpResolver(F, Intrinsic::nacl_longjmp,
+ "longjmp");
Changed |= visitCalls(SetJmpResolver);
Changed |= visitCalls(LongJmpResolver);
- NaCl::AtomicIntrinsics AI(F.getParent()->getContext());
+ NaCl::AtomicIntrinsics AI(C);
NaCl::AtomicIntrinsics::View V = AI.allIntrinsicsAndOverloads();
for (NaCl::AtomicIntrinsics::View::iterator I = V.begin(), E = V.end();
I != E; ++I) {
@@ -263,6 +332,10 @@ bool ResolvePNaClIntrinsics::runOnFunction(Function &F) {
Changed |= visitCalls(AtomicResolver);
}
+ ConstantCallResolver<IsLockFreeToConstant> IsLockFreeResolver(
+ F, Intrinsic::nacl_atomic_is_lock_free, IsLockFreeToConstant());
+ Changed |= visitCalls(IsLockFreeResolver);
+
return Changed;
}