-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #81 from Sparrow-lang/parallel_fix
Parallel fix
- Loading branch information
Showing
40 changed files
with
1,781 additions
and
1,835 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,143 +1,102 @@ | ||
module par.atomic; | ||
module par.atomic | ||
|
||
import config | ||
import "atomic.llvm" | ||
|
||
using AtomicInt = Atomic(Int) | ||
using AtomicLong = Atomic(Long) | ||
|
||
concept AtomicType(x) if x._IsAtomicType | ||
concept AtomicInteger(x) if x._IsAtomicType && Integer(#$x.ValueType) | ||
concept NonStdAtomicType(x) if x._IsAtomicType && x.ValueType != x._UnderlyingType | ||
|
||
datatype Atomic(T: Type) if sizeOf(T) <= 8 | ||
using _IsAtomicType = true | ||
using ValueType = T | ||
using _UnderlyingType = _Impl.AtomicTypeTraits(T)._UnderlyingType | ||
|
||
_value: _UnderlyingType | ||
|
||
[protected] | ||
fun ctor(this: @Atomic, v: this.ValueType) | ||
_value ctor _toUnderlying(this, v) | ||
|
||
fun =(lhs: @AtomicType, rhs: typeOf(lhs)) | ||
lhs store (rhs load) | ||
//! Stores a value inside the given atomic, using the assignment operator | ||
fun =(this: @AtomicType, val: this.ValueType) = this store val | ||
|
||
//! Loads the value from an atomic; returns a non-atomic value | ||
[native("_Atomic_load32")] fun load(this: @AtomicInt): Int; | ||
[native("_Atomic_load64")] fun load(this: @AtomicLong): Long; | ||
fun load(this: @NonStdAtomicType): ValueType \ | ||
= this._fromUnderlying(this._baseAtomic load) | ||
|
||
//! Stores a value inside the given atomic | ||
[native("_Atomic_store32")] fun store(this: @AtomicInt, newVal: Int); | ||
[native("_Atomic_store64")] fun store(this: @AtomicLong, newVal: Long); | ||
fun store(this: @NonStdAtomicType, newVal: AnyType) | ||
this._baseAtomic store this._toUnderlying(newVal) | ||
|
||
//! Fetches the current value of an atomic, and stores a new value in the atomic | ||
[native("_Atomic_fetchAndStore32")] fun fetchAndStore(x: @AtomicInt, newVal: Int): Int; | ||
[native("_Atomic_fetchAndStore64")] fun fetchAndStore(x: @AtomicLong, newVal: Long): Long; | ||
fun fetchAndStore(x: @NonStdAtomicType, newVal: AnyType): x.ValueType \ | ||
= x._fromUnderlying(x._baseAtomic fetchAndStore x._toUnderlying(newVal)) | ||
|
||
//! Fetch the value of the atomic, and then add the given value to it | ||
[native("_Atomic_fetchAndAdd32")] fun fetchAndAdd(x: @AtomicInt, val: Int): Int; | ||
[native("_Atomic_fetchAndAdd64")] fun fetchAndAdd(x: @AtomicLong, val: Long): Long; | ||
fun fetchAndAdd(x: @NonStdAtomicType, val: AnyType): x.ValueType \ | ||
= x._fromUnderlying(x._baseAtomic fetchAndAdd x._toUnderlying(val)) \ | ||
if Integer(#$x.ValueType) | ||
|
||
//! Fetch the value of the atomic and the increment it | ||
fun fetchAndIncrement(x: @AtomicInteger) = x fetchAndAdd 1 | ||
//! Fetch the value of the atomic and the decrement it | ||
fun fetchAndDecrement(x: @AtomicInteger) = x fetchAndAdd -1 | ||
|
||
//! Adds the given value to the atomic | ||
fun += (x: @AtomicInteger, val: AnyType) { x fetchAndAdd val; } | ||
//! Subtracts the given value to the atomic | ||
fun -= (x: @AtomicInteger, val: AnyType) { x fetchAndAdd (-val); } | ||
|
||
//! Increment the atomic value; returns the new value | ||
fun pre_++(x: @AtomicInteger): x.ValueType = (x fetchAndIncrement)+1 | ||
//! Increment the atomic value; returns the old value | ||
fun post_++(x: @AtomicInteger): x.ValueType = (x fetchAndIncrement) | ||
|
||
//! Decrement the atomic value; returns the new value | ||
fun pre_--(x: @AtomicInteger): x.ValueType = (x fetchAndDecrement)-1 | ||
//! Decrement the atomic value; returns the old value | ||
fun post_--(x: @AtomicInteger): x.ValueType = (x fetchAndDecrement) | ||
|
||
fun _toUnderlying(this: @Atomic, val: this.ValueType): this._UnderlyingType | ||
var res: _UnderlyingType | ||
reinterpretCast(@ValueType, res) = val | ||
return res | ||
fun _fromUnderlying(this: @Atomic, val: this._UnderlyingType): this.ValueType | ||
var res: ValueType | ||
res = reinterpretCast(@ValueType, val) | ||
return res | ||
fun _baseAtomic(this: @Atomic): @Atomic(_UnderlyingType) = reinterpretCast(@Atomic(_UnderlyingType), this) | ||
|
||
import config; | ||
import "atomic.llvm"; | ||
|
||
[initCtor] datatype Atomic(T: Type) if T == Int { | ||
using _IsAtomicType = true; | ||
using ValueType = Int; | ||
|
||
//! The value for this atomic | ||
_value: ValueType; | ||
} | ||
|
||
[initCtor] datatype Atomic(T: Type) if T == Long { | ||
using _IsAtomicType = true; | ||
using ValueType = Long; | ||
|
||
//! The value for this atomic | ||
_value: ValueType; | ||
} | ||
|
||
datatype Atomic(T: Type) if T != Int && T != Long && sizeOf(T) <= 8 { | ||
using _IsAtomicType = true; | ||
|
||
using ValueType = T; | ||
|
||
using _UnderlyingType = Impl.AtomicTypeTraits(T)._UnderlyingType; | ||
using _BaseAtomicType = Impl.AtomicTypeTraits(T)._BaseAtomicType; | ||
|
||
//! The value for this atomic | ||
_value: _UnderlyingType; | ||
|
||
} | ||
|
||
fun ctor(this: @Atomic, v: this.ValueType) | ||
_value construct _toUnderlying(v); | ||
|
||
fun _toUnderlying(this: @Atomic, val: this.ValueType): this._UnderlyingType { | ||
var res: _UnderlyingType; | ||
reinterpretCast(@T, res) = val; | ||
return res; | ||
} | ||
fun _fromUnderlying(this: @Atomic, val: this._UnderlyingType): T { | ||
var res: ValueType; | ||
res = reinterpretCast(@ValueType, val); | ||
return res; | ||
} | ||
fun _baseAtomic(this: @Atomic): @_BaseAtomicType = reinterpretCast(@_BaseAtomicType, this); | ||
|
||
using AtomicInt = Atomic(Int); | ||
using AtomicLong = Atomic(Long); | ||
|
||
concept AtomicType(x) if x._IsAtomicType; | ||
concept AtomicInteger(x) if x._IsAtomicType && Integer(#$x.ValueType); | ||
concept NonStdAtomicType(x) if x._IsAtomicType && x.ValueType != x._UnderlyingType; | ||
|
||
fun =(lhs: @AtomicType, rhs: AtomicType) { lhs store (rhs load); } | ||
//! Compare the atomic value with the given comparand; if equal store 'newVal' and return true; if not equal returns false | ||
[native("_Atomic_compareAndSwap32")] fun compareAndSwap(x: @AtomicInt, newVal, comparand: Int): Bool; | ||
[native("_Atomic_compareAndSwap64")] fun compareAndSwap(x: @AtomicLong, newVal, comparand: Long): Bool; | ||
fun compareAndSwap(x: @NonStdAtomicType, newVal, comparand: AnyType): Bool \ | ||
= compareAndSwap(x._baseAtomic, x._toUnderlying(newVal), x._toUnderlying(comparand)) | ||
|
||
//! Converts a regular value to an atomic value | ||
//! Returns the reference to the same memory address | ||
//! Used to make it possible to use atomic operations | ||
fun asAtomic(val: @AnyType): @Atomic(typeOf(val)) \ | ||
= reinterpretCast(@Atomic(typeOf(val)), val) \ | ||
if sizeOf(val) == sizeOf(Atomic(typeOf(val))); | ||
|
||
//! Loads the value from an atomic; returns a non-atomic value | ||
[native("_Atomic_load32")] fun load(x: @AtomicInt): Int; | ||
[native("_Atomic_load64")] fun load(x: @AtomicLong): Long; | ||
fun load(x: @NonStdAtomicType): x.ValueType \ | ||
= x._fromUnderlying(x._baseAtomic load); | ||
|
||
//! Stores a value inside the given atomic | ||
[native("_Atomic_store32")] fun store(x: @AtomicInt, newVal: Int); | ||
[native("_Atomic_store64")] fun store(x: @AtomicLong, newVal: Long); | ||
fun store(x: @NonStdAtomicType, newVal: AnyType) | ||
{ x._baseAtomic store x._toUnderlying(newVal); } | ||
|
||
//! Stores a value inside the given atomic, using the assignment operator | ||
fun =(x: @AtomicType, val: AnyType) = store(x, val); | ||
|
||
//! Fetches the current value of an atomic, and stores a new value in the atomic | ||
[native("_Atomic_fetchAndStore32")] fun fetchAndStore(x: @AtomicInt, newVal: Int): Int; | ||
[native("_Atomic_fetchAndStore64")] fun fetchAndStore(x: @AtomicLong, newVal: Long): Long; | ||
fun fetchAndStore(x: @NonStdAtomicType, newVal: AnyType): x.ValueType \ | ||
= x._fromUnderlying(x._baseAtomic fetchAndStore x._toUnderlying(newVal)); | ||
fun asAtomic(val: @AnyType): @Atomic(-@typeOf(val)) if sizeOf(val) == sizeOf(Atomic(-@typeOf(val))) | ||
return reinterpretCast(@Atomic(-@typeOf(val)), val) | ||
|
||
//! Compare the atomic value with the given comparand; if equal store 'newVal' and return true; if not equal returns false | ||
[native("_Atomic_compareAndSwap32")] fun compareAndSwap(x: @AtomicInt, newVal, comparand: Int): Bool; | ||
[native("_Atomic_compareAndSwap64")] fun compareAndSwap(x: @AtomicLong, newVal, comparand: Long): Bool; | ||
fun compareAndSwap(x: @NonStdAtomicType, newVal, comparand: AnyType): Bool \ | ||
= compareAndSwap(x._baseAtomic, x._toUnderlying(newVal), x._toUnderlying(comparand)); | ||
|
||
//! Fetch the value of the atomic, and then add the given value to it | ||
[native("_Atomic_fetchAndAdd32")] fun fetchAndAdd(x: @AtomicInt, val: Int): Int; | ||
[native("_Atomic_fetchAndAdd64")] fun fetchAndAdd(x: @AtomicLong, val: Long): Long; | ||
fun fetchAndAdd(x: @NonStdAtomicType, val: AnyType): x.ValueType \ | ||
= x._fromUnderlying(x._baseAtomic fetchAndAdd x._toUnderlying(val)) \ | ||
if Integer(#$x.ValueType); | ||
|
||
//! Fetch the value of the atomic and the increment it | ||
fun fetchAndIncrement(x: @AtomicInteger) = x fetchAndAdd 1; | ||
//! Fetch the value of the atomic and the decrement it | ||
fun fetchAndDecrement(x: @AtomicInteger) = x fetchAndAdd -1; | ||
|
||
//! Adds the given value to the atomic | ||
fun += (x: @AtomicInteger, val: AnyType) { x fetchAndAdd val; } | ||
//! Subtracts the given value to the atomic | ||
fun -= (x: @AtomicInteger, val: AnyType) { x fetchAndAdd (-val); } | ||
|
||
//! Increment the atomic value; returns the new value | ||
fun pre_++(x: @AtomicInteger): x.ValueType = (x fetchAndIncrement)+1; | ||
//! Increment the atomic value; returns the old value | ||
fun post_++(x: @AtomicInteger): x.ValueType = (x fetchAndIncrement); | ||
|
||
//! Decrement the atomic value; returns the new value | ||
fun pre_--(x: @AtomicInteger): x.ValueType = (x fetchAndDecrement)-1; | ||
//! Decrement the atomic value; returns the old value | ||
fun post_--(x: @AtomicInteger): x.ValueType = (x fetchAndDecrement); | ||
|
||
package Impl { | ||
datatype AtomicTypeTraits(T: Type) if sizeOf(T) <= 4 { | ||
using _UnderlyingType = Int; | ||
using _BaseAtomicType = Atomic(Int); | ||
} | ||
datatype AtomicTypeTraits(T: Type) if sizeOf(T) == 8 { | ||
using _UnderlyingType = Long; | ||
using _BaseAtomicType = Atomic(Long); | ||
} | ||
|
||
fun packAtomic(x: @NonStdAtomicType): @AtomicTypeTraits(x.ValueType) \ | ||
= reinterpretCast(@AtomicTypeTraits(x.ValueType), x); | ||
|
||
fun pack(x: @NonStdAtomicType, val: AnyType): AtomicTypeTraits(x.ValueType)._UnderlyingType { | ||
var res: AtomicTypeTraits(x.ValueType)._UnderlyingType; | ||
reinterpretCast(@AtomicTypeTraits(x.ValueType)._UnderlyingType, res) = val; | ||
return res; | ||
} | ||
fun unpack(x: @NonStdAtomicType, val: AnyType): x.ValueType { | ||
var res: x.ValueType; | ||
res = reinterpretCast(@AtomicTypeTraits(x.ValueType)._UnderlyingType, val); | ||
return res; | ||
} | ||
} | ||
|
||
package _Impl | ||
datatype AtomicTypeTraits(T: Type) if sizeOf(T) <= 4 | ||
using _UnderlyingType = Int | ||
datatype AtomicTypeTraits(T: Type) if sizeOf(T) == 8 | ||
using _UnderlyingType = Long |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,27 @@ | ||
module par.config; | ||
module par.config | ||
|
||
import std.ptr; | ||
|
||
package Impl | ||
{ | ||
using _SC_NPROCESSORS_ONLN = 58; | ||
|
||
[native("sysconf")] fun sysconf(name: Int): Long; | ||
} | ||
|
||
datatype NativeThreadHandle = Byte Ptr; // Opaque type | ||
import std.ptr | ||
|
||
datatype NativeThreadHandle = Byte Ptr // Opaque type | ||
|
||
fun >>(h: NativeThreadHandle, os: @OutStream) | ||
{ | ||
if ( h.impl.isSet ) | ||
os << mkStreamRefWrapper(h.impl.get); | ||
os << mkStreamRefWrapper(h.impl.get) | ||
else | ||
os << "null"; | ||
} | ||
os << "null" | ||
|
||
using InvalidThreadHandle = NativeThreadHandle(); | ||
using InvalidThreadHandle = NativeThreadHandle() | ||
|
||
|
||
//! Get the number of available logical CPU cores for our process | ||
//! This dictates how much parallelism we have to be exploit | ||
fun getAvailableCoresNum(): UInt { | ||
var maxProcs: Long = Impl.sysconf(Impl._SC_NPROCESSORS_ONLN); | ||
return ife(maxProcs<1, UInt(1), UInt(maxProcs)); | ||
fun getAvailableCoresNum(): UInt | ||
var maxProcs: Long = _Impl.sysconf(_Impl._SC_NPROCESSORS_ONLN) | ||
return ife(maxProcs<1, UInt(1), UInt(maxProcs)) | ||
// TODO: also consider process affinity | ||
} | ||
|
||
package _Impl | ||
using _SC_NPROCESSORS_ONLN = 58 | ||
|
||
[native("sysconf")] fun sysconf(name: Int): Long | ||
|
Oops, something went wrong.