1
Fork 0

Add intrinsics for compare_exchange and compare_exchange_weak

This commit is contained in:
Amanieu d'Antras 2016-01-16 23:40:11 +00:00
parent 8e2a577804
commit 64ddcb33f4
8 changed files with 114 additions and 40 deletions

View file

@ -58,6 +58,33 @@ extern "rust-intrinsic" {
pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> T; pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> T;
pub fn atomic_cxchg_acqrel<T>(dst: *mut T, old: T, src: T) -> T; pub fn atomic_cxchg_acqrel<T>(dst: *mut T, old: T, src: T) -> T;
pub fn atomic_cxchg_relaxed<T>(dst: *mut T, old: T, src: T) -> T; pub fn atomic_cxchg_relaxed<T>(dst: *mut T, old: T, src: T) -> T;
#[cfg(not(stage0))]
pub fn atomic_cxchg_failrelaxed<T>(dst: *mut T, old: T, src: T) -> T;
#[cfg(not(stage0))]
pub fn atomic_cxchg_failacq<T>(dst: *mut T, old: T, src: T) -> T;
#[cfg(not(stage0))]
pub fn atomic_cxchg_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> T;
#[cfg(not(stage0))]
pub fn atomic_cxchg_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> T;
#[cfg(not(stage0))]
pub fn atomic_cxchgweak<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_acqrel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_failacq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
#[cfg(not(stage0))]
pub fn atomic_cxchgweak_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
pub fn atomic_load<T>(src: *const T) -> T; pub fn atomic_load<T>(src: *const T) -> T;
pub fn atomic_load_acq<T>(src: *const T) -> T; pub fn atomic_load_acq<T>(src: *const T) -> T;

View file

@ -1584,7 +1584,8 @@ extern {
CMP: ValueRef, CMP: ValueRef,
RHS: ValueRef, RHS: ValueRef,
Order: AtomicOrdering, Order: AtomicOrdering,
FailureOrder: AtomicOrdering) FailureOrder: AtomicOrdering,
Weak: Bool)
-> ValueRef; -> ValueRef;
pub fn LLVMBuildAtomicRMW(B: BuilderRef, pub fn LLVMBuildAtomicRMW(B: BuilderRef,
Op: AtomicBinOp, Op: AtomicBinOp,

View file

@ -1067,8 +1067,9 @@ pub fn Resume(cx: Block, exn: ValueRef) -> ValueRef {
pub fn AtomicCmpXchg(cx: Block, dst: ValueRef, pub fn AtomicCmpXchg(cx: Block, dst: ValueRef,
cmp: ValueRef, src: ValueRef, cmp: ValueRef, src: ValueRef,
order: AtomicOrdering, order: AtomicOrdering,
failure_order: AtomicOrdering) -> ValueRef { failure_order: AtomicOrdering,
B(cx).atomic_cmpxchg(dst, cmp, src, order, failure_order) weak: llvm::Bool) -> ValueRef {
B(cx).atomic_cmpxchg(dst, cmp, src, order, failure_order, weak)
} }
pub fn AtomicRMW(cx: Block, op: AtomicBinOp, pub fn AtomicRMW(cx: Block, op: AtomicBinOp,
dst: ValueRef, src: ValueRef, dst: ValueRef, src: ValueRef,

View file

@ -1077,10 +1077,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
pub fn atomic_cmpxchg(&self, dst: ValueRef, pub fn atomic_cmpxchg(&self, dst: ValueRef,
cmp: ValueRef, src: ValueRef, cmp: ValueRef, src: ValueRef,
order: AtomicOrdering, order: AtomicOrdering,
failure_order: AtomicOrdering) -> ValueRef { failure_order: AtomicOrdering,
weak: llvm::Bool) -> ValueRef {
unsafe { unsafe {
llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src,
order, failure_order) order, failure_order, weak)
} }
} }
pub fn atomic_rmw(&self, op: AtomicBinOp, pub fn atomic_rmw(&self, op: AtomicBinOp,

View file

@ -678,49 +678,54 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
// "atomic_<operation>[_<ordering>]", and no ordering means SeqCst // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
(_, name) if name.starts_with("atomic_") => { (_, name) if name.starts_with("atomic_") => {
let split: Vec<&str> = name.split('_').collect(); let split: Vec<&str> = name.split('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic not correct format");
let order = if split.len() == 2 { let (order, failorder) = match split.len() {
llvm::SequentiallyConsistent 2 => (llvm::SequentiallyConsistent, llvm::SequentiallyConsistent),
} else { 3 => match split[2] {
match split[2] { "unordered" => (llvm::Unordered, llvm::Unordered),
"unordered" => llvm::Unordered, "relaxed" => (llvm::Monotonic, llvm::Monotonic),
"relaxed" => llvm::Monotonic, "acq" => (llvm::Acquire, llvm::Acquire),
"acq" => llvm::Acquire, "rel" => (llvm::Release, llvm::Monotonic),
"rel" => llvm::Release, "acqrel" => (llvm::AcquireRelease, llvm::Acquire),
"acqrel" => llvm::AcquireRelease, "failrelaxed" if split[1] == "cxchg" || split[1] == "cxchgweak" =>
(llvm::SequentiallyConsistent, llvm::Monotonic),
"failacq" if split[1] == "cxchg" || split[1] == "cxchgweak" =>
(llvm::SequentiallyConsistent, llvm::Acquire),
_ => ccx.sess().fatal("unknown ordering in atomic intrinsic") _ => ccx.sess().fatal("unknown ordering in atomic intrinsic")
} },
4 => match (split[2], split[3]) {
("acq", "failrelaxed") if split[1] == "cxchg" || split[1] == "cxchgweak" =>
(llvm::Acquire, llvm::Monotonic),
("acqrel", "failrelaxed") if split[1] == "cxchg" || split[1] == "cxchgweak" =>
(llvm::AcquireRelease, llvm::Monotonic),
_ => ccx.sess().fatal("unknown ordering in atomic intrinsic")
},
_ => ccx.sess().fatal("Atomic intrinsic not in correct format"),
}; };
match split[1] { match split[1] {
"cxchg" => { "cxchg" => {
// See include/llvm/IR/Instructions.h for their implementation
// of this, I assume that it's good enough for us to use for
// now.
let strongest_failure_ordering = match order {
llvm::NotAtomic | llvm::Unordered =>
ccx.sess().fatal("cmpxchg must be atomic"),
llvm::Monotonic | llvm::Release =>
llvm::Monotonic,
llvm::Acquire | llvm::AcquireRelease =>
llvm::Acquire,
llvm::SequentiallyConsistent =>
llvm::SequentiallyConsistent
};
let tp_ty = *substs.types.get(FnSpace, 0); let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty); let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
let cmp = from_arg_ty(bcx, llargs[1], tp_ty); let cmp = from_arg_ty(bcx, llargs[1], tp_ty);
let src = from_arg_ty(bcx, llargs[2], tp_ty); let src = from_arg_ty(bcx, llargs[2], tp_ty);
let res = AtomicCmpXchg(bcx, ptr, cmp, src, order, let res = AtomicCmpXchg(bcx, ptr, cmp, src, order, failorder, llvm::False);
strongest_failure_ordering);
ExtractValue(bcx, res, 0) ExtractValue(bcx, res, 0)
} }
"cxchgweak" => {
let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
let cmp = from_arg_ty(bcx, llargs[1], tp_ty);
let src = from_arg_ty(bcx, llargs[2], tp_ty);
let val = AtomicCmpXchg(bcx, ptr, cmp, src, order, failorder, llvm::True);
let result = ExtractValue(bcx, val, 0);
let success = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool(bcx.ccx()));
Store(bcx, result, StructGEP(bcx, llresult, 0));
Store(bcx, success, StructGEP(bcx, llresult, 1));
C_nil(ccx)
}
"load" => { "load" => {
let tp_ty = *substs.types.get(FnSpace, 0); let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty); let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);

View file

@ -83,6 +83,10 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
param(ccx, 0), param(ccx, 0),
param(ccx, 0)), param(ccx, 0)),
param(ccx, 0)), param(ccx, 0)),
"cxchgweak" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)),
param(ccx, 0),
param(ccx, 0)),
tcx.mk_tup(vec!(param(ccx, 0), tcx.types.bool))),
"load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))), "load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))),
param(ccx, 0)), param(ccx, 0)),
"store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), "store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)),

View file

@ -191,11 +191,15 @@ extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B,
LLVMValueRef old, LLVMValueRef old,
LLVMValueRef source, LLVMValueRef source,
AtomicOrdering order, AtomicOrdering order,
AtomicOrdering failure_order) { AtomicOrdering failure_order,
return wrap(unwrap(B)->CreateAtomicCmpXchg(unwrap(target), unwrap(old), LLVMBool weak) {
unwrap(source), order, AtomicCmpXchgInst* acxi = unwrap(B)->CreateAtomicCmpXchg(unwrap(target),
failure_order unwrap(old),
)); unwrap(source),
order,
failure_order);
acxi->setWeak(weak);
return wrap(acxi);
} }
extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B, extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B,
AtomicOrdering order, AtomicOrdering order,

View file

@ -19,6 +19,10 @@ mod rusti {
pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> T; pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> T;
pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> T; pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> T;
pub fn atomic_cxchgweak<T>(dst: *mut T, old: T, src: T) -> (T, bool);
pub fn atomic_cxchgweak_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
pub fn atomic_cxchgweak_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
pub fn atomic_load<T>(src: *const T) -> T; pub fn atomic_load<T>(src: *const T) -> T;
pub fn atomic_load_acq<T>(src: *const T) -> T; pub fn atomic_load_acq<T>(src: *const T) -> T;
@ -79,5 +83,32 @@ pub fn main() {
assert_eq!(rusti::atomic_xsub_acq(&mut *x, 1), 2); assert_eq!(rusti::atomic_xsub_acq(&mut *x, 1), 2);
assert_eq!(rusti::atomic_xsub_rel(&mut *x, 1), 1); assert_eq!(rusti::atomic_xsub_rel(&mut *x, 1), 1);
assert_eq!(*x, 0); assert_eq!(*x, 0);
loop {
let res = rusti::atomic_cxchgweak(&mut *x, 0, 1);
assert_eq!(res.0, 0);
if res.1 {
break;
}
}
assert_eq!(*x, 1);
loop {
let res = rusti::atomic_cxchgweak_acq(&mut *x, 1, 2);
assert_eq!(res.0, 1);
if res.1 {
break;
}
}
assert_eq!(*x, 2);
loop {
let res = rusti::atomic_cxchgweak_rel(&mut *x, 2, 3);
assert_eq!(res.0, 2);
if res.1 {
break;
}
}
assert_eq!(*x, 3);
} }
} }