Skip to content

Commit

Permalink
Add singlethreaded fence intrinsics.
Browse files Browse the repository at this point in the history
These new intrinsics are comparable to `atomic_signal_fence` in C++,
ensuring the compiler will not reorder memory accesses across the
barrier, nor will it emit any machine instructions for it.

Closes rust-lang#24118, implementing RFC 888.
  • Loading branch information
tari committed Apr 26, 2015
1 parent 0d8309e commit 998c10d
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 11 deletions.
15 changes: 15 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ extern "rust-intrinsic" {
pub fn atomic_fence_rel();
pub fn atomic_fence_acqrel();

/// A compiler-only memory barrier.
///
/// Memory accesses will never be reordered across this barrier by the compiler,
/// but no instructions will be emitted for it. This is appropriate for operations
/// on the same thread that may be preempted, such as when interacting with signal
/// handlers.
#[cfg(not(stage0))] // SNAP 5520801
pub fn atomic_singlethreadfence();
#[cfg(not(stage0))] // SNAP 5520801
pub fn atomic_singlethreadfence_acq();
#[cfg(not(stage0))] // SNAP 5520801
pub fn atomic_singlethreadfence_rel();
#[cfg(not(stage0))] // SNAP 5520801
pub fn atomic_singlethreadfence_acqrel();

/// Aborts the execution of the process.
pub fn abort() -> !;

Expand Down
12 changes: 11 additions & 1 deletion src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub use self::RealPredicate::*;
pub use self::TypeKind::*;
pub use self::AtomicBinOp::*;
pub use self::AtomicOrdering::*;
pub use self::SynchronizationScope::*;
pub use self::FileType::*;
pub use self::MetadataType::*;
pub use self::AsmDialect::*;
Expand Down Expand Up @@ -361,6 +362,13 @@ pub enum AtomicOrdering {
SequentiallyConsistent = 7
}

#[repr(C)]
#[derive(Copy, Clone)]
pub enum SynchronizationScope {
SingleThread = 0,
CrossThread = 1
}

// Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h)
#[repr(C)]
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -1534,7 +1542,9 @@ extern {
SingleThreaded: Bool)
-> ValueRef;

pub fn LLVMBuildAtomicFence(B: BuilderRef, Order: AtomicOrdering);
pub fn LLVMBuildAtomicFence(B: BuilderRef,
Order: AtomicOrdering,
Scope: SynchronizationScope);


/* Selected entries from the downcasts. */
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_trans/trans/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#![allow(non_snake_case)]

use llvm;
use llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect, AttrBuilder};
use llvm::{CallConv, AtomicBinOp, AtomicOrdering, SynchronizationScope, AsmDialect, AttrBuilder};
use llvm::{Opcode, IntPredicate, RealPredicate};
use llvm::{ValueRef, BasicBlockRef};
use trans::common::*;
Expand Down Expand Up @@ -965,9 +965,9 @@ pub fn CallWithConv(cx: Block,
B(cx).call_with_conv(fn_, args, conv, attributes)
}

pub fn AtomicFence(cx: Block, order: AtomicOrdering) {
pub fn AtomicFence(cx: Block, order: AtomicOrdering, scope: SynchronizationScope) {
if cx.unreachable.get() { return; }
B(cx).atomic_fence(order)
B(cx).atomic_fence(order, scope)
}

pub fn Select(cx: Block, if_: ValueRef, then: ValueRef, else_: ValueRef) -> ValueRef {
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_trans/trans/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#![allow(dead_code)] // FFI wrappers

use llvm;
use llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect, AttrBuilder};
use llvm::{CallConv, AtomicBinOp, AtomicOrdering, SynchronizationScope, AsmDialect, AttrBuilder};
use llvm::{Opcode, IntPredicate, RealPredicate, False};
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
use trans::base;
Expand Down Expand Up @@ -989,9 +989,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

pub fn atomic_fence(&self, order: AtomicOrdering) {
pub fn atomic_fence(&self, order: AtomicOrdering, scope: SynchronizationScope) {
unsafe {
llvm::LLVMBuildAtomicFence(self.llbuilder, order);
llvm::LLVMBuildAtomicFence(self.llbuilder, order, scope);
}
}
}
7 changes: 6 additions & 1 deletion src/librustc_trans/trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
}

"fence" => {
AtomicFence(bcx, order);
AtomicFence(bcx, order, llvm::CrossThread);
C_nil(ccx)
}

"singlethreadfence" => {
AtomicFence(bcx, order, llvm::SingleThread);
C_nil(ccx)
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4812,7 +4812,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
(1, vec!(ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0)),
param(ccx, 0))
}
"fence" => {
"fence" | "singlethreadfence" => {
(0, Vec::new(), ty::mk_nil(tcx))
}
op => {
Expand Down
6 changes: 4 additions & 2 deletions src/rustllvm/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,10 @@ extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B,
failure_order
));
}
extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B, AtomicOrdering order) {
return wrap(unwrap(B)->CreateFence(order));
extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B,
AtomicOrdering order,
SynchronizationScope scope) {
return wrap(unwrap(B)->CreateFence(order, scope));
}

extern "C" void LLVMSetDebug(int Enabled) {
Expand Down

0 comments on commit 998c10d

Please sign in to comment.