mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Use unsigned LLVM intrinsic arithmetic for unsigned integers
Closes #2331
This commit is contained in:
parent
2f3919c870
commit
abe42781d5
3 changed files with 86 additions and 25 deletions
|
@ -201,24 +201,28 @@ macro_rules! float_intrinsic {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! int_intrinsic {
|
macro_rules! int_intrinsic {
|
||||||
($name:literal) => {{
|
($signed_name:literal, $unsigned_name:literal) => {{
|
||||||
let mut output = IntrinsicName::default();
|
let mut output = IntrinsicName::default();
|
||||||
|
|
||||||
// These are LLVM types which don't include
|
// The indeces align with the `Index` impl for `IntrinsicName`.
|
||||||
// u64 for example
|
output.options[4] = concat!($unsigned_name, ".i8");
|
||||||
output.options[4] = concat!($name, ".i8");
|
output.options[5] = concat!($unsigned_name, ".i16");
|
||||||
output.options[5] = concat!($name, ".i16");
|
output.options[6] = concat!($unsigned_name, ".i32");
|
||||||
output.options[6] = concat!($name, ".i32");
|
output.options[7] = concat!($unsigned_name, ".i64");
|
||||||
output.options[7] = concat!($name, ".i64");
|
output.options[8] = concat!($unsigned_name, ".i128");
|
||||||
output.options[8] = concat!($name, ".i128");
|
|
||||||
output.options[9] = concat!($name, ".i8");
|
output.options[9] = concat!($signed_name, ".i8");
|
||||||
output.options[10] = concat!($name, ".i16");
|
output.options[10] = concat!($signed_name, ".i16");
|
||||||
output.options[11] = concat!($name, ".i32");
|
output.options[11] = concat!($signed_name, ".i32");
|
||||||
output.options[12] = concat!($name, ".i64");
|
output.options[12] = concat!($signed_name, ".i64");
|
||||||
output.options[13] = concat!($name, ".i128");
|
output.options[13] = concat!($signed_name, ".i128");
|
||||||
|
|
||||||
output
|
output
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
($name:literal) => {
|
||||||
|
int_intrinsic!($name, $name)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const NUM_ASIN: IntrinsicName = float_intrinsic!("roc_builtins.num.asin");
|
pub const NUM_ASIN: IntrinsicName = float_intrinsic!("roc_builtins.num.asin");
|
||||||
|
|
|
@ -562,19 +562,19 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
|
||||||
});
|
});
|
||||||
add_float_intrinsic(ctx, module, &LLVM_FLOOR, |t| t.fn_type(&[t.into()], false));
|
add_float_intrinsic(ctx, module, &LLVM_FLOOR, |t| t.fn_type(&[t.into()], false));
|
||||||
|
|
||||||
add_int_intrinsic(ctx, module, &LLVM_SADD_WITH_OVERFLOW, |t| {
|
add_int_intrinsic(ctx, module, &LLVM_ADD_WITH_OVERFLOW, |t| {
|
||||||
let fields = [t.into(), i1_type.into()];
|
let fields = [t.into(), i1_type.into()];
|
||||||
ctx.struct_type(&fields, false)
|
ctx.struct_type(&fields, false)
|
||||||
.fn_type(&[t.into(), t.into()], false)
|
.fn_type(&[t.into(), t.into()], false)
|
||||||
});
|
});
|
||||||
|
|
||||||
add_int_intrinsic(ctx, module, &LLVM_SSUB_WITH_OVERFLOW, |t| {
|
add_int_intrinsic(ctx, module, &LLVM_SUB_WITH_OVERFLOW, |t| {
|
||||||
let fields = [t.into(), i1_type.into()];
|
let fields = [t.into(), i1_type.into()];
|
||||||
ctx.struct_type(&fields, false)
|
ctx.struct_type(&fields, false)
|
||||||
.fn_type(&[t.into(), t.into()], false)
|
.fn_type(&[t.into(), t.into()], false)
|
||||||
});
|
});
|
||||||
|
|
||||||
add_int_intrinsic(ctx, module, &LLVM_SMUL_WITH_OVERFLOW, |t| {
|
add_int_intrinsic(ctx, module, &LLVM_MUL_WITH_OVERFLOW, |t| {
|
||||||
let fields = [t.into(), i1_type.into()];
|
let fields = [t.into(), i1_type.into()];
|
||||||
ctx.struct_type(&fields, false)
|
ctx.struct_type(&fields, false)
|
||||||
.fn_type(&[t.into(), t.into()], false)
|
.fn_type(&[t.into(), t.into()], false)
|
||||||
|
@ -602,9 +602,12 @@ static LLVM_STACK_SAVE: &str = "llvm.stacksave";
|
||||||
static LLVM_SETJMP: &str = "llvm.eh.sjlj.setjmp";
|
static LLVM_SETJMP: &str = "llvm.eh.sjlj.setjmp";
|
||||||
pub static LLVM_LONGJMP: &str = "llvm.eh.sjlj.longjmp";
|
pub static LLVM_LONGJMP: &str = "llvm.eh.sjlj.longjmp";
|
||||||
|
|
||||||
const LLVM_SADD_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.sadd.with.overflow");
|
const LLVM_ADD_WITH_OVERFLOW: IntrinsicName =
|
||||||
const LLVM_SSUB_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.ssub.with.overflow");
|
int_intrinsic!("llvm.sadd.with.overflow", "llvm.uadd.with.overflow");
|
||||||
const LLVM_SMUL_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.smul.with.overflow");
|
const LLVM_SUB_WITH_OVERFLOW: IntrinsicName =
|
||||||
|
int_intrinsic!("llvm.ssub.with.overflow", "llvm.usub.with.overflow");
|
||||||
|
const LLVM_MUL_WITH_OVERFLOW: IntrinsicName =
|
||||||
|
int_intrinsic!("llvm.smul.with.overflow", "llvm.umul.with.overflow");
|
||||||
|
|
||||||
fn add_intrinsic<'ctx>(
|
fn add_intrinsic<'ctx>(
|
||||||
module: &Module<'ctx>,
|
module: &Module<'ctx>,
|
||||||
|
@ -6366,7 +6369,7 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
NumAdd => {
|
NumAdd => {
|
||||||
let result = env
|
let result = env
|
||||||
.call_intrinsic(
|
.call_intrinsic(
|
||||||
&LLVM_SADD_WITH_OVERFLOW[int_width],
|
&LLVM_ADD_WITH_OVERFLOW[int_width],
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
)
|
)
|
||||||
.into_struct_value();
|
.into_struct_value();
|
||||||
|
@ -6375,13 +6378,13 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
NumAddWrap => bd.build_int_add(lhs, rhs, "add_int_wrap").into(),
|
NumAddWrap => bd.build_int_add(lhs, rhs, "add_int_wrap").into(),
|
||||||
NumAddChecked => env.call_intrinsic(
|
NumAddChecked => env.call_intrinsic(
|
||||||
&LLVM_SADD_WITH_OVERFLOW[int_width],
|
&LLVM_ADD_WITH_OVERFLOW[int_width],
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
),
|
),
|
||||||
NumSub => {
|
NumSub => {
|
||||||
let result = env
|
let result = env
|
||||||
.call_intrinsic(
|
.call_intrinsic(
|
||||||
&LLVM_SSUB_WITH_OVERFLOW[int_width],
|
&LLVM_SUB_WITH_OVERFLOW[int_width],
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
)
|
)
|
||||||
.into_struct_value();
|
.into_struct_value();
|
||||||
|
@ -6390,13 +6393,13 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
NumSubWrap => bd.build_int_sub(lhs, rhs, "sub_int").into(),
|
NumSubWrap => bd.build_int_sub(lhs, rhs, "sub_int").into(),
|
||||||
NumSubChecked => env.call_intrinsic(
|
NumSubChecked => env.call_intrinsic(
|
||||||
&LLVM_SSUB_WITH_OVERFLOW[int_width],
|
&LLVM_SUB_WITH_OVERFLOW[int_width],
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
),
|
),
|
||||||
NumMul => {
|
NumMul => {
|
||||||
let result = env
|
let result = env
|
||||||
.call_intrinsic(
|
.call_intrinsic(
|
||||||
&LLVM_SMUL_WITH_OVERFLOW[int_width],
|
&LLVM_MUL_WITH_OVERFLOW[int_width],
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
)
|
)
|
||||||
.into_struct_value();
|
.into_struct_value();
|
||||||
|
@ -6405,7 +6408,7 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
NumMulWrap => bd.build_int_mul(lhs, rhs, "mul_int").into(),
|
NumMulWrap => bd.build_int_mul(lhs, rhs, "mul_int").into(),
|
||||||
NumMulChecked => env.call_intrinsic(
|
NumMulChecked => env.call_intrinsic(
|
||||||
&LLVM_SMUL_WITH_OVERFLOW[int_width],
|
&LLVM_MUL_WITH_OVERFLOW[int_width],
|
||||||
&[lhs.into(), rhs.into()],
|
&[lhs.into(), rhs.into()],
|
||||||
),
|
),
|
||||||
NumGt => bd.build_int_compare(SGT, lhs, rhs, "int_gt").into(),
|
NumGt => bd.build_int_compare(SGT, lhs, rhs, "int_gt").into(),
|
||||||
|
|
|
@ -2101,3 +2101,57 @@ fn num_to_str() {
|
||||||
RocStr
|
RocStr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn u8_addition_greater_than_i8() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : U8
|
||||||
|
x = 100
|
||||||
|
y : U8
|
||||||
|
y = 100
|
||||||
|
x + y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
200,
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn u8_sub_greater_than_i8() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : U8
|
||||||
|
x = 255
|
||||||
|
y : U8
|
||||||
|
y = 55
|
||||||
|
x - y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
200,
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn u8_mul_greater_than_i8() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : U8
|
||||||
|
x = 40
|
||||||
|
y : U8
|
||||||
|
y = 5
|
||||||
|
x * y
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
200,
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue