[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

Reply via email to