mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge pull request #5496 from roc-lang/remove-libc-instrinsic
Stop using llvm instrinsics that just call libc
This commit is contained in:
commit
6d6e3b9c60
7 changed files with 103 additions and 96 deletions
|
@ -725,7 +725,7 @@ mod cli_run {
|
|||
Arg::PlainText("81"),
|
||||
],
|
||||
&[],
|
||||
"4\n",
|
||||
"4.000000000000001\n",
|
||||
UseValgrind::No,
|
||||
TestCliCommands::Run,
|
||||
)
|
||||
|
|
|
@ -17,7 +17,7 @@ pub fn build(b: *Builder) void {
|
|||
// Tests
|
||||
var main_tests = b.addTest(main_path);
|
||||
main_tests.setBuildMode(mode);
|
||||
main_tests.linkSystemLibrary("c");
|
||||
main_tests.linkLibC();
|
||||
const test_step = b.step("test", "Run tests");
|
||||
test_step.dependOn(&main_tests.step);
|
||||
|
||||
|
|
|
@ -85,8 +85,12 @@ comptime {
|
|||
num.exportPow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".pow_int.");
|
||||
num.exportDivCeil(T, ROC_BUILTINS ++ "." ++ NUM ++ ".div_ceil.");
|
||||
|
||||
num.exportRoundF32(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f32.");
|
||||
num.exportRoundF64(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f64.");
|
||||
num.exportRound(f32, T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f32.");
|
||||
num.exportRound(f64, T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_f64.");
|
||||
num.exportFloor(f32, T, ROC_BUILTINS ++ "." ++ NUM ++ ".floor_f32.");
|
||||
num.exportFloor(f64, T, ROC_BUILTINS ++ "." ++ NUM ++ ".floor_f64.");
|
||||
num.exportCeiling(f32, T, ROC_BUILTINS ++ "." ++ NUM ++ ".ceiling_f32.");
|
||||
num.exportCeiling(f64, T, ROC_BUILTINS ++ "." ++ NUM ++ ".ceiling_f64.");
|
||||
|
||||
num.exportAddWithOverflow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".add_with_overflow.");
|
||||
num.exportAddOrPanic(T, ROC_BUILTINS ++ "." ++ NUM ++ ".add_or_panic.");
|
||||
|
@ -126,6 +130,8 @@ comptime {
|
|||
|
||||
num.exportPow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".pow.");
|
||||
num.exportLog(T, ROC_BUILTINS ++ "." ++ NUM ++ ".log.");
|
||||
num.exportFAbs(T, ROC_BUILTINS ++ "." ++ NUM ++ ".fabs.");
|
||||
num.exportSqrt(T, ROC_BUILTINS ++ "." ++ NUM ++ ".sqrt.");
|
||||
|
||||
num.exportAddWithOverflow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".add_with_overflow.");
|
||||
num.exportSubWithOverflow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".sub_with_overflow.");
|
||||
|
|
|
@ -152,7 +152,7 @@ pub fn exportAtan(comptime T: type, comptime name: []const u8) void {
|
|||
pub fn exportSin(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: T) callconv(.C) T {
|
||||
return @sin(input);
|
||||
return math.sin(input);
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
|
@ -161,7 +161,7 @@ pub fn exportSin(comptime T: type, comptime name: []const u8) void {
|
|||
pub fn exportCos(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: T) callconv(.C) T {
|
||||
return @cos(input);
|
||||
return math.cos(input);
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
|
@ -170,25 +170,52 @@ pub fn exportCos(comptime T: type, comptime name: []const u8) void {
|
|||
pub fn exportLog(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: T) callconv(.C) T {
|
||||
return @log(input);
|
||||
return math.ln(input);
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn exportRoundF32(comptime T: type, comptime name: []const u8) void {
|
||||
pub fn exportFAbs(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: f32) callconv(.C) T {
|
||||
return @floatToInt(T, (@round(input)));
|
||||
fn func(input: T) callconv(.C) T {
|
||||
return math.absFloat(input);
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn exportRoundF64(comptime T: type, comptime name: []const u8) void {
|
||||
pub fn exportSqrt(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: f64) callconv(.C) T {
|
||||
return @floatToInt(T, (@round(input)));
|
||||
fn func(input: T) callconv(.C) T {
|
||||
return math.sqrt(input);
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn exportRound(comptime F: type, comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: F) callconv(.C) T {
|
||||
return @floatToInt(T, (math.round(input)));
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn exportFloor(comptime F: type, comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: F) callconv(.C) T {
|
||||
return @floatToInt(T, (math.floor(input)));
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn exportCeiling(comptime F: type, comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: F) callconv(.C) T {
|
||||
return @floatToInt(T, (math.ceil(input)));
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
|
|
|
@ -267,9 +267,15 @@ pub const NUM_IS_INFINITE: IntrinsicName = float_intrinsic!("roc_builtins.num.is
|
|||
pub const NUM_IS_FINITE: IntrinsicName = float_intrinsic!("roc_builtins.num.is_finite");
|
||||
pub const NUM_LOG: IntrinsicName = float_intrinsic!("roc_builtins.num.log");
|
||||
pub const NUM_POW: IntrinsicName = float_intrinsic!("roc_builtins.num.pow");
|
||||
pub const NUM_FABS: IntrinsicName = float_intrinsic!("roc_builtins.num.fabs");
|
||||
pub const NUM_SQRT: IntrinsicName = float_intrinsic!("roc_builtins.num.sqrt");
|
||||
|
||||
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_CEILING_F32: IntrinsicName = int_intrinsic!("roc_builtins.num.ceiling_f32");
|
||||
pub const NUM_CEILING_F64: IntrinsicName = int_intrinsic!("roc_builtins.num.ceiling_f64");
|
||||
pub const NUM_FLOOR_F32: IntrinsicName = int_intrinsic!("roc_builtins.num.floor_f32");
|
||||
pub const NUM_FLOOR_F64: IntrinsicName = int_intrinsic!("roc_builtins.num.floor_f64");
|
||||
pub const NUM_ROUND_F32: IntrinsicName = int_intrinsic!("roc_builtins.num.round_f32");
|
||||
pub const NUM_ROUND_F64: IntrinsicName = int_intrinsic!("roc_builtins.num.round_f64");
|
||||
|
||||
|
|
|
@ -7,11 +7,12 @@ use inkwell::{
|
|||
};
|
||||
use roc_builtins::{
|
||||
bitcode::{FloatWidth, IntWidth, IntrinsicName},
|
||||
float_intrinsic, llvm_int_intrinsic,
|
||||
llvm_int_intrinsic,
|
||||
};
|
||||
|
||||
use super::build::{add_func, FunctionSpec};
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn add_float_intrinsic<'ctx, F>(
|
||||
ctx: &'ctx Context,
|
||||
module: &Module<'ctx>,
|
||||
|
@ -111,18 +112,6 @@ pub(crate) fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
|
|||
i8_ptr_type.fn_type(&[], false),
|
||||
);
|
||||
|
||||
add_float_intrinsic(ctx, module, &LLVM_LOG, |t| t.fn_type(&[t.into()], false));
|
||||
add_float_intrinsic(ctx, module, &LLVM_POW, |t| {
|
||||
t.fn_type(&[t.into(), t.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_int_intrinsic(ctx, module, &LLVM_ADD_WITH_OVERFLOW, |t| {
|
||||
let fields = [t.into(), i1_type.into()];
|
||||
ctx.struct_type(&fields, false)
|
||||
|
@ -150,17 +139,6 @@ pub(crate) fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
|
|||
});
|
||||
}
|
||||
|
||||
pub const LLVM_POW: IntrinsicName = float_intrinsic!("llvm.pow");
|
||||
pub const LLVM_FABS: IntrinsicName = float_intrinsic!("llvm.fabs");
|
||||
pub static LLVM_SQRT: IntrinsicName = float_intrinsic!("llvm.sqrt");
|
||||
pub static LLVM_LOG: IntrinsicName = float_intrinsic!("llvm.log");
|
||||
|
||||
pub static LLVM_SIN: IntrinsicName = float_intrinsic!("llvm.sin");
|
||||
pub static LLVM_COS: IntrinsicName = float_intrinsic!("llvm.cos");
|
||||
pub static LLVM_CEILING: IntrinsicName = float_intrinsic!("llvm.ceil");
|
||||
pub static LLVM_FLOOR: IntrinsicName = float_intrinsic!("llvm.floor");
|
||||
pub static LLVM_ROUND: IntrinsicName = float_intrinsic!("llvm.round");
|
||||
|
||||
pub static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64";
|
||||
pub static LLVM_MEMSET_I32: &str = "llvm.memset.p0i8.i32";
|
||||
|
||||
|
|
|
@ -41,9 +41,13 @@ use crate::llvm::{
|
|||
self, basic_type_from_layout, zig_num_parse_result_type, zig_to_int_checked_result_type,
|
||||
},
|
||||
intrinsics::{
|
||||
LLVM_ADD_SATURATED, LLVM_ADD_WITH_OVERFLOW, LLVM_CEILING, LLVM_COS, LLVM_FABS, LLVM_FLOOR,
|
||||
LLVM_LOG, LLVM_MUL_WITH_OVERFLOW, LLVM_POW, LLVM_ROUND, LLVM_SIN, LLVM_SQRT,
|
||||
LLVM_SUB_SATURATED, LLVM_SUB_WITH_OVERFLOW,
|
||||
// These instrinsics do not generate calls to libc and are safe to keep.
|
||||
// If we find that any of them generate calls to libc on some platforms, we need to define them as zig bitcode.
|
||||
LLVM_ADD_SATURATED,
|
||||
LLVM_ADD_WITH_OVERFLOW,
|
||||
LLVM_MUL_WITH_OVERFLOW,
|
||||
LLVM_SUB_SATURATED,
|
||||
LLVM_SUB_WITH_OVERFLOW,
|
||||
},
|
||||
refcounting::PointerToRefcount,
|
||||
};
|
||||
|
@ -1704,7 +1708,11 @@ fn build_float_binop<'ctx>(
|
|||
NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(),
|
||||
NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(),
|
||||
NumDivFrac => bd.build_float_div(lhs, rhs, "div_float").into(),
|
||||
NumPow => env.call_intrinsic(&LLVM_POW[float_width], &[lhs.into(), rhs.into()]),
|
||||
NumPow => call_bitcode_fn(
|
||||
env,
|
||||
&[lhs.into(), rhs.into()],
|
||||
&bitcode::NUM_POW[float_width],
|
||||
),
|
||||
_ => {
|
||||
unreachable!("Unrecognized int binary operation: {:?}", op);
|
||||
}
|
||||
|
@ -2316,9 +2324,9 @@ fn build_float_unary_op<'a, 'ctx>(
|
|||
// TODO: Handle different sized floats
|
||||
match op {
|
||||
NumNeg => bd.build_float_neg(arg, "negate_float").into(),
|
||||
NumAbs => env.call_intrinsic(&LLVM_FABS[float_width], &[arg.into()]),
|
||||
NumSqrtUnchecked => env.call_intrinsic(&LLVM_SQRT[float_width], &[arg.into()]),
|
||||
NumLogUnchecked => env.call_intrinsic(&LLVM_LOG[float_width], &[arg.into()]),
|
||||
NumAbs => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_FABS[float_width]),
|
||||
NumSqrtUnchecked => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_SQRT[float_width]),
|
||||
NumLogUnchecked => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_LOG[float_width]),
|
||||
NumToFrac => {
|
||||
let return_width = match layout_interner.get(layout).repr {
|
||||
LayoutRepr::Builtin(Builtin::Float(return_width)) => return_width,
|
||||
|
@ -2342,64 +2350,46 @@ fn build_float_unary_op<'a, 'ctx>(
|
|||
}
|
||||
}
|
||||
NumCeiling => {
|
||||
let (return_signed, return_type) = match layout_interner.get(layout).repr {
|
||||
LayoutRepr::Builtin(Builtin::Int(int_width)) => (
|
||||
int_width.is_signed(),
|
||||
convert::int_type_from_int_width(env, int_width),
|
||||
),
|
||||
let int_width = match layout_interner.get(layout).repr {
|
||||
LayoutRepr::Builtin(Builtin::Int(int_width)) => int_width,
|
||||
_ => internal_error!("Ceiling return layout is not int: {:?}", layout),
|
||||
};
|
||||
let opcode = if return_signed {
|
||||
InstructionOpcode::FPToSI
|
||||
} else {
|
||||
InstructionOpcode::FPToUI
|
||||
};
|
||||
env.builder.build_cast(
|
||||
opcode,
|
||||
env.call_intrinsic(&LLVM_CEILING[float_width], &[arg.into()]),
|
||||
return_type,
|
||||
"num_ceiling",
|
||||
)
|
||||
match float_width {
|
||||
FloatWidth::F32 => {
|
||||
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_CEILING_F32[int_width])
|
||||
}
|
||||
FloatWidth::F64 => {
|
||||
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_CEILING_F64[int_width])
|
||||
}
|
||||
}
|
||||
}
|
||||
NumFloor => {
|
||||
let (return_signed, return_type) = match layout_interner.get(layout).repr {
|
||||
LayoutRepr::Builtin(Builtin::Int(int_width)) => (
|
||||
int_width.is_signed(),
|
||||
convert::int_type_from_int_width(env, int_width),
|
||||
),
|
||||
_ => internal_error!("Ceiling return layout is not int: {:?}", layout),
|
||||
let int_width = match layout_interner.get(layout).repr {
|
||||
LayoutRepr::Builtin(Builtin::Int(int_width)) => int_width,
|
||||
_ => internal_error!("Floor return layout is not int: {:?}", layout),
|
||||
};
|
||||
let opcode = if return_signed {
|
||||
InstructionOpcode::FPToSI
|
||||
} else {
|
||||
InstructionOpcode::FPToUI
|
||||
};
|
||||
env.builder.build_cast(
|
||||
opcode,
|
||||
env.call_intrinsic(&LLVM_FLOOR[float_width], &[arg.into()]),
|
||||
return_type,
|
||||
"num_floor",
|
||||
)
|
||||
match float_width {
|
||||
FloatWidth::F32 => {
|
||||
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_FLOOR_F32[int_width])
|
||||
}
|
||||
FloatWidth::F64 => {
|
||||
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_FLOOR_F64[int_width])
|
||||
}
|
||||
}
|
||||
}
|
||||
NumRound => {
|
||||
let (return_signed, return_type) = match layout_interner.get(layout).repr {
|
||||
LayoutRepr::Builtin(Builtin::Int(int_width)) => (
|
||||
int_width.is_signed(),
|
||||
convert::int_type_from_int_width(env, int_width),
|
||||
),
|
||||
_ => internal_error!("Ceiling return layout is not int: {:?}", layout),
|
||||
let int_width = match layout_interner.get(layout).repr {
|
||||
LayoutRepr::Builtin(Builtin::Int(int_width)) => int_width,
|
||||
_ => internal_error!("Round return layout is not int: {:?}", layout),
|
||||
};
|
||||
let opcode = if return_signed {
|
||||
InstructionOpcode::FPToSI
|
||||
} else {
|
||||
InstructionOpcode::FPToUI
|
||||
};
|
||||
env.builder.build_cast(
|
||||
opcode,
|
||||
env.call_intrinsic(&LLVM_ROUND[float_width], &[arg.into()]),
|
||||
return_type,
|
||||
"num_round",
|
||||
)
|
||||
match float_width {
|
||||
FloatWidth::F32 => {
|
||||
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ROUND_F32[int_width])
|
||||
}
|
||||
FloatWidth::F64 => {
|
||||
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ROUND_F64[int_width])
|
||||
}
|
||||
}
|
||||
}
|
||||
NumIsNan => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_IS_NAN[float_width]),
|
||||
NumIsInfinite => {
|
||||
|
@ -2408,8 +2398,8 @@ fn build_float_unary_op<'a, 'ctx>(
|
|||
NumIsFinite => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_IS_FINITE[float_width]),
|
||||
|
||||
// trigonometry
|
||||
NumSin => env.call_intrinsic(&LLVM_SIN[float_width], &[arg.into()]),
|
||||
NumCos => env.call_intrinsic(&LLVM_COS[float_width], &[arg.into()]),
|
||||
NumSin => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_SIN[float_width]),
|
||||
NumCos => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_COS[float_width]),
|
||||
|
||||
NumAtan => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ATAN[float_width]),
|
||||
NumAcos => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ACOS[float_width]),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue