[this is a bit of a follow-up to in-person interactions at SC13,
but posting it here for a wider audience (aka not pestering Brad
*again*)...]
Does the following seem like a half-way sane method for adapting
to different compilers' intrinsics in Chapel? There's heavy
cheating around the ll/sc, and I don't have a Power account handy
for testing, so consider this a sketch...
// module Atomic-intrinsics.chpl
use Atomics;
module impl {
use ChapelBase;
// XXX: Don't recall if pgi implements these...
inline proc gccish_intrinsics() param {
return CHPL_TARGET_COMPILER == "gnu" || CHPL_TARGET_COMPILER == "intel" ||
CHPL_TARGET_COMPILER == "pgi" || CHPL_TARGET_COMPILER ==
"cray-prgenv-gnu" ||
CHPL_TARGET_COMPILER == "cray-prgenv-intel" ||
CHPL_TARGET_COMPILER == "cray-prgenv-pgi";
}
// XXX: This should be for xlc on power and not other platforms.
inline proc xlcish_power_intrinsics() param {
return CHPL_TARGET_COMPILER == "xlc";
}
inline proc xmtish_intrinsics() param {
compilerError("Get a real machine.");
return false;
}
inline proc target_compiler_name() param { return CHPL_TARGET_COMPILER; }
}
use impl;
// local{} clauses just to make sure...
// OP: add
inline proc atomic_fetch_add(ref x, val: x.type, const
order:memory_order=memory_order_seq_cst) : x.type {
if (gccish_intrinsics()) {
extern proc __atomic_fetch_add(ref x: real(64), val: real(64),
order:memory_order) : real(64);
extern proc __atomic_fetch_add(ref x: int(64), val: int(64),
order:memory_order) : int(64);
extern proc __atomic_fetch_add(ref x: uint(64), val: uint(64),
order:memory_order) : uint(64);
extern proc __atomic_fetch_add(ref x: real(32), val: real(32),
order:memory_order) : real(32);
extern proc __atomic_fetch_add(ref x: int(32), val: int(32),
order:memory_order) : int(32);
extern proc __atomic_fetch_add(ref x: uint(32), val: uint(32),
order:memory_order) : uint(32);
extern proc __atomic_fetch_add(ref x: int(16), val: int(16),
order:memory_order) : int(16);
extern proc __atomic_fetch_add(ref x: uint(16), val: uint(16),
order:memory_order) : uint(16);
extern proc __atomic_fetch_add(ref x: int(8), val: int(8),
order:memory_order) : int(8);
extern proc __atomic_fetch_add(ref x: uint(8), val: uint(8),
order:memory_order) : uint(8);
inline proc __atomic_fetch_add(x, val, order) {
compilerError("No fetch and add for this type.");
return 0:x.type;
}
var retval : x.type;
local {
retval = __atomic_fetch_add(x, val, order);
}
return retval;
} else if (xlcish_power_intrinsics()) {
compilerWarning("Completely untested atomics for ", target_compiler_name());
compilerWarning(" Needs isync, eieio, etc. for memory order.");
var retval : x.type;
inline proc __fa(ref x: int(32), in val: int(32)) {
extern proc __fetch_and_add(ref x: int(32), in val: int(32)) : int(32);
return __fetch_and_add(x, val);
}
inline proc __fa(ref x: int(64), in val: int(64)) {
extern proc __fetch_and_addlp(ref x: int(64), in val: int(64)) : int(64);
return __fetch_and_addlp(x, val);
}
inline proc __fa(ref x: real(32), in val: real(32)) {
extern proc __lwarx(ref x: real(32)) : real(32);
extern proc __stwcx(ref x: real(32), in val: real(32)) : int(32);
var outval : real(32);
var newval : real(32);
do {
outval = __lwarx(x);
newval = outval + val;
} while !(__stwcx (x, newval));
return outval;
}
inline proc __fa(ref x: real(64), in val: real(64)) {
extern proc __ldarx(ref x: real(64)) : real(64);
extern proc __stdcx(ref x: real(64), in val: real(64)) : int(64);
var outval : real(64);
var newval : real(64);
do {
outval = __ldarx(x);
newval = outval + val;
} while !(__stdcx (x, newval));
return outval;
}
inline proc __fa(x, val) {
compilerError("No fetch and add for this type.");
}
local {
retval = __fa(x, val);
}
return retval;
} else {
compilerError("Unrecognized target compiler: ", target_compiler_name());
}
}
inline proc atomic_add_fetch(ref x, val: x.type, const
order:memory_order=memory_order_seq_cst) : x.type {
if (gccish_intrinsics()) {
extern proc __atomic_add_fetch(ref x: real(64), val: real(64),
order:memory_order) : real(64);
extern proc __atomic_add_fetch(ref x: int(64), val: int(64),
order:memory_order) : int(64);
extern proc __atomic_add_fetch(ref x: uint(64), val: uint(64),
order:memory_order) : uint(64);
extern proc __atomic_add_fetch(ref x: real(32), val: real(32),
order:memory_order) : real(32);
extern proc __atomic_add_fetch(ref x: int(32), val: int(32),
order:memory_order) : int(32);
extern proc __atomic_add_fetch(ref x: uint(32), val: uint(32),
order:memory_order) : uint(32);
extern proc __atomic_add_fetch(ref x: int(16), val: int(16),
order:memory_order) : int(16);
extern proc __atomic_add_fetch(ref x: uint(16), val: uint(16),
order:memory_order) : uint(16);
extern proc __atomic_add_fetch(ref x: int(8), val: int(8),
order:memory_order) : int(8);
extern proc __atomic_add_fetch(ref x: uint(8), val: uint(8),
order:memory_order) : uint(8);
inline proc __atomic_add_fetch(x, val, order) {
compilerError("No fetch and add for this type.");
return 0:x.type;
}
var retval : x.type;
local {
retval = __atomic_add_fetch(x, val, order);
}
return retval;
} else if (xlcish_power_intrinsics()) {
compilerWarning("Completely untested atomics for ", target_compiler_name());
compilerWarning(" Needs isync, eieio, etc. for memory order.");
var retval : x.type;
inline proc __fa(ref x: int(32), in val: int(32)) {
extern proc __fetch_and_add(ref x: int(32), in val: int(32)) : int(32);
return __fetch_and_add(x, val) + val;
}
inline proc __fa(ref x: int(64), in val: int(64)) {
extern proc __fetch_and_addlp(ref x: int(64), in val: int(64)) : int(64);
return __fetch_and_addlp(x, val) + val;
}
inline proc __fa(ref x: real(32), in val: real(32)) {
extern proc __lwarx(ref x: real(32)) : real(32);
extern proc __stwcx(ref x: real(32), in val: real(32)) : int(32);
var outval : real(32);
var newval : real(32);
do {
outval = __lwarx(x);
newval = outval + val;
} while !(__stwcx (x, newval));
return newval;
}
inline proc __fa(ref x: real(64), in val: real(64)) {
extern proc __ldarx(ref x: real(64)) : real(64);
extern proc __stdcx(ref x: real(64), in val: real(64)) : int(64);
var outval : real(64);
var newval : real(64);
do {
outval = __ldarx(x);
newval = outval + val;
} while !(__stdcx (x, newval));
return newval;
}
inline proc __fa(x, val) {
compilerError("No fetch and add for this type.");
}
local {
retval = __fa(x, val);
}
return retval;
} else {
compilerError("Unrecognized target compiler: ", target_compiler_name());
}
}
inline proc atomic_add(ref x, val: x.type, const
order:memory_order=memory_order_seq_cst) : x.type {
// Sufficient.
return atomic_fetch_add(x, val, order);
}
--
Jason Riedy
------------------------------------------------------------------------------
Shape the Mobile Experience: Free Subscription
Software experts and developers: Be at the forefront of tech innovation.
Intel(R) Software Adrenaline delivers strategic insight and game-changing
conversations that shape the rapidly evolving mobile landscape. Sign up now.
http://pubads.g.doubleclick.net/gampad/clk?id=63431311&iu=/4140/ostg.clktrk
_______________________________________________
Chapel-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-users