Skip to content

Commit

Permalink
Add the rest of the atomic operations.
Browse files Browse the repository at this point in the history
This makes the handling of atomic operations more generic, which
does impose a specific naming convention for the intrinsics, but
that seems ok with me, rather than having an individual case for
each name.

It also adds the intrinsics to the the intrinsics file.
  • Loading branch information
James Miller committed Jun 22, 2013
1 parent fd83b92 commit befbd3a
Show file tree
Hide file tree
Showing 4 changed files with 475 additions and 396 deletions.
176 changes: 65 additions & 111 deletions src/librustc/middle/trans/foreign.rs
Expand Up @@ -11,7 +11,6 @@
use core::prelude::*;

use back::{link, abi};
use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
use lib::llvm::{TypeRef, ValueRef};
use lib;
use middle::trans::base::*;
Expand Down Expand Up @@ -578,118 +577,73 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
let mut bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let first_real_arg = fcx.arg_pos(0u);
match ccx.sess.str_of(item.ident).as_slice() {
"atomic_cxchg" => {
let old = AtomicCmpXchg(bcx,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u),
SequentiallyConsistent);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_cxchg_acq" => {
let old = AtomicCmpXchg(bcx,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u),
Acquire);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_cxchg_rel" => {
let old = AtomicCmpXchg(bcx,
get_param(decl, first_real_arg),

let nm = ccx.sess.str_of(item.ident);
let name = nm.as_slice();

// This requires that atomic intrinsics follow a specific naming pattern:
// "atomic_<operation>[_<ordering>], and no ordering means SeqCst
if name.starts_with("atomic_") {
let split : ~[&str] = name.split_iter('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic not correct format");
let order = if split.len() == 2 {
lib::llvm::SequentiallyConsistent
} else {
match split[2] {
"relaxed" => lib::llvm::Monotonic,
"acq" => lib::llvm::Acquire,
"rel" => lib::llvm::Release,
"acqrel" => lib::llvm::AcquireRelease,
_ => ccx.sess.fatal("Unknown ordering in atomic intrinsic")
}
};

match split[1] {
"cxchg" => {
let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u),
order);
Store(bcx, old, fcx.llretptr.get());
}
"load" => {
let old = AtomicLoad(bcx, get_param(decl, first_real_arg),
order);
Store(bcx, old, fcx.llretptr.get());
}
"store" => {
AtomicStore(bcx, get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg),
order);
}
op => {
// These are all AtomicRMW ops
let atom_op = match op {
"xchg" => lib::llvm::Xchg,
"xadd" => lib::llvm::Add,
"xsub" => lib::llvm::Sub,
"and" => lib::llvm::And,
"nand" => lib::llvm::Nand,
"or" => lib::llvm::Or,
"xor" => lib::llvm::Xor,
"max" => lib::llvm::Max,
"min" => lib::llvm::Min,
"umax" => lib::llvm::UMax,
"umin" => lib::llvm::UMin,
_ => ccx.sess.fatal("Unknown atomic operation")
};

let old = AtomicRMW(bcx, atom_op, get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg + 2u),
Release);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_load" => {
let old = AtomicLoad(bcx,
get_param(decl, first_real_arg),
SequentiallyConsistent);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_load_acq" => {
let old = AtomicLoad(bcx,
get_param(decl, first_real_arg),
Acquire);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_store" => {
AtomicStore(bcx,
get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg),
SequentiallyConsistent);
}
"atomic_store_rel" => {
AtomicStore(bcx,
get_param(decl, first_real_arg + 1u),
get_param(decl, first_real_arg),
Release);
}
"atomic_xchg" => {
let old = AtomicRMW(bcx, Xchg,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
SequentiallyConsistent);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xchg_acq" => {
let old = AtomicRMW(bcx, Xchg,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
Acquire);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xchg_rel" => {
let old = AtomicRMW(bcx, Xchg,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
Release);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xadd" => {
let old = AtomicRMW(bcx, lib::llvm::Add,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
SequentiallyConsistent);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xadd_acq" => {
let old = AtomicRMW(bcx, lib::llvm::Add,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
Acquire);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xadd_rel" => {
let old = AtomicRMW(bcx, lib::llvm::Add,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
Release);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xsub" => {
let old = AtomicRMW(bcx, lib::llvm::Sub,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
SequentiallyConsistent);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xsub_acq" => {
let old = AtomicRMW(bcx, lib::llvm::Sub,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
Acquire);
Store(bcx, old, fcx.llretptr.get());
}
"atomic_xsub_rel" => {
let old = AtomicRMW(bcx, lib::llvm::Sub,
get_param(decl, first_real_arg),
get_param(decl, first_real_arg + 1u),
Release);
Store(bcx, old, fcx.llretptr.get());
order);
Store(bcx, old, fcx.llretptr.get());
}
}

return;
}

match name {
"size_of" => {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
Expand Down
77 changes: 37 additions & 40 deletions src/librustc/middle/trans/type_use.rs
Expand Up @@ -117,46 +117,43 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint)
_,
_) => {
if abi.is_intrinsic() {
let flags = match cx.ccx.sess.str_of(i.ident).as_slice() {
"size_of" | "pref_align_of" | "min_align_of" |
"uninit" | "init" | "transmute" | "move_val" |
"move_val_init" => use_repr,

"get_tydesc" | "needs_drop" => use_tydesc,

"atomic_cxchg" | "atomic_cxchg_acq"|
"atomic_cxchg_rel"| "atomic_load" |
"atomic_load_acq" | "atomic_store" |
"atomic_store_rel"| "atomic_xchg" |
"atomic_xadd" | "atomic_xsub" |
"atomic_xchg_acq" | "atomic_xadd_acq" |
"atomic_xsub_acq" | "atomic_xchg_rel" |
"atomic_xadd_rel" | "atomic_xsub_rel" => 0,

"visit_tydesc" | "forget" | "frame_address" |
"morestack_addr" => 0,

"memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
"memset32" | "memset64" => use_repr,

"sqrtf32" | "sqrtf64" | "powif32" | "powif64" |
"sinf32" | "sinf64" | "cosf32" | "cosf64" |
"powf32" | "powf64" | "expf32" | "expf64" |
"exp2f32" | "exp2f64" | "logf32" | "logf64" |
"log10f32"| "log10f64"| "log2f32" | "log2f64" |
"fmaf32" | "fmaf64" | "fabsf32" | "fabsf64" |
"floorf32"| "floorf64"| "ceilf32" | "ceilf64" |
"truncf32"| "truncf64" => 0,

"ctpop8" | "ctpop16" | "ctpop32" | "ctpop64" => 0,

"ctlz8" | "ctlz16" | "ctlz32" | "ctlz64" => 0,
"cttz8" | "cttz16" | "cttz32" | "cttz64" => 0,

"bswap16" | "bswap32" | "bswap64" => 0,

// would be cool to make these an enum instead of strings!
_ => fail!("unknown intrinsic in type_use")
let nm = cx.ccx.sess.str_of(i.ident);
let name = nm.as_slice();
let flags = if name.starts_with("atomic_") {
0
} else {
match name {
"size_of" | "pref_align_of" | "min_align_of" |
"uninit" | "init" | "transmute" | "move_val" |
"move_val_init" => use_repr,

"get_tydesc" | "needs_drop" => use_tydesc,

"visit_tydesc" | "forget" | "frame_address" |
"morestack_addr" => 0,

"memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
"memset32" | "memset64" => use_repr,

"sqrtf32" | "sqrtf64" | "powif32" | "powif64" |
"sinf32" | "sinf64" | "cosf32" | "cosf64" |
"powf32" | "powf64" | "expf32" | "expf64" |
"exp2f32" | "exp2f64" | "logf32" | "logf64" |
"log10f32"| "log10f64"| "log2f32" | "log2f64" |
"fmaf32" | "fmaf64" | "fabsf32" | "fabsf64" |
"floorf32"| "floorf64"| "ceilf32" | "ceilf64" |
"truncf32"| "truncf64" => 0,

"ctpop8" | "ctpop16" | "ctpop32" | "ctpop64" => 0,

"ctlz8" | "ctlz16" | "ctlz32" | "ctlz64" => 0,
"cttz8" | "cttz16" | "cttz32" | "cttz64" => 0,

"bswap16" | "bswap32" | "bswap64" => 0,

// would be cool to make these an enum instead of strings!
_ => fail!("unknown intrinsic in type_use")
}
};
for uint::range(0u, n_tps) |n| { cx.uses[n] |= flags;}
}
Expand Down

0 comments on commit befbd3a

Please sign in to comment.