Merge pull request #1796 from rtfeldman/divTruncate

Intrinsics for more types
This commit is contained in:
Richard Feldman 2021-10-20 21:33:44 -04:00 committed by GitHub
commit cf76ef1f6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 443 additions and 244 deletions

View file

@ -1,4 +1,9 @@
const std = @import("std"); const std = @import("std");
const math = std.math;
const utils = @import("utils.zig");
const ROC_BUILTINS = "roc_builtins";
const NUM = "num";
// Dec Module // Dec Module
const dec = @import("dec.zig"); const dec = @import("dec.zig");
@ -72,16 +77,28 @@ comptime {
// Num Module // Num Module
const num = @import("num.zig"); const num = @import("num.zig");
const INTEGERS = [_]type{ i8, i16, i32, i64, i128, u8, u16, u32, u64, u128 };
const FLOATS = [_]type{ f32, f64 };
const NUMBERS = INTEGERS ++ FLOATS;
comptime { comptime {
exportNumFn(num.atan, "atan");
exportNumFn(num.isFinite, "is_finite");
exportNumFn(num.powInt, "pow_int");
exportNumFn(num.divCeil, "div_ceil");
exportNumFn(num.acos, "acos");
exportNumFn(num.asin, "asin");
exportNumFn(num.bytesToU16C, "bytes_to_u16"); exportNumFn(num.bytesToU16C, "bytes_to_u16");
exportNumFn(num.bytesToU32C, "bytes_to_u32"); exportNumFn(num.bytesToU32C, "bytes_to_u32");
exportNumFn(num.round, "round");
inline for (INTEGERS) |T| {
num.exportPow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".pow_int.");
num.exportDivCeil(T, ROC_BUILTINS ++ "." ++ NUM ++ ".div_ceil.");
}
inline for (FLOATS) |T| {
num.exportAsin(T, ROC_BUILTINS ++ "." ++ NUM ++ ".asin.");
num.exportAcos(T, ROC_BUILTINS ++ "." ++ NUM ++ ".acos.");
num.exportAtan(T, ROC_BUILTINS ++ "." ++ NUM ++ ".atan.");
num.exportIsFinite(T, ROC_BUILTINS ++ "." ++ NUM ++ ".is_finite.");
num.exportRound(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round.");
}
} }
// Str Module // Str Module
@ -107,7 +124,7 @@ comptime {
} }
// Utils // Utils
const utils = @import("utils.zig");
comptime { comptime {
exportUtilsFn(utils.test_panic, "test_panic"); exportUtilsFn(utils.test_panic, "test_panic");
exportUtilsFn(utils.decrefC, "decref"); exportUtilsFn(utils.decrefC, "decref");

View file

@ -3,28 +3,67 @@ const always_inline = std.builtin.CallOptions.Modifier.always_inline;
const math = std.math; const math = std.math;
const RocList = @import("list.zig").RocList; const RocList = @import("list.zig").RocList;
pub fn atan(num: f64) callconv(.C) f64 { pub fn exportPow(comptime T: type, comptime name: []const u8) void {
return @call(.{ .modifier = always_inline }, math.atan, .{num}); comptime var f = struct {
fn func(base: T, exp: T) callconv(.C) T {
return std.math.pow(T, base, exp);
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
} }
pub fn isFinite(num: f64) callconv(.C) bool { pub fn exportIsFinite(comptime T: type, comptime name: []const u8) void {
return @call(.{ .modifier = always_inline }, math.isFinite, .{num}); comptime var f = struct {
fn func(input: T) callconv(.C) bool {
return std.math.isFinite(input);
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
} }
pub fn powInt(base: i64, exp: i64) callconv(.C) i64 { pub fn exportAsin(comptime T: type, comptime name: []const u8) void {
return @call(.{ .modifier = always_inline }, math.pow, .{ i64, base, exp }); comptime var f = struct {
fn func(input: T) callconv(.C) T {
return std.math.asin(input);
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
} }
pub fn divCeil(numerator: i64, denominator: i64) callconv(.C) i64 { pub fn exportAcos(comptime T: type, comptime name: []const u8) void {
return @call(.{ .modifier = always_inline }, math.divCeil, .{ i64, numerator, denominator }) catch unreachable; comptime var f = struct {
fn func(input: T) callconv(.C) T {
return std.math.acos(input);
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
} }
pub fn acos(num: f64) callconv(.C) f64 { pub fn exportAtan(comptime T: type, comptime name: []const u8) void {
return @call(.{ .modifier = always_inline }, math.acos, .{num}); comptime var f = struct {
fn func(input: T) callconv(.C) T {
return std.math.atan(input);
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
} }
pub fn asin(num: f64) callconv(.C) f64 { pub fn exportRound(comptime T: type, comptime name: []const u8) void {
return @call(.{ .modifier = always_inline }, math.asin, .{num}); comptime var f = struct {
fn func(input: T) callconv(.C) i64 {
return @floatToInt(i64, (@round(input)));
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
}
pub fn exportDivCeil(comptime T: type, comptime name: []const u8) void {
comptime var f = struct {
fn func(a: T, b: T) callconv(.C) T {
return math.divCeil(T, a, b) catch unreachable;
}
}.func;
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
} }
pub fn bytesToU16C(arg: RocList, position: usize) callconv(.C) u16 { pub fn bytesToU16C(arg: RocList, position: usize) callconv(.C) u16 {
@ -44,7 +83,3 @@ fn bytesToU32(arg: RocList, position: usize) u32 {
const bytes = @ptrCast([*]const u8, arg.bytes); const bytes = @ptrCast([*]const u8, arg.bytes);
return @bitCast(u32, [_]u8{ bytes[position], bytes[position + 1], bytes[position + 2], bytes[position + 3] }); return @bitCast(u32, [_]u8{ bytes[position], bytes[position + 1], bytes[position + 2], bytes[position + 3] });
} }
pub fn round(num: f64) callconv(.C) i64 {
return @floatToInt(i32, (@round(num)));
}

View file

@ -1,17 +1,129 @@
use std::ops::Index;
pub const OBJ_PATH: &str = env!( pub const OBJ_PATH: &str = env!(
"BUILTINS_O", "BUILTINS_O",
"Env var BUILTINS_O not found. Is there a problem with the build script?" "Env var BUILTINS_O not found. Is there a problem with the build script?"
); );
pub const NUM_ASIN: &str = "roc_builtins.num.asin"; #[derive(Debug, Default)]
pub const NUM_ACOS: &str = "roc_builtins.num.acos"; pub struct IntrinsicName {
pub const NUM_ATAN: &str = "roc_builtins.num.atan"; pub options: [&'static str; 14],
pub const NUM_IS_FINITE: &str = "roc_builtins.num.is_finite"; }
pub const NUM_POW_INT: &str = "roc_builtins.num.pow_int";
pub const NUM_DIV_CEIL: &str = "roc_builtins.num.div_ceil"; impl IntrinsicName {
pub const fn default() -> Self {
Self { options: [""; 14] }
}
}
#[repr(u8)]
pub enum DecWidth {
Dec,
}
#[repr(u8)]
pub enum FloatWidth {
F32,
F64,
F128,
}
#[repr(u8)]
pub enum IntWidth {
U8,
U16,
U32,
U64,
U128,
I8,
I16,
I32,
I64,
I128,
}
impl Index<DecWidth> for IntrinsicName {
type Output = str;
fn index(&self, _: DecWidth) -> &Self::Output {
self.options[0]
}
}
impl Index<FloatWidth> for IntrinsicName {
type Output = str;
fn index(&self, index: FloatWidth) -> &Self::Output {
match index {
FloatWidth::F32 => self.options[1],
FloatWidth::F64 => self.options[2],
FloatWidth::F128 => self.options[3],
}
}
}
impl Index<IntWidth> for IntrinsicName {
type Output = str;
fn index(&self, index: IntWidth) -> &Self::Output {
match index {
IntWidth::U8 => self.options[4],
IntWidth::U16 => self.options[5],
IntWidth::U32 => self.options[6],
IntWidth::U64 => self.options[7],
IntWidth::U128 => self.options[8],
IntWidth::I8 => self.options[9],
IntWidth::I16 => self.options[10],
IntWidth::I32 => self.options[11],
IntWidth::I64 => self.options[12],
IntWidth::I128 => self.options[13],
}
}
}
#[macro_export]
macro_rules! float_intrinsic {
($name:literal) => {{
let mut output = IntrinsicName::default();
output.options[1] = concat!($name, ".f32");
output.options[2] = concat!($name, ".f64");
output.options[3] = concat!($name, ".f128");
output
}};
}
#[macro_export]
macro_rules! int_intrinsic {
($name:literal) => {{
let mut output = IntrinsicName::default();
output.options[4] = concat!($name, ".i8");
output.options[5] = concat!($name, ".i16");
output.options[6] = concat!($name, ".i32");
output.options[7] = concat!($name, ".i64");
output.options[8] = concat!($name, ".i128");
output.options[9] = concat!($name, ".i8");
output.options[10] = concat!($name, ".i16");
output.options[11] = concat!($name, ".i32");
output.options[12] = concat!($name, ".i64");
output.options[13] = concat!($name, ".i128");
output
}};
}
pub const NUM_ASIN: IntrinsicName = float_intrinsic!("roc_builtins.num.asin");
pub const NUM_ACOS: IntrinsicName = float_intrinsic!("roc_builtins.num.acos");
pub const NUM_ATAN: IntrinsicName = float_intrinsic!("roc_builtins.num.atan");
pub const NUM_IS_FINITE: IntrinsicName = float_intrinsic!("roc_builtins.num.is_finite");
pub const NUM_POW_INT: IntrinsicName = int_intrinsic!("roc_builtins.num.pow_int");
pub const NUM_DIV_CEIL: IntrinsicName = int_intrinsic!("roc_builtins.num.div_ceil");
pub const NUM_ROUND: IntrinsicName = float_intrinsic!("roc_builtins.num.round");
pub const NUM_BYTES_TO_U16: &str = "roc_builtins.num.bytes_to_u16"; pub const NUM_BYTES_TO_U16: &str = "roc_builtins.num.bytes_to_u16";
pub const NUM_BYTES_TO_U32: &str = "roc_builtins.num.bytes_to_u32"; pub const NUM_BYTES_TO_U32: &str = "roc_builtins.num.bytes_to_u32";
pub const NUM_ROUND: &str = "roc_builtins.num.round";
pub const STR_INIT: &str = "roc_builtins.str.init"; pub const STR_INIT: &str = "roc_builtins.str.init";
pub const STR_COUNT_SEGMENTS: &str = "roc_builtins.str.count_segments"; pub const STR_COUNT_SEGMENTS: &str = "roc_builtins.str.count_segments";

View file

@ -3,7 +3,7 @@
#![allow(clippy::large_enum_variant, clippy::upper_case_acronyms)] #![allow(clippy::large_enum_variant, clippy::upper_case_acronyms)]
use bumpalo::{collections::Vec, Bump}; use bumpalo::{collections::Vec, Bump};
use roc_builtins::bitcode; use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
use roc_collections::all::{MutMap, MutSet}; use roc_collections::all::{MutMap, MutSet};
use roc_module::ident::{ModuleName, TagName}; use roc_module::ident::{ModuleName, TagName};
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
@ -400,21 +400,21 @@ where
} }
LowLevel::NumAcos => self.build_fn_call( LowLevel::NumAcos => self.build_fn_call(
sym, sym,
bitcode::NUM_ACOS.to_string(), bitcode::NUM_ACOS[FloatWidth::F64].to_string(),
args, args,
arg_layouts, arg_layouts,
ret_layout, ret_layout,
), ),
LowLevel::NumAsin => self.build_fn_call( LowLevel::NumAsin => self.build_fn_call(
sym, sym,
bitcode::NUM_ASIN.to_string(), bitcode::NUM_ASIN[FloatWidth::F64].to_string(),
args, args,
arg_layouts, arg_layouts,
ret_layout, ret_layout,
), ),
LowLevel::NumAtan => self.build_fn_call( LowLevel::NumAtan => self.build_fn_call(
sym, sym,
bitcode::NUM_ATAN.to_string(), bitcode::NUM_ATAN[FloatWidth::F64].to_string(),
args, args,
arg_layouts, arg_layouts,
ret_layout, ret_layout,
@ -437,7 +437,7 @@ where
} }
LowLevel::NumPowInt => self.build_fn_call( LowLevel::NumPowInt => self.build_fn_call(
sym, sym,
bitcode::NUM_POW_INT.to_string(), bitcode::NUM_POW_INT[IntWidth::I64].to_string(),
args, args,
arg_layouts, arg_layouts,
ret_layout, ret_layout,
@ -473,7 +473,7 @@ where
} }
LowLevel::NumRound => self.build_fn_call( LowLevel::NumRound => self.build_fn_call(
sym, sym,
bitcode::NUM_ROUND.to_string(), bitcode::NUM_ROUND[FloatWidth::F64].to_string(),
args, args,
arg_layouts, arg_layouts,
ret_layout, ret_layout,

View file

@ -48,7 +48,8 @@ use inkwell::{AddressSpace, IntPredicate};
use morphic_lib::{ use morphic_lib::{
CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar, CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar,
}; };
use roc_builtins::bitcode; use roc_builtins::bitcode::{self, FloatWidth, IntWidth, IntrinsicName};
use roc_builtins::{float_intrinsic, int_intrinsic};
use roc_collections::all::{ImMap, MutMap, MutSet}; use roc_collections::all::{ImMap, MutMap, MutSet};
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
@ -430,6 +431,58 @@ pub fn module_from_builtins<'ctx>(
module module
} }
fn add_float_intrinsic<'ctx, F>(
ctx: &'ctx Context,
module: &Module<'ctx>,
name: &IntrinsicName,
construct_type: F,
) where
F: Fn(inkwell::types::FloatType<'ctx>) -> inkwell::types::FunctionType<'ctx>,
{
macro_rules! check {
($width:expr, $typ:expr) => {
let full_name = &name[$width];
if let Some(_) = module.get_function(full_name) {
// zig defined this function already
} else {
add_intrinsic(module, full_name, construct_type($typ));
}
};
}
check!(FloatWidth::F32, ctx.f32_type());
check!(FloatWidth::F64, ctx.f64_type());
// check!(IntWidth::F128, ctx.i128_type());
}
fn add_int_intrinsic<'ctx, F>(
ctx: &'ctx Context,
module: &Module<'ctx>,
name: &IntrinsicName,
construct_type: F,
) where
F: Fn(inkwell::types::IntType<'ctx>) -> inkwell::types::FunctionType<'ctx>,
{
macro_rules! check {
($width:expr, $typ:expr) => {
let full_name = &name[$width];
if let Some(_) = module.get_function(full_name) {
// zig defined this function already
} else {
add_intrinsic(module, full_name, construct_type($typ));
}
};
}
check!(IntWidth::I8, ctx.i8_type());
check!(IntWidth::I16, ctx.i16_type());
check!(IntWidth::I32, ctx.i32_type());
check!(IntWidth::I64, ctx.i64_type());
check!(IntWidth::I128, ctx.i128_type());
}
fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
// List of all supported LLVM intrinsics: // List of all supported LLVM intrinsics:
// //
@ -438,7 +491,6 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
let i1_type = ctx.bool_type(); let i1_type = ctx.bool_type();
let i8_type = ctx.i8_type(); let i8_type = ctx.i8_type();
let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic); let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic);
let i16_type = ctx.i16_type();
let i32_type = ctx.i32_type(); let i32_type = ctx.i32_type();
let i64_type = ctx.i64_type(); let i64_type = ctx.i64_type();
let void_type = ctx.void_type(); let void_type = ctx.void_type();
@ -475,114 +527,56 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
add_intrinsic(module, LLVM_STACK_SAVE, i8_ptr_type.fn_type(&[], false)); add_intrinsic(module, LLVM_STACK_SAVE, i8_ptr_type.fn_type(&[], false));
add_intrinsic(
module,
LLVM_LOG_F64,
f64_type.fn_type(&[f64_type.into()], false),
);
add_intrinsic( add_intrinsic(
module, module,
LLVM_LROUND_I64_F64, LLVM_LROUND_I64_F64,
i64_type.fn_type(&[f64_type.into()], false), i64_type.fn_type(&[f64_type.into()], false),
); );
add_intrinsic( add_float_intrinsic(ctx, module, &LLVM_LOG, |t| t.fn_type(&[t.into()], false));
module, add_float_intrinsic(ctx, module, &LLVM_POW, |t| {
LLVM_FABS_F64, t.fn_type(&[t.into(), t.into()], false)
f64_type.fn_type(&[f64_type.into()], false), });
); add_float_intrinsic(ctx, module, &LLVM_FABS, |t| t.fn_type(&[t.into()], false));
add_float_intrinsic(ctx, module, &LLVM_SIN, |t| t.fn_type(&[t.into()], false));
add_float_intrinsic(ctx, module, &LLVM_COS, |t| t.fn_type(&[t.into()], false));
add_float_intrinsic(ctx, module, &LLVM_CEILING, |t| {
t.fn_type(&[t.into()], false)
});
add_float_intrinsic(ctx, module, &LLVM_FLOOR, |t| t.fn_type(&[t.into()], false));
add_intrinsic( add_int_intrinsic(ctx, module, &LLVM_SADD_WITH_OVERFLOW, |t| {
module, let fields = [t.into(), i1_type.into()];
LLVM_SIN_F64,
f64_type.fn_type(&[f64_type.into()], false),
);
add_intrinsic(
module,
LLVM_COS_F64,
f64_type.fn_type(&[f64_type.into()], false),
);
add_intrinsic(
module,
LLVM_POW_F64,
f64_type.fn_type(&[f64_type.into(), f64_type.into()], false),
);
add_intrinsic(
module,
LLVM_CEILING_F64,
f64_type.fn_type(&[f64_type.into()], false),
);
add_intrinsic(
module,
LLVM_FLOOR_F64,
f64_type.fn_type(&[f64_type.into()], false),
);
add_intrinsic(module, LLVM_SADD_WITH_OVERFLOW_I8, {
let fields = [i8_type.into(), i1_type.into()];
ctx.struct_type(&fields, false) ctx.struct_type(&fields, false)
.fn_type(&[i8_type.into(), i8_type.into()], false) .fn_type(&[t.into(), t.into()], false)
}); });
add_intrinsic(module, LLVM_SADD_WITH_OVERFLOW_I16, { add_int_intrinsic(ctx, module, &LLVM_SSUB_WITH_OVERFLOW, |t| {
let fields = [i16_type.into(), i1_type.into()]; let fields = [t.into(), i1_type.into()];
ctx.struct_type(&fields, false) ctx.struct_type(&fields, false)
.fn_type(&[i16_type.into(), i16_type.into()], false) .fn_type(&[t.into(), t.into()], false)
}); });
add_intrinsic(module, LLVM_SADD_WITH_OVERFLOW_I32, { add_int_intrinsic(ctx, module, &LLVM_SMUL_WITH_OVERFLOW, |t| {
let fields = [i32_type.into(), i1_type.into()]; let fields = [t.into(), i1_type.into()];
ctx.struct_type(&fields, false) ctx.struct_type(&fields, false)
.fn_type(&[i32_type.into(), i32_type.into()], false) .fn_type(&[t.into(), t.into()], false)
});
add_intrinsic(module, LLVM_SADD_WITH_OVERFLOW_I64, {
let fields = [i64_type.into(), i1_type.into()];
ctx.struct_type(&fields, false)
.fn_type(&[i64_type.into(), i64_type.into()], false)
});
add_intrinsic(module, LLVM_SSUB_WITH_OVERFLOW_I8, {
let fields = [i8_type.into(), i1_type.into()];
ctx.struct_type(&fields, false)
.fn_type(&[i8_type.into(), i8_type.into()], false)
});
add_intrinsic(module, LLVM_SSUB_WITH_OVERFLOW_I16, {
let fields = [i16_type.into(), i1_type.into()];
ctx.struct_type(&fields, false)
.fn_type(&[i16_type.into(), i16_type.into()], false)
});
add_intrinsic(module, LLVM_SSUB_WITH_OVERFLOW_I32, {
let fields = [i32_type.into(), i1_type.into()];
ctx.struct_type(&fields, false)
.fn_type(&[i32_type.into(), i32_type.into()], false)
});
add_intrinsic(module, LLVM_SSUB_WITH_OVERFLOW_I64, {
let fields = [i64_type.into(), i1_type.into()];
ctx.struct_type(&fields, false)
.fn_type(&[i64_type.into(), i64_type.into()], false)
}); });
} }
const LLVM_POW: IntrinsicName = float_intrinsic!("llvm.pow");
const LLVM_FABS: IntrinsicName = float_intrinsic!("llvm.fabs");
static LLVM_SQRT: IntrinsicName = float_intrinsic!("llvm.sqrt");
static LLVM_LOG: IntrinsicName = float_intrinsic!("llvm.log");
static LLVM_SIN: IntrinsicName = float_intrinsic!("llvm.sin");
static LLVM_COS: IntrinsicName = float_intrinsic!("llvm.cos");
static LLVM_CEILING: IntrinsicName = float_intrinsic!("llvm.ceil");
static LLVM_FLOOR: IntrinsicName = float_intrinsic!("llvm.floor");
static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64"; static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64";
static LLVM_MEMSET_I32: &str = "llvm.memset.p0i8.i32"; static LLVM_MEMSET_I32: &str = "llvm.memset.p0i8.i32";
static LLVM_SQRT_F64: &str = "llvm.sqrt.f64";
static LLVM_LOG_F64: &str = "llvm.log.f64";
static LLVM_LROUND_I64_F64: &str = "llvm.lround.i64.f64"; static LLVM_LROUND_I64_F64: &str = "llvm.lround.i64.f64";
static LLVM_FABS_F64: &str = "llvm.fabs.f64";
static LLVM_SIN_F64: &str = "llvm.sin.f64";
static LLVM_COS_F64: &str = "llvm.cos.f64";
static LLVM_POW_F64: &str = "llvm.pow.f64";
static LLVM_CEILING_F64: &str = "llvm.ceil.f64";
static LLVM_FLOOR_F64: &str = "llvm.floor.f64";
// static LLVM_FRAME_ADDRESS: &str = "llvm.frameaddress"; // static LLVM_FRAME_ADDRESS: &str = "llvm.frameaddress";
static LLVM_FRAME_ADDRESS: &str = "llvm.frameaddress.p0i8"; static LLVM_FRAME_ADDRESS: &str = "llvm.frameaddress.p0i8";
@ -591,23 +585,13 @@ 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";
pub static LLVM_SADD_WITH_OVERFLOW_I8: &str = "llvm.sadd.with.overflow.i8"; const LLVM_SADD_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.sadd.with.overflow");
pub static LLVM_SADD_WITH_OVERFLOW_I16: &str = "llvm.sadd.with.overflow.i16"; const LLVM_SSUB_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.ssub.with.overflow");
pub static LLVM_SADD_WITH_OVERFLOW_I32: &str = "llvm.sadd.with.overflow.i32"; const LLVM_SMUL_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.smul.with.overflow");
pub static LLVM_SADD_WITH_OVERFLOW_I64: &str = "llvm.sadd.with.overflow.i64";
pub static LLVM_SADD_WITH_OVERFLOW_I128: &str = "llvm.sadd.with.overflow.i128";
pub static LLVM_SSUB_WITH_OVERFLOW_I8: &str = "llvm.ssub.with.overflow.i8";
pub static LLVM_SSUB_WITH_OVERFLOW_I16: &str = "llvm.ssub.with.overflow.i16";
pub static LLVM_SSUB_WITH_OVERFLOW_I32: &str = "llvm.ssub.with.overflow.i32";
pub static LLVM_SSUB_WITH_OVERFLOW_I64: &str = "llvm.ssub.with.overflow.i64";
pub static LLVM_SSUB_WITH_OVERFLOW_I128: &str = "llvm.ssub.with.overflow.i128";
pub static LLVM_SMUL_WITH_OVERFLOW_I64: &str = "llvm.smul.with.overflow.i64";
fn add_intrinsic<'ctx>( fn add_intrinsic<'ctx>(
module: &Module<'ctx>, module: &Module<'ctx>,
intrinsic_name: &'static str, intrinsic_name: &str,
fn_type: FunctionType<'ctx>, fn_type: FunctionType<'ctx>,
) -> FunctionValue<'ctx> { ) -> FunctionValue<'ctx> {
add_func( add_func(
@ -5161,8 +5145,14 @@ fn run_low_level<'a, 'ctx, 'env>(
Usize | Int128 | Int64 | Int32 | Int16 | Int8 => { Usize | Int128 | Int64 | Int32 | Int16 | Int8 => {
build_int_unary_op(env, arg.into_int_value(), arg_builtin, op) build_int_unary_op(env, arg.into_int_value(), arg_builtin, op)
} }
Float128 | Float64 | Float32 => { Float32 => {
build_float_unary_op(env, arg.into_float_value(), op) build_float_unary_op(env, arg.into_float_value(), op, FloatWidth::F32)
}
Float64 => {
build_float_unary_op(env, arg.into_float_value(), op, FloatWidth::F64)
}
Float128 => {
build_float_unary_op(env, arg.into_float_value(), op, FloatWidth::F128)
} }
_ => { _ => {
unreachable!("Compiler bug: tried to run numeric operation {:?} on invalid builtin layout: ({:?})", op, arg_layout); unreachable!("Compiler bug: tried to run numeric operation {:?} on invalid builtin layout: ({:?})", op, arg_layout);
@ -5896,6 +5886,31 @@ fn throw_on_overflow<'a, 'ctx, 'env>(
.unwrap() .unwrap()
} }
pub fn intwidth_from_builtin(builtin: Builtin<'_>, ptr_bytes: u32) -> IntWidth {
use IntWidth::*;
match builtin {
Builtin::Int128 => I128,
Builtin::Int64 => I64,
Builtin::Int32 => I32,
Builtin::Int16 => I16,
Builtin::Int8 => I8,
Builtin::Usize => match ptr_bytes {
4 => I32,
8 => I64,
_ => unreachable!(),
},
_ => unreachable!(),
}
}
fn intwidth_from_layout(layout: Layout<'_>, ptr_bytes: u32) -> IntWidth {
match layout {
Layout::Builtin(builtin) => intwidth_from_builtin(builtin, ptr_bytes),
_ => unreachable!(),
}
}
fn build_int_binop<'a, 'ctx, 'env>( fn build_int_binop<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>, parent: FunctionValue<'ctx>,
@ -5910,62 +5925,54 @@ fn build_int_binop<'a, 'ctx, 'env>(
let bd = env.builder; let bd = env.builder;
let int_width = intwidth_from_layout(*lhs_layout, env.ptr_bytes);
match op { match op {
NumAdd => { NumAdd => {
let intrinsic = match lhs_layout {
Layout::Builtin(Builtin::Int8) => LLVM_SADD_WITH_OVERFLOW_I8,
Layout::Builtin(Builtin::Int16) => LLVM_SADD_WITH_OVERFLOW_I16,
Layout::Builtin(Builtin::Int32) => LLVM_SADD_WITH_OVERFLOW_I32,
Layout::Builtin(Builtin::Int64) => LLVM_SADD_WITH_OVERFLOW_I64,
Layout::Builtin(Builtin::Int128) => LLVM_SADD_WITH_OVERFLOW_I128,
Layout::Builtin(Builtin::Usize) => match env.ptr_bytes {
4 => LLVM_SADD_WITH_OVERFLOW_I32,
8 => LLVM_SADD_WITH_OVERFLOW_I64,
other => panic!("invalid ptr_bytes {}", other),
},
_ => unreachable!(),
};
let result = env let result = env
.call_intrinsic(intrinsic, &[lhs.into(), rhs.into()]) .call_intrinsic(
&LLVM_SADD_WITH_OVERFLOW[int_width],
&[lhs.into(), rhs.into()],
)
.into_struct_value(); .into_struct_value();
throw_on_overflow(env, parent, result, "integer addition overflowed!") throw_on_overflow(env, parent, result, "integer addition overflowed!")
} }
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(LLVM_SADD_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]), NumAddChecked => env.call_intrinsic(
&LLVM_SADD_WITH_OVERFLOW[int_width],
&[lhs.into(), rhs.into()],
),
NumSub => { NumSub => {
let intrinsic = match lhs_layout {
Layout::Builtin(Builtin::Int8) => LLVM_SSUB_WITH_OVERFLOW_I8,
Layout::Builtin(Builtin::Int16) => LLVM_SSUB_WITH_OVERFLOW_I16,
Layout::Builtin(Builtin::Int32) => LLVM_SSUB_WITH_OVERFLOW_I32,
Layout::Builtin(Builtin::Int64) => LLVM_SSUB_WITH_OVERFLOW_I64,
Layout::Builtin(Builtin::Int128) => LLVM_SSUB_WITH_OVERFLOW_I128,
Layout::Builtin(Builtin::Usize) => match env.ptr_bytes {
4 => LLVM_SSUB_WITH_OVERFLOW_I32,
8 => LLVM_SSUB_WITH_OVERFLOW_I64,
other => panic!("invalid ptr_bytes {}", other),
},
_ => unreachable!("invalid layout {:?}", lhs_layout),
};
let result = env let result = env
.call_intrinsic(intrinsic, &[lhs.into(), rhs.into()]) .call_intrinsic(
&LLVM_SSUB_WITH_OVERFLOW[int_width],
&[lhs.into(), rhs.into()],
)
.into_struct_value(); .into_struct_value();
throw_on_overflow(env, parent, result, "integer subtraction overflowed!") throw_on_overflow(env, parent, result, "integer subtraction overflowed!")
} }
NumSubWrap => bd.build_int_sub(lhs, rhs, "sub_int").into(), NumSubWrap => bd.build_int_sub(lhs, rhs, "sub_int").into(),
NumSubChecked => env.call_intrinsic(LLVM_SSUB_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]), NumSubChecked => env.call_intrinsic(
&LLVM_SSUB_WITH_OVERFLOW[int_width],
&[lhs.into(), rhs.into()],
),
NumMul => { NumMul => {
let result = env let result = env
.call_intrinsic(LLVM_SMUL_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]) .call_intrinsic(
&LLVM_SMUL_WITH_OVERFLOW[int_width],
&[lhs.into(), rhs.into()],
)
.into_struct_value(); .into_struct_value();
throw_on_overflow(env, parent, result, "integer multiplication overflowed!") throw_on_overflow(env, parent, result, "integer multiplication overflowed!")
} }
NumMulWrap => bd.build_int_mul(lhs, rhs, "mul_int").into(), NumMulWrap => bd.build_int_mul(lhs, rhs, "mul_int").into(),
NumMulChecked => env.call_intrinsic(LLVM_SMUL_WITH_OVERFLOW_I64, &[lhs.into(), rhs.into()]), NumMulChecked => env.call_intrinsic(
&LLVM_SMUL_WITH_OVERFLOW[int_width],
&[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(),
NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(), NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(),
NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(), NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(),
@ -6039,11 +6046,17 @@ fn build_int_binop<'a, 'ctx, 'env>(
phi.as_basic_value() phi.as_basic_value()
} }
} }
NumPowInt => call_bitcode_fn(
env,
&[lhs.into(), rhs.into()],
&bitcode::NUM_POW_INT[int_width],
),
NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(), NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(),
NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_POW_INT), NumDivCeilUnchecked => call_bitcode_fn(
NumDivCeilUnchecked => { env,
call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_DIV_CEIL) &[lhs.into(), rhs.into()],
} &bitcode::NUM_DIV_CEIL[int_width],
),
NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(), NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(),
NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(), NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(),
NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(), NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(),
@ -6085,6 +6098,17 @@ pub fn build_num_binop<'a, 'ctx, 'env>(
{ {
use roc_mono::layout::Builtin::*; use roc_mono::layout::Builtin::*;
let float_binop = |float_width| {
build_float_binop(
env,
parent,
lhs_arg.into_float_value(),
rhs_arg.into_float_value(),
float_width,
op,
)
};
match lhs_builtin { match lhs_builtin {
Usize | Int128 | Int64 | Int32 | Int16 | Int8 => build_int_binop( Usize | Int128 | Int64 | Int32 | Int16 | Int8 => build_int_binop(
env, env,
@ -6095,15 +6119,11 @@ pub fn build_num_binop<'a, 'ctx, 'env>(
rhs_layout, rhs_layout,
op, op,
), ),
Float128 | Float64 | Float32 => build_float_binop(
env, Float32 => float_binop(FloatWidth::F32),
parent, Float64 => float_binop(FloatWidth::F64),
lhs_arg.into_float_value(), Float128 => float_binop(FloatWidth::F128),
lhs_layout,
rhs_arg.into_float_value(),
rhs_layout,
op,
),
Decimal => { Decimal => {
build_dec_binop(env, parent, lhs_arg, lhs_layout, rhs_arg, rhs_layout, op) build_dec_binop(env, parent, lhs_arg, lhs_layout, rhs_arg, rhs_layout, op)
} }
@ -6122,9 +6142,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>, parent: FunctionValue<'ctx>,
lhs: FloatValue<'ctx>, lhs: FloatValue<'ctx>,
_lhs_layout: &Layout<'a>,
rhs: FloatValue<'ctx>, rhs: FloatValue<'ctx>,
_rhs_layout: &Layout<'a>, float_width: FloatWidth,
op: LowLevel, op: LowLevel,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
use inkwell::FloatPredicate::*; use inkwell::FloatPredicate::*;
@ -6140,7 +6159,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
let result = bd.build_float_add(lhs, rhs, "add_float"); let result = bd.build_float_add(lhs, rhs, "add_float");
let is_finite = let is_finite =
call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width])
.into_int_value();
let then_block = context.append_basic_block(parent, "then_block"); let then_block = context.append_basic_block(parent, "then_block");
let throw_block = context.append_basic_block(parent, "throw_block"); let throw_block = context.append_basic_block(parent, "throw_block");
@ -6161,7 +6181,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
let result = bd.build_float_add(lhs, rhs, "add_float"); let result = bd.build_float_add(lhs, rhs, "add_float");
let is_finite = let is_finite =
call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width])
.into_int_value();
let is_infinite = bd.build_not(is_finite, "negate"); let is_infinite = bd.build_not(is_finite, "negate");
let struct_type = context.struct_type( let struct_type = context.struct_type(
@ -6189,7 +6210,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
let result = bd.build_float_sub(lhs, rhs, "sub_float"); let result = bd.build_float_sub(lhs, rhs, "sub_float");
let is_finite = let is_finite =
call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width])
.into_int_value();
let then_block = context.append_basic_block(parent, "then_block"); let then_block = context.append_basic_block(parent, "then_block");
let throw_block = context.append_basic_block(parent, "throw_block"); let throw_block = context.append_basic_block(parent, "throw_block");
@ -6210,7 +6232,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
let result = bd.build_float_sub(lhs, rhs, "sub_float"); let result = bd.build_float_sub(lhs, rhs, "sub_float");
let is_finite = let is_finite =
call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width])
.into_int_value();
let is_infinite = bd.build_not(is_finite, "negate"); let is_infinite = bd.build_not(is_finite, "negate");
let struct_type = context.struct_type( let struct_type = context.struct_type(
@ -6238,7 +6261,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
let result = bd.build_float_mul(lhs, rhs, "mul_float"); let result = bd.build_float_mul(lhs, rhs, "mul_float");
let is_finite = let is_finite =
call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width])
.into_int_value();
let then_block = context.append_basic_block(parent, "then_block"); let then_block = context.append_basic_block(parent, "then_block");
let throw_block = context.append_basic_block(parent, "throw_block"); let throw_block = context.append_basic_block(parent, "throw_block");
@ -6259,7 +6283,8 @@ fn build_float_binop<'a, 'ctx, 'env>(
let result = bd.build_float_mul(lhs, rhs, "mul_float"); let result = bd.build_float_mul(lhs, rhs, "mul_float");
let is_finite = let is_finite =
call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width])
.into_int_value();
let is_infinite = bd.build_not(is_finite, "negate"); let is_infinite = bd.build_not(is_finite, "negate");
let struct_type = context.struct_type( let struct_type = context.struct_type(
@ -6286,7 +6311,7 @@ fn build_float_binop<'a, 'ctx, 'env>(
NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(), NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(),
NumRemUnchecked => bd.build_float_rem(lhs, rhs, "rem_float").into(), NumRemUnchecked => bd.build_float_rem(lhs, rhs, "rem_float").into(),
NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(), NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(),
NumPow => env.call_intrinsic(LLVM_POW_F64, &[lhs.into(), rhs.into()]), NumPow => env.call_intrinsic(&LLVM_POW[float_width], &[lhs.into(), rhs.into()]),
_ => { _ => {
unreachable!("Unrecognized int binary operation: {:?}", op); unreachable!("Unrecognized int binary operation: {:?}", op);
} }
@ -6528,6 +6553,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
arg: FloatValue<'ctx>, arg: FloatValue<'ctx>,
op: LowLevel, op: LowLevel,
float_width: FloatWidth,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
use roc_module::low_level::LowLevel::*; use roc_module::low_level::LowLevel::*;
@ -6536,34 +6562,72 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
// TODO: Handle different sized floats // TODO: Handle different sized floats
match op { match op {
NumNeg => bd.build_float_neg(arg, "negate_float").into(), NumNeg => bd.build_float_neg(arg, "negate_float").into(),
NumAbs => env.call_intrinsic(LLVM_FABS_F64, &[arg.into()]), NumAbs => env.call_intrinsic(&LLVM_FABS[float_width], &[arg.into()]),
NumSqrtUnchecked => env.call_intrinsic(LLVM_SQRT_F64, &[arg.into()]), NumSqrtUnchecked => env.call_intrinsic(&LLVM_SQRT[float_width], &[arg.into()]),
NumLogUnchecked => env.call_intrinsic(LLVM_LOG_F64, &[arg.into()]), NumLogUnchecked => env.call_intrinsic(&LLVM_LOG[float_width], &[arg.into()]),
NumRound => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_ROUND),
NumSin => env.call_intrinsic(LLVM_SIN_F64, &[arg.into()]),
NumCos => env.call_intrinsic(LLVM_COS_F64, &[arg.into()]),
NumToFloat => arg.into(), /* Converting from Float to Float is a no-op */ NumToFloat => arg.into(), /* Converting from Float to Float is a no-op */
NumCeiling => env.builder.build_cast( NumCeiling => env.builder.build_cast(
InstructionOpcode::FPToSI, InstructionOpcode::FPToSI,
env.call_intrinsic(LLVM_CEILING_F64, &[arg.into()]), env.call_intrinsic(&LLVM_CEILING[float_width], &[arg.into()]),
env.context.i64_type(), env.context.i64_type(),
"num_ceiling", "num_ceiling",
), ),
NumFloor => env.builder.build_cast( NumFloor => env.builder.build_cast(
InstructionOpcode::FPToSI, InstructionOpcode::FPToSI,
env.call_intrinsic(LLVM_FLOOR_F64, &[arg.into()]), env.call_intrinsic(&LLVM_FLOOR[float_width], &[arg.into()]),
env.context.i64_type(), env.context.i64_type(),
"num_floor", "num_floor",
), ),
NumIsFinite => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_IS_FINITE), NumIsFinite => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_IS_FINITE[float_width]),
NumAtan => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_ATAN), NumRound => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ROUND[float_width]),
NumAcos => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_ACOS),
NumAsin => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_ASIN), // trigonometry
NumSin => env.call_intrinsic(&LLVM_SIN[float_width], &[arg.into()]),
NumCos => env.call_intrinsic(&LLVM_COS[float_width], &[arg.into()]),
NumAtan => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ATAN[float_width]),
NumAcos => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ACOS[float_width]),
NumAsin => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ASIN[float_width]),
_ => { _ => {
unreachable!("Unrecognized int unary operation: {:?}", op); unreachable!("Unrecognized int unary operation: {:?}", op);
} }
} }
} }
pub fn call_bitcode_int_fn<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
fn_name: &str,
args: &[BasicValueEnum<'ctx>],
int_width: IntWidth,
) -> BasicValueEnum<'ctx> {
match int_width {
IntWidth::U8 => call_bitcode_fn(env, args, &format!("{}_u8", fn_name)),
IntWidth::U16 => call_bitcode_fn(env, args, &format!("{}_u16", fn_name)),
IntWidth::U32 => call_bitcode_fn(env, args, &format!("{}_u32", fn_name)),
IntWidth::U64 => call_bitcode_fn(env, args, &format!("{}_u64", fn_name)),
IntWidth::U128 => call_bitcode_fn(env, args, &format!("{}_u128", fn_name)),
IntWidth::I8 => call_bitcode_fn(env, args, &format!("{}_i8", fn_name)),
IntWidth::I16 => call_bitcode_fn(env, args, &format!("{}_i16", fn_name)),
IntWidth::I32 => call_bitcode_fn(env, args, &format!("{}_i32", fn_name)),
IntWidth::I64 => call_bitcode_fn(env, args, &format!("{}_i64", fn_name)),
IntWidth::I128 => call_bitcode_fn(env, args, &format!("{}_i128", fn_name)),
}
}
pub fn call_bitcode_float_fn<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
fn_name: &str,
args: &[BasicValueEnum<'ctx>],
float_width: FloatWidth,
) -> BasicValueEnum<'ctx> {
match float_width {
FloatWidth::F32 => call_bitcode_fn(env, args, &format!("{}_f32", fn_name)),
FloatWidth::F64 => call_bitcode_fn(env, args, &format!("{}_f64", fn_name)),
FloatWidth::F128 => todo!("suport 128-bit floats"),
}
}
fn define_global_str_literal_ptr<'a, 'ctx, 'env>( fn define_global_str_literal_ptr<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
message: &str, message: &str,

View file

@ -502,38 +502,6 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
env.builder.build_load(result_ptr, "load_result") env.builder.build_load(result_ptr, "load_result")
} }
#[allow(dead_code)]
#[repr(u8)]
enum IntWidth {
U8,
U16,
U32,
U64,
U128,
I8,
I16,
I32,
I64,
I128,
Usize,
}
impl From<roc_mono::layout::Builtin<'_>> for IntWidth {
fn from(builtin: Builtin) -> Self {
use IntWidth::*;
match builtin {
Builtin::Int128 => I128,
Builtin::Int64 => I64,
Builtin::Int32 => I32,
Builtin::Int16 => I16,
Builtin::Int8 => I8,
Builtin::Usize => Usize,
_ => unreachable!(),
}
}
}
/// List.range : Int a, Int a -> List (Int a) /// List.range : Int a, Int a -> List (Int a)
pub fn list_range<'a, 'ctx, 'env>( pub fn list_range<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
@ -552,7 +520,10 @@ pub fn list_range<'a, 'ctx, 'env>(
let int_width = env let int_width = env
.context .context
.i8_type() .i8_type()
.const_int(IntWidth::from(builtin) as u64, false) .const_int(
crate::llvm::build::intwidth_from_builtin(builtin, env.ptr_bytes) as u64,
false,
)
.into(); .into();
call_bitcode_fn( call_bitcode_fn(