From 4a1a0fbed5a57958eb7b658bbe3e5257872ae99f Mon Sep 17 00:00:00 2001 From: James Miller Date: Sun, 28 Jul 2013 19:48:16 +1200 Subject: [PATCH] Add an atomic fence intrinsic --- src/librustc/lib/llvm.rs | 3 +++ src/librustc/middle/trans/build.rs | 5 +++++ src/librustc/middle/trans/builder.rs | 6 ++++++ src/librustc/middle/trans/foreign.rs | 4 ++++ src/librustc/middle/typeck/check/mod.rs | 4 +++- src/libstd/unstable/atomics.rs | 27 +++++++++++++++++++++++++ src/libstd/unstable/intrinsics.rs | 9 +++++++++ src/rustllvm/RustWrapper.cpp | 5 ++++- src/rustllvm/rustllvm.def.in | 1 + 9 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index f3bca7a6ab3..57563948b0f 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1594,6 +1594,9 @@ pub mod llvm { Order: AtomicOrdering) -> ValueRef; + pub unsafe fn LLVMBuildAtomicFence(B: BuilderRef, Order: AtomicOrdering); + + /* Selected entries from the downcasts. */ #[fast_ffi] pub unsafe fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index 9c34d2a3526..07b774105bb 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -660,6 +660,11 @@ pub fn CallWithConv(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef], B(cx).call_with_conv(Fn, Args, Conv) } +pub fn AtomicFence(cx: @mut Block, order: AtomicOrdering) { + if cx.unreachable { return; } + B(cx).atomic_fence(order) +} + pub fn Select(cx: @mut Block, If: ValueRef, Then: ValueRef, Else: ValueRef) -> ValueRef { if cx.unreachable { return _Undef(Then); } B(cx).select(If, Then, Else) diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs index 1c9161163cc..be9d5a6c118 100644 --- a/src/librustc/middle/trans/builder.rs +++ b/src/librustc/middle/trans/builder.rs @@ -943,4 +943,10 @@ impl Builder { llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order) } } + + pub fn atomic_fence(&self, order: AtomicOrdering) { + unsafe { + llvm::LLVMBuildAtomicFence(self.llbuilder, order); + } + } } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 6e198af448b..080d1f2adb5 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -661,6 +661,10 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, order); RetVoid(bcx); } + "fence" => { + AtomicFence(bcx, order); + RetVoid(bcx); + } op => { // These are all AtomicRMW ops let atom_op = match op { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 0b80c0cb3c6..cffceee88d3 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3521,7 +3521,9 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ty::re_bound(ty::br_anon(0)), ty::mk_int()), ty::mk_int() ], ty::mk_int()) } - + "fence" => { + (0, ~[], ty::mk_nil()) + } op => { tcx.sess.span_err(it.span, fmt!("unrecognized atomic operation function: `%s`", diff --git a/src/libstd/unstable/atomics.rs b/src/libstd/unstable/atomics.rs index 712c32d2436..8b57da32bbd 100644 --- a/src/libstd/unstable/atomics.rs +++ b/src/libstd/unstable/atomics.rs @@ -569,6 +569,33 @@ pub unsafe fn atomic_umin(dst: &mut T, val: T, order: Ordering) -> T { }) } +/** + * An atomic fence. + * + * A fence 'A' which has `Release` ordering semantics, synchronizes with a + * fence 'B' with (at least) `Aquire` semantics, if and only if there exists + * atomic operations X and Y, bother operating on some atomic object 'M' such + * that A is sequenced before X, Y is synchronized before B and Y obsevers + * the change to M. This provides a happens-before dependence between A and B. + * + * Atomic operations with `Release` or `Acquire` semantics can also synchronize + * with a fence. + * + * A fence with has `SeqCst` ordering, in addition to having both `Acquire` and + * `Release` semantics, participates in the global program order of the other + * `SeqCst` operations and/or fences. + * + * Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings. + */ +#[inline] #[cfg(not(stage0))] +pub fn fence(order: Ordering) { + match order { + Acquire => intrinsics::atomic_fence_acq(), + Release => intrinsics::atomic_fence_rel(), + AcqRel => intrinsics::atomic_fence_rel(), + _ => intrinsics::atomic_fence(), + } +} #[cfg(test)] mod test { diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 76958fa333f..655ede6b4eb 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -256,6 +256,15 @@ extern "rust-intrinsic" { pub fn atomic_umax_acqrel(dst: &mut int, src: int) -> int; pub fn atomic_umax_relaxed(dst: &mut int, src: int) -> int; + #[cfg(not(stage0))] + pub fn atomic_fence(); + #[cfg(not(stage0))] + pub fn atomic_fence_acq(); + #[cfg(not(stage0))] + pub fn atomic_fence_rel(); + #[cfg(not(stage0))] + pub fn atomic_fence_acqrel(); + /// The size of a type in bytes. /// /// This is the exact number of bytes in memory taken up by a diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 2a1f26bf441..beaa7e1daef 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -513,6 +513,9 @@ extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, return wrap(unwrap(B)->CreateAtomicCmpXchg(unwrap(target), unwrap(old), unwrap(source), order)); } +extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B, AtomicOrdering order) { + return wrap(unwrap(B)->CreateFence(order)); +} extern "C" LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, AtomicRMWInst::BinOp op, LLVMValueRef target, @@ -838,4 +841,4 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType( Flags, unwrapDI(Elements), RunTimeLang)); -} \ No newline at end of file +} diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index 48888760fc6..260a16dab98 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -90,6 +90,7 @@ LLVMBuildAtomicLoad LLVMBuildAtomicStore LLVMBuildAtomicCmpXchg LLVMBuildAtomicRMW +LLVMBuildAtomicFence LLVMBuildAdd LLVMBuildAggregateRet LLVMBuildAlloca