diff --git a/lib/std/core/values.c3 b/lib/std/core/values.c3
index f65ec893e..26cd10968 100644
--- a/lib/std/core/values.c3
+++ b/lib/std/core/values.c3
@@ -2,6 +2,10 @@ module std::core::values;
macro TypeKind @typekind(#value) @builtin => $typeof(#value).kindof;
macro bool @typeis(#value, $Type) @builtin => $typeof(#value).typeid == $Type.typeid;
+/**
+ * Return true if two values have the same type before any conversions.
+ **/
+macro bool @is_same_type(#value1, #value2) => $typeof(#value1).typeid == $typeof(#value2).typeid;
macro bool @is_bool(#value) => types::is_bool($typeof(#value));
macro bool @is_int(#value) => types::is_int($typeof(#value));
macro bool @convertable_to(#a, #b) => $checks($typeof(#b) x = #a);
@@ -9,6 +13,7 @@ macro bool @is_floatlike(#value) => types::is_floatlike($typeof(#value));
macro bool @is_float(#value) => types::is_float($typeof(#value));
macro bool @is_promotable_to_floatlike(#value) => types::is_promotable_to_floatlike($typeof(#value));
macro bool @is_promotable_to_float(#value) => types::is_promotable_to_float($typeof(#value));
+macro bool @is_vector(#value) => types::is_vector($typeof(#value));
macro bool @is_same_vector_type(#value1, #value2) => types::is_same_vector_type($typeof(#value1), $typeof(#value2));
macro promote_int(x)
{
diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3
index c4b827a26..4a032ac6b 100644
--- a/lib/std/math/math.c3
+++ b/lib/std/math/math.c3
@@ -80,6 +80,11 @@ enum RoundingMode : int
TOWARD_NEG_INFINITY
}
+fault MathError
+{
+ OVERFLOW,
+}
+
fault MatrixError
{
MATRIX_INVERSE_DOESNT_EXIST,
@@ -545,6 +550,23 @@ macro normalize(x) @private
return x * (1 / len);
}
+/**
+ * Use a mask to select values from either "then" or "else" vectors.
+ *
+ * @param mask "The mask to use for the select, 'true' will pick the then_value, 'false' the else_value"
+ * @param then_value "The vector to get elements from where the mask is 'true'"
+ * @param else_value "The vector to get elements from where the mask is 'false'"
+ * @require values::@is_vector(then_value) && values::@is_vector(else_value) "'Then' and 'else' must be vectors."
+ * @require values::@is_same_type(then_value, else_value) "'Then' and 'else' vectors must be of the same type."
+ * @require then_value.len == mask.len "Mask and selected vectors must be of the same width."
+ *
+ * @return "a vector of the same type as then/else"
+ **/
+macro select(bool[<*>] mask, then_value, else_value)
+{
+ return $$select(mask, then_value, else_value);
+}
+
macro float float.ceil(float x) => $$ceil(x);
macro float float.clamp(float x, float lower, float upper) => $$max(lower, $$min(x, upper));
macro float float.copysign(float mag, float sgn) => $$copysign(mag, sgn);
@@ -798,52 +820,82 @@ macro char char.sat_add(char x, char y) => $$sat_add(x, y);
macro char char.sat_sub(char x, char y) => $$sat_sub(x, y);
macro char char.sat_mul(char x, char y) => $$sat_mul(x, y);
macro char char.sat_shl(char x, char y) => $$sat_shl(x, y);
+macro char! char.overflow_add(char x, char y) => overflow_add_helper(x, y);
+macro char! char.overflow_sub(char x, char y) => overflow_sub_helper(x, y);
+macro char! char.overflow_mul(char x, char y) => overflow_mul_helper(x, y);
+
macro ichar ichar.sat_add(ichar x, ichar y) => $$sat_add(x, y);
macro ichar ichar.sat_sub(ichar x, ichar y) => $$sat_sub(x, y);
macro ichar ichar.sat_mul(ichar x, ichar y) => $$sat_mul(x, y);
macro ichar ichar.sat_shl(ichar x, ichar y) => $$sat_shl(x, y);
+macro ichar! ichar.overflow_add(ichar x, ichar y) => overflow_add_helper(x, y);
+macro ichar! ichar.overflow_sub(ichar x, ichar y) => overflow_sub_helper(x, y);
+macro ichar! ichar.overflow_mul(ichar x, ichar y) => overflow_mul_helper(x, y);
macro ushort ushort.sat_add(ushort x, ushort y) => $$sat_add(x, y);
macro ushort ushort.sat_sub(ushort x, ushort y) => $$sat_sub(x, y);
macro ushort ushort.sat_mul(ushort x, ushort y) => $$sat_mul(x, y);
macro ushort ushort.sat_shl(ushort x, ushort y) => $$sat_shl(x, y);
+macro ushort! ushort.overflow_add(ushort x, ushort y) => overflow_add_helper(x, y);
+macro ushort! ushort.overflow_sub(ushort x, ushort y) => overflow_sub_helper(x, y);
+macro ushort! ushort.overflow_mul(ushort x, ushort y) => overflow_mul_helper(x, y);
macro short short.sat_add(short x, short y) => $$sat_add(x, y);
macro short short.sat_sub(short x, short y) => $$sat_sub(x, y);
macro short short.sat_mul(short x, short y) => $$sat_mul(x, y);
macro short short.sat_shl(short x, short y) => $$sat_shl(x, y);
+macro short! short.overflow_add(short x, short y) => overflow_add_helper(x, y);
+macro short! short.overflow_sub(short x, short y) => overflow_sub_helper(x, y);
+macro short! short.overflow_mul(short x, short y) => overflow_mul_helper(x, y);
macro uint uint.sat_add(uint x, uint y) => $$sat_add(x, y);
macro uint uint.sat_sub(uint x, uint y) => $$sat_sub(x, y);
macro uint uint.sat_mul(uint x, uint y) => $$sat_mul(x, y);
macro uint uint.sat_shl(uint x, uint y) => $$sat_shl(x, y);
+macro uint! uint.overflow_add(uint x, uint y) => overflow_add_helper(x, y);
+macro uint! uint.overflow_sub(uint x, uint y) => overflow_sub_helper(x, y);
+macro uint! uint.overflow_mul(uint x, uint y) => overflow_mul_helper(x, y);
macro int int.sat_add(int x, int y) => $$sat_add(x, y);
macro int int.sat_sub(int x, int y) => $$sat_sub(x, y);
macro int int.sat_mul(int x, int y) => $$sat_mul(x, y);
macro int int.sat_shl(int x, int y) => $$sat_shl(x, y);
+macro int! int.overflow_add(int x, int y) => overflow_add_helper(x, y);
+macro int! int.overflow_sub(int x, int y) => overflow_sub_helper(x, y);
+macro int! int.overflow_mul(int x, int y) => overflow_mul_helper(x, y);
macro ulong ulong.sat_add(ulong x, ulong y) => $$sat_add(x, y);
macro ulong ulong.sat_sub(ulong x, ulong y) => $$sat_sub(x, y);
macro ulong ulong.sat_mul(ulong x, ulong y) => $$sat_mul(x, y);
macro ulong ulong.sat_shl(ulong x, ulong y) => $$sat_shl(x, y);
+macro ulong! ulong.overflow_add(ulong x, ulong y) => overflow_add_helper(x, y);
+macro ulong! ulong.overflow_sub(ulong x, ulong y) => overflow_sub_helper(x, y);
+macro ulong! ulong.overflow_mul(ulong x, ulong y) => overflow_mul_helper(x, y);
macro long long.sat_add(long x, long y) => $$sat_add(x, y);
macro long long.sat_sub(long x, long y) => $$sat_sub(x, y);
macro long long.sat_mul(long x, long y) => $$sat_mul(x, y);
macro long long.sat_shl(long x, long y) => $$sat_shl(x, y);
+macro long! long.overflow_add(long x, long y) => overflow_add_helper(x, y);
+macro long! long.overflow_sub(long x, long y) => overflow_sub_helper(x, y);
+macro long! long.overflow_mul(long x, long y) => overflow_mul_helper(x, y);
macro uint128 uint128.sat_add(uint128 x, uint128 y) => $$sat_add(x, y);
macro uint128 uint128.sat_sub(uint128 x, uint128 y) => $$sat_sub(x, y);
macro uint128 uint128.sat_mul(uint128 x, uint128 y) => $$sat_mul(x, y);
macro uint128 uint128.sat_shl(uint128 x, uint128 y) => $$sat_shl(x, y);
+macro uint128! uint128.overflow_add(uint128 x, uint128 y) => overflow_add_helper(x, y);
+macro uint128! uint128.overflow_sub(uint128 x, uint128 y) => overflow_sub_helper(x, y);
+macro uint128! uint128.overflow_mul(uint128 x, uint128 y) => overflow_mul_helper(x, y);
macro int128 int128.sat_add(int128 x, int128 y) => $$sat_add(x, y);
macro int128 int128.sat_sub(int128 x, int128 y) => $$sat_sub(x, y);
macro int128 int128.sat_mul(int128 x, int128 y) => $$sat_mul(x, y);
macro int128 int128.sat_shl(int128 x, int128 y) => $$sat_shl(x, y);
-
+macro int128! int128.overflow_add(int128 x, int128 y) => overflow_add_helper(x, y);
+macro int128! int128.overflow_sub(int128 x, int128 y) => overflow_sub_helper(x, y);
+macro int128! int128.overflow_mul(int128 x, int128 y) => overflow_mul_helper(x, y);
/**
* @require values::@is_int(x) `The input must be an integer`
**/
@@ -986,4 +1038,25 @@ fn float _frexpf(float x, int* e)
i |= 0x3f000000u32;
return bitcast(i, float);
}
-}
\ No newline at end of file
+}
+
+macro overflow_add_helper(x, y) @local
+{
+ $typeof(x) res @noinit;
+ if ($$overflow_add(x, y, &res)) return MathError.OVERFLOW?;
+ return res;
+}
+
+macro overflow_sub_helper(x, y) @local
+{
+ $typeof(x) res @noinit;
+ if ($$overflow_sub(x, y, &res)) return MathError.OVERFLOW?;
+ return res;
+}
+
+macro overflow_mul_helper(x, y) @local
+{
+ $typeof(x) res @noinit;
+ if ($$overflow_mul(x, y, &res)) return MathError.OVERFLOW?;
+ return res;
+}
diff --git a/releasenotes.md b/releasenotes.md
index 9dc7dc277..18993edd1 100644
--- a/releasenotes.md
+++ b/releasenotes.md
@@ -3,6 +3,7 @@
## 0.5.0 Change List
### Changes / improvements
+- '$$select' builtin for vector masked select.
- Subtype matching in type switches.
- Added parentof typeid property.
- Slice assignment is expanded.
diff --git a/src/build/build_options.c b/src/build/build_options.c
index 72b7099c1..8f1f8c83b 100644
--- a/src/build/build_options.c
+++ b/src/build/build_options.c
@@ -147,6 +147,7 @@ static void usage(void)
OUTPUT(" --memory-env=