495 lines
11 KiB
V
495 lines
11 KiB
V
module overflow
|
|
|
|
// Functions for integer arithmetic overflow.
|
|
fn C.__builtin_add_overflow(x any, y any, z voidptr) bool
|
|
fn C.__builtin_sub_overflow(x any, y any, z voidptr) bool
|
|
fn C.__builtin_mul_overflow(x any, y any, z voidptr) bool
|
|
|
|
// add_i8 computes `x` + `y` for i8 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_i8(x i8, y i8) i8 {
|
|
mut res := i8(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) + i64(y)
|
|
res = i8(res64)
|
|
is_overflow = res64 > max_i8 || res64 < min_i8
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(i8(${x}) + i8(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// add_u8 computes `x` + `y` for u8 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_u8(x u8, y u8) u8 {
|
|
mut res := u8(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res = x + y
|
|
is_overflow = res < x
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(u8(${x}) + u8(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_i8 computes `x` - `y` for i8 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_i8(x i8, y i8) i8 {
|
|
mut res := i8(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) - i64(y)
|
|
res = i8(res64)
|
|
is_overflow = res64 > max_i8 || res64 < min_i8
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(i8(${x}) - i8(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_u8 computes `x` - `y` for u8 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_u8(x u8, y u8) u8 {
|
|
mut res := u8(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res = x - y
|
|
is_overflow = x < y
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(u8(${x}) - u8(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_i8 computes `x` * `y` for i8 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_i8(x i8, y i8) i8 {
|
|
mut res := i8(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) * i64(y)
|
|
res = i8(res64)
|
|
is_overflow = res64 > max_i8 || res64 < min_i8
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(i8(${x}) * i8(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_u8 computes `x` * `y` for u8 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_u8(x u8, y u8) u8 {
|
|
mut res := u8(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := u64(x) * u64(y)
|
|
res = u8(res64)
|
|
is_overflow = res64 > max_u8
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(u8(${x}) * u8(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// add_i16 computes `x` + `y` for i16 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_i16(x i16, y i16) i16 {
|
|
mut res := i16(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) + i64(y)
|
|
res = i16(res64)
|
|
is_overflow = res64 > max_i16 || res64 < min_i16
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(i16(${x}) + i16(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// add_u16 computes `x` + `y` for u16 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_u16(x u16, y u16) u16 {
|
|
mut res := u16(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res = x + y
|
|
is_overflow = res < x
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(u16(${x}) + u16(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_i16 computes `x` - `y` for i16 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_i16(x i16, y i16) i16 {
|
|
mut res := i16(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) - i64(y)
|
|
res = i16(res64)
|
|
is_overflow = res64 > max_i16 || res64 < min_i16
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(i16(${x}) - i16(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_u16 computes `x` - `y` for u16 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_u16(x u16, y u16) u16 {
|
|
mut res := u16(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res = x - y
|
|
is_overflow = x < y
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(u16(${x}) - u16(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_i16 computes `x` * `y` for i16 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_i16(x i16, y i16) i16 {
|
|
mut res := i16(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) * i64(y)
|
|
res = i16(res64)
|
|
is_overflow = res64 > max_i16 || res64 < min_i16
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(i16(${x}) * i16(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_u16 computes `x` * `y` for u16 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_u16(x u16, y u16) u16 {
|
|
mut res := u16(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := u64(x) * u64(y)
|
|
res = u16(res64)
|
|
is_overflow = res64 > max_u16
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(u16(${x}) * u16(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// add_i32 computes `x` + `y` for i32 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_i32(x i32, y i32) i32 {
|
|
mut res := i32(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) + i64(y)
|
|
res = i32(res64)
|
|
is_overflow = res64 > max_i32 || res64 < min_i32
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(i32(${x}) + i32(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// add_u32 computes `x` + `y` for u32 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_u32(x u32, y u32) u32 {
|
|
mut res := u32(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res = x + y
|
|
is_overflow = res < x
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(u32(${x}) + u32(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_i32 computes `x` - `y` for i32 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_i32(x i32, y i32) i32 {
|
|
mut res := i32(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) - i64(y)
|
|
res = i32(res64)
|
|
is_overflow = res64 > max_i32 || res64 < min_i32
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(i32(${x}) - i32(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_u32 computes `x` - `y` for u32 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_u32(x u32, y u32) u32 {
|
|
mut res := u32(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res = x - y
|
|
is_overflow = x < y
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(u32(${x}) - u32(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_i32 computes `x` * `y` for i32 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_i32(x i32, y i32) i32 {
|
|
mut res := i32(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := i64(x) * i64(y)
|
|
res = i32(res64)
|
|
is_overflow = res64 > max_i32 || res64 < min_i32
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(i32(${x}) * i32(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_u32 computes `x` * `y` for u32 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_u32(x u32, y u32) u32 {
|
|
mut res := u32(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res64 := u64(x) * u64(y)
|
|
res = u32(res64)
|
|
is_overflow = res64 > max_u32
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(u32(${x}) * u32(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// add_i64 computes `x` + `y` for i64 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_i64(x i64, y i64) i64 {
|
|
mut res := i64(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res = x + y
|
|
is_overflow = (x > 0 && y > 0 && res < 0) || (x < 0 && y < 0 && res > 0)
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(i64(${x}) + i64(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// add_u64 computes `x` + `y` for u64 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn add_u64(x u64, y u64) u64 {
|
|
mut res := u64(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_add_overflow(x, y, &res)
|
|
} $else {
|
|
res = x + y
|
|
is_overflow = res < x
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to add with overflow(u64(${x}) + u64(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_i64 computes `x` - `y` for i64 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_i64(x i64, y i64) i64 {
|
|
mut res := i64(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res = x - y
|
|
is_overflow = (x >= 0 && y < 0 && res < 0) || (x < 0 && y > 0 && res > 0)
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(i64(${x}) - i64(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// sub_u64 computes `x` - `y` for u64 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn sub_u64(x u64, y u64) u64 {
|
|
mut res := u64(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_sub_overflow(x, y, &res)
|
|
} $else {
|
|
res = x - y
|
|
is_overflow = x < y
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to sub with overflow(u64(${x}) - u64(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_i64 computes `x` * `y` for i64 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_i64(x i64, y i64) i64 {
|
|
mut res := i64(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res = x * y
|
|
if x == 0 || y == 0 {
|
|
is_overflow = false
|
|
} else if x == min_i64 {
|
|
is_overflow = y != 1
|
|
} else if y == min_i64 {
|
|
is_overflow = x != 1
|
|
} else {
|
|
if x > 0 {
|
|
if y > 0 {
|
|
is_overflow = x > max_i64 / y
|
|
} else {
|
|
is_overflow = y < min_i64 / x
|
|
}
|
|
} else if x < 0 {
|
|
if y > 0 {
|
|
is_overflow = x < min_i64 / y
|
|
} else {
|
|
is_overflow = y < max_i64 / x
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(i64(${x}) * i64(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
// mul_u64 computes `x` * `y` for u64 values, and panic if overflow occurs
|
|
@[inline]
|
|
fn mul_u64(x u64, y u64) u64 {
|
|
mut res := u64(0)
|
|
mut is_overflow := false
|
|
$if gcc || clang {
|
|
is_overflow = C.__builtin_mul_overflow(x, y, &res)
|
|
} $else {
|
|
res = x * y
|
|
is_overflow = y != 0 && x > max_u64 / y
|
|
}
|
|
if is_overflow {
|
|
panic('attempt to mul with overflow(u64(${x}) * u64(${y}))')
|
|
}
|
|
return res
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
// These are here to prevent cgen errors for `./v -check-overflow vlib/math/vec/vec4_test.v`
|
|
// TODO: check for correctness and add tests. Improve markused so it keeps them, when they are used.
|
|
@[inline; markused]
|
|
fn add_int(x int, y int) int {
|
|
return add_i32(x, y)
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn sub_int(x int, y int) int {
|
|
return sub_i32(x, y)
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn mul_int(x int, y int) int {
|
|
return mul_i32(x, y)
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn add_f32(x f32, y f32) f32 {
|
|
return x + y
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn sub_f32(x f32, y f32) f32 {
|
|
return x - y
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn mul_f32(x f32, y f32) f32 {
|
|
return x * y
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn add_f64(x f64, y f64) f64 {
|
|
return x + y
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn sub_f64(x f64, y f64) f64 {
|
|
return x - y
|
|
}
|
|
|
|
@[inline; markused]
|
|
fn mul_f64(x f64, y f64) f64 {
|
|
return x * y
|
|
}
|