From 6cc8f8624c87df400865e02869d29c758aa79c91 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 18 Oct 2021 11:09:38 +0200 Subject: [PATCH 01/10] a way forward --- compiler/builtins/bitcode/src/main.zig | 2 +- compiler/builtins/bitcode/src/num.zig | 16 ++++++++++++++-- compiler/builtins/src/bitcode.rs | 2 +- compiler/gen_dev/src/lib.rs | 2 +- compiler/gen_llvm/src/llvm/build.rs | 2 +- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index d82b8542a8..8e0ef81779 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -75,7 +75,7 @@ const num = @import("num.zig"); comptime { exportNumFn(num.atan, "atan"); exportNumFn(num.isFinite, "is_finite"); - exportNumFn(num.powInt, "pow_int"); + // exportNumFn(num.powInt, "pow_int"); exportNumFn(num.acos, "acos"); exportNumFn(num.asin, "asin"); exportNumFn(num.bytesToU16C, "bytes_to_u16"); diff --git a/compiler/builtins/bitcode/src/num.zig b/compiler/builtins/bitcode/src/num.zig index 94873f2fe6..ccf14a4d91 100644 --- a/compiler/builtins/bitcode/src/num.zig +++ b/compiler/builtins/bitcode/src/num.zig @@ -11,8 +11,20 @@ pub fn isFinite(num: f64) callconv(.C) bool { return @call(.{ .modifier = always_inline }, math.isFinite, .{num}); } -pub fn powInt(base: i64, exp: i64) callconv(.C) i64 { - return @call(.{ .modifier = always_inline }, math.pow, .{ i64, base, exp }); +comptime { + var types = [_]type{ i32, i64, i16 }; + inline for (types) |T| { + exportFunctions(T); + } +} +fn exportFunctions(comptime T: type) void { + comptime var f = struct { + fn func(base: T, exp: T) callconv(.C) T { + return std.math.pow(T, base, exp); + } + }.func; + const args = .{ .name = "roc_builtins.num.pow_int_" ++ @typeName(T), .linkage = .Strong }; + @export(f, args); } pub fn acos(num: f64) callconv(.C) f64 { diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index e451a1e68d..ea3769a279 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -7,7 +7,7 @@ pub const NUM_ASIN: &str = "roc_builtins.num.asin"; pub const NUM_ACOS: &str = "roc_builtins.num.acos"; pub const NUM_ATAN: &str = "roc_builtins.num.atan"; 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_POW_INT_I64: &str = "roc_builtins.num.pow_int_i64"; 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_ROUND: &str = "roc_builtins.num.round"; diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 5ef03a3a42..0c3289efb0 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -437,7 +437,7 @@ where } LowLevel::NumPowInt => self.build_fn_call( sym, - bitcode::NUM_POW_INT.to_string(), + bitcode::NUM_POW_INT_I64.to_string(), args, arg_layouts, ret_layout, diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index eac79e9978..95db376d05 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -6072,7 +6072,7 @@ fn build_int_binop<'a, 'ctx, 'env>( } } NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(), - NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_POW_INT), + NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_POW_INT_I64), NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(), NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(), NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(), From 78c49d3095883b6f6bc8971a058a3ec3bde6d1d3 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 19 Oct 2021 21:41:38 +0200 Subject: [PATCH 02/10] support intrinsics/builtins for more integer types --- compiler/builtins/bitcode/src/main.zig | 31 ++- compiler/builtins/bitcode/src/num.zig | 68 ++++--- compiler/builtins/bitcode/src/utils.zig | 33 +++ compiler/builtins/src/bitcode.rs | 2 +- compiler/gen_dev/src/lib.rs | 8 +- compiler/gen_llvm/src/llvm/build.rs | 247 ++++++++++++++++++----- compiler/gen_llvm/src/llvm/build_list.rs | 34 +--- 7 files changed, 308 insertions(+), 115 deletions(-) diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index 8e0ef81779..38e3b68f20 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -1,4 +1,9 @@ const std = @import("std"); +const math = std.math; +const utils = @import("utils.zig"); + +const ROC_BUILTINS = "roc_builtins"; +const NUM = "num"; // Dec Module const dec = @import("dec.zig"); @@ -72,15 +77,27 @@ comptime { // Num Module const num = @import("num.zig"); + +const INTEGERS = [_]type{ i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize }; +const FLOATS = [_]type{ f32, f64 }; +const NUMBERS = INTEGERS ++ FLOATS; + comptime { - exportNumFn(num.atan, "atan"); - exportNumFn(num.isFinite, "is_finite"); - // exportNumFn(num.powInt, "pow_int"); - exportNumFn(num.acos, "acos"); - exportNumFn(num.asin, "asin"); exportNumFn(num.bytesToU16C, "bytes_to_u16"); exportNumFn(num.bytesToU32C, "bytes_to_u32"); - exportNumFn(num.round, "round"); + + inline for (INTEGERS) |T| { + num.exportPow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".pow_int_"); + } + + inline for (FLOATS) |T| { + num.exportAsin(T, ROC_BUILTINS ++ "." ++ NUM ++ ".acos_"); + num.exportAcos(T, ROC_BUILTINS ++ "." ++ NUM ++ ".asin_"); + num.exportAtan(T, ROC_BUILTINS ++ "." ++ NUM ++ ".atan_"); + + num.exportIsFinite(T, ROC_BUILTINS ++ "." ++ NUM ++ ".is_finite_"); + num.exportRound(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_"); + } } // Str Module @@ -106,7 +123,7 @@ comptime { } // Utils -const utils = @import("utils.zig"); + comptime { exportUtilsFn(utils.test_panic, "test_panic"); exportUtilsFn(utils.decrefC, "decref"); diff --git a/compiler/builtins/bitcode/src/num.zig b/compiler/builtins/bitcode/src/num.zig index ccf14a4d91..fdaa09f379 100644 --- a/compiler/builtins/bitcode/src/num.zig +++ b/compiler/builtins/bitcode/src/num.zig @@ -3,36 +3,58 @@ const always_inline = std.builtin.CallOptions.Modifier.always_inline; const math = std.math; const RocList = @import("list.zig").RocList; -pub fn atan(num: f64) callconv(.C) f64 { - return @call(.{ .modifier = always_inline }, math.atan, .{num}); -} - -pub fn isFinite(num: f64) callconv(.C) bool { - return @call(.{ .modifier = always_inline }, math.isFinite, .{num}); -} - -comptime { - var types = [_]type{ i32, i64, i16 }; - inline for (types) |T| { - exportFunctions(T); - } -} -fn exportFunctions(comptime T: type) void { +pub fn exportPow(comptime T: type, comptime name: []const u8) void { comptime var f = struct { fn func(base: T, exp: T) callconv(.C) T { return std.math.pow(T, base, exp); } }.func; - const args = .{ .name = "roc_builtins.num.pow_int_" ++ @typeName(T), .linkage = .Strong }; - @export(f, args); + @export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong }); } -pub fn acos(num: f64) callconv(.C) f64 { - return @call(.{ .modifier = always_inline }, math.acos, .{num}); +pub fn exportIsFinite(comptime T: type, comptime name: []const u8) void { + 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 asin(num: f64) callconv(.C) f64 { - return @call(.{ .modifier = always_inline }, math.asin, .{num}); +pub fn exportAsin(comptime T: type, comptime name: []const u8) void { + 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 exportAcos(comptime T: type, comptime name: []const u8) void { + 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 exportAtan(comptime T: type, comptime name: []const u8) void { + 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 exportRound(comptime T: type, comptime name: []const u8) void { + 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 bytesToU16C(arg: RocList, position: usize) callconv(.C) u16 { @@ -52,7 +74,3 @@ fn bytesToU32(arg: RocList, position: usize) u32 { const bytes = @ptrCast([*]const u8, arg.bytes); 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))); -} diff --git a/compiler/builtins/bitcode/src/utils.zig b/compiler/builtins/bitcode/src/utils.zig index 1371afe674..9f407c5b83 100644 --- a/compiler/builtins/bitcode/src/utils.zig +++ b/compiler/builtins/bitcode/src/utils.zig @@ -261,3 +261,36 @@ pub const UpdateMode = extern enum(u8) { Immutable = 0, InPlace = 1, }; + +/// Functions of the form `a -> b` +pub fn generateAtoB( + comptime A: type, + comptime B: type, + comptime function: fn (A) B, + comptime name: []const u8, +) void { + comptime var f = struct { + fn func(input: A) callconv(.C) B { + return function(input); + } + }.func; + const args = .{ .name = name ++ @typeName(A), .linkage = .Strong }; + @export(f, args); +} + +/// Functions of the form `a, b -> c` +pub fn generateAtoBtoC( + comptime A: type, + comptime B: type, + comptime C: type, + comptime function: fn (A, B) C, + comptime name: []const u8, +) void { + comptime var f = struct { + fn func(input1: A, input2: B) callconv(.C) C { + return function(input1, input2); + } + }.func; + const args = .{ .name = name ++ @typeName(A), .linkage = .Strong }; + @export(f, args); +} diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index ea3769a279..e451a1e68d 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -7,7 +7,7 @@ pub const NUM_ASIN: &str = "roc_builtins.num.asin"; pub const NUM_ACOS: &str = "roc_builtins.num.acos"; pub const NUM_ATAN: &str = "roc_builtins.num.atan"; pub const NUM_IS_FINITE: &str = "roc_builtins.num.is_finite"; -pub const NUM_POW_INT_I64: &str = "roc_builtins.num.pow_int_i64"; +pub const NUM_POW_INT: &str = "roc_builtins.num.pow_int"; 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_ROUND: &str = "roc_builtins.num.round"; diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 0c3289efb0..6c06c85fec 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -400,21 +400,21 @@ where } LowLevel::NumAcos => self.build_fn_call( sym, - bitcode::NUM_ACOS.to_string(), + format!("{}_i64", bitcode::NUM_ACOS), args, arg_layouts, ret_layout, ), LowLevel::NumAsin => self.build_fn_call( sym, - bitcode::NUM_ASIN.to_string(), + format!("{}_i64", bitcode::NUM_ASIN), args, arg_layouts, ret_layout, ), LowLevel::NumAtan => self.build_fn_call( sym, - bitcode::NUM_ATAN.to_string(), + format!("{}_i64", bitcode::NUM_ATAN), args, arg_layouts, ret_layout, @@ -437,7 +437,7 @@ where } LowLevel::NumPowInt => self.build_fn_call( sym, - bitcode::NUM_POW_INT_I64.to_string(), + format!("{}_i64", bitcode::NUM_POW_INT), args, arg_layouts, ret_layout, diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 95db376d05..0f5beaff40 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -204,7 +204,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { pub fn build_intrinsic_call( &self, - intrinsic_name: &'static str, + intrinsic_name: &str, args: &[BasicValueEnum<'ctx>], ) -> CallSiteValue<'ctx> { let fn_val = self @@ -229,7 +229,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { pub fn call_intrinsic( &self, - intrinsic_name: &'static str, + intrinsic_name: &str, args: &[BasicValueEnum<'ctx>], ) -> BasicValueEnum<'ctx> { let call = self.build_intrinsic_call(intrinsic_name, args); @@ -487,11 +487,17 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { i64_type.fn_type(&[f64_type.into()], false), ); - add_intrinsic( - module, - LLVM_FABS_F64, - f64_type.fn_type(&[f64_type.into()], false), - ); + for width in ["f32", "f64"] { + let name = format!("{}.{}", LLVM_FABS, width); + add_intrinsic(module, &name, f64_type.fn_type(&[f64_type.into()], false)); + + let name = format!("{}.{}", LLVM_POW, width); + add_intrinsic( + module, + &name, + f64_type.fn_type(&[f64_type.into(), f64_type.into()], false), + ); + } add_intrinsic( module, @@ -505,12 +511,6 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { 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, @@ -577,10 +577,10 @@ 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_FABS_F64: &str = "llvm.fabs.f64"; +static LLVM_FABS: &str = "llvm.fabs"; 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_POW: &str = "llvm.pow"; static LLVM_CEILING_F64: &str = "llvm.ceil.f64"; static LLVM_FLOOR_F64: &str = "llvm.floor.f64"; @@ -607,7 +607,7 @@ pub static LLVM_SMUL_WITH_OVERFLOW_I64: &str = "llvm.smul.with.overflow.i64"; fn add_intrinsic<'ctx>( module: &Module<'ctx>, - intrinsic_name: &'static str, + intrinsic_name: &str, fn_type: FunctionType<'ctx>, ) -> FunctionValue<'ctx> { add_func( @@ -5193,8 +5193,14 @@ fn run_low_level<'a, 'ctx, 'env>( Usize | Int128 | Int64 | Int32 | Int16 | Int8 => { build_int_unary_op(env, arg.into_int_value(), arg_builtin, op) } - Float128 | Float64 | Float32 => { - build_float_unary_op(env, arg.into_float_value(), op) + Float32 => { + 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); @@ -5942,6 +5948,8 @@ fn build_int_binop<'a, 'ctx, 'env>( let bd = env.builder; + let int_width = IntWidth::from(*lhs_layout); + match op { NumAdd => { let intrinsic = match lhs_layout { @@ -6072,7 +6080,12 @@ fn build_int_binop<'a, 'ctx, 'env>( } } NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(), - NumPowInt => call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_POW_INT_I64), + NumPowInt => call_bitcode_int_fn( + env, + bitcode::NUM_POW_INT, + &[lhs.into(), rhs.into()], + int_width, + ), NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(), NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(), NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(), @@ -6114,6 +6127,17 @@ pub fn build_num_binop<'a, 'ctx, 'env>( { 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 { Usize | Int128 | Int64 | Int32 | Int16 | Int8 => build_int_binop( env, @@ -6124,15 +6148,11 @@ pub fn build_num_binop<'a, 'ctx, 'env>( rhs_layout, op, ), - Float128 | Float64 | Float32 => build_float_binop( - env, - parent, - lhs_arg.into_float_value(), - lhs_layout, - rhs_arg.into_float_value(), - rhs_layout, - op, - ), + + Float32 => float_binop(FloatWidth::F32), + Float64 => float_binop(FloatWidth::F64), + Float128 => float_binop(FloatWidth::F128), + Decimal => { build_dec_binop(env, parent, lhs_arg, lhs_layout, rhs_arg, rhs_layout, op) } @@ -6151,9 +6171,8 @@ fn build_float_binop<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, parent: FunctionValue<'ctx>, lhs: FloatValue<'ctx>, - _lhs_layout: &Layout<'a>, rhs: FloatValue<'ctx>, - _rhs_layout: &Layout<'a>, + float_width: FloatWidth, op: LowLevel, ) -> BasicValueEnum<'ctx> { use inkwell::FloatPredicate::*; @@ -6169,7 +6188,8 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_add(lhs, rhs, "add_float"); let is_finite = - call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); + call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + .into_int_value(); let then_block = context.append_basic_block(parent, "then_block"); let throw_block = context.append_basic_block(parent, "throw_block"); @@ -6190,7 +6210,8 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_add(lhs, rhs, "add_float"); let is_finite = - call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); + call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + .into_int_value(); let is_infinite = bd.build_not(is_finite, "negate"); let struct_type = context.struct_type( @@ -6218,7 +6239,8 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_sub(lhs, rhs, "sub_float"); let is_finite = - call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); + call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + .into_int_value(); let then_block = context.append_basic_block(parent, "then_block"); let throw_block = context.append_basic_block(parent, "throw_block"); @@ -6239,7 +6261,8 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_sub(lhs, rhs, "sub_float"); let is_finite = - call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); + call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + .into_int_value(); let is_infinite = bd.build_not(is_finite, "negate"); let struct_type = context.struct_type( @@ -6267,7 +6290,8 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_mul(lhs, rhs, "mul_float"); let is_finite = - call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); + call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + .into_int_value(); let then_block = context.append_basic_block(parent, "then_block"); let throw_block = context.append_basic_block(parent, "throw_block"); @@ -6288,7 +6312,8 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_mul(lhs, rhs, "mul_float"); let is_finite = - call_bitcode_fn(env, &[result.into()], bitcode::NUM_IS_FINITE).into_int_value(); + call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + .into_int_value(); let is_infinite = bd.build_not(is_finite, "negate"); let struct_type = context.struct_type( @@ -6315,7 +6340,7 @@ fn build_float_binop<'a, 'ctx, 'env>( NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(), NumRemUnchecked => bd.build_float_rem(lhs, rhs, "rem_float").into(), NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(), - NumPow => env.call_intrinsic(LLVM_POW_F64, &[lhs.into(), rhs.into()]), + NumPow => call_float_intrinsic(env, LLVM_POW, &[lhs.into(), rhs.into()], float_width), _ => { unreachable!("Unrecognized int binary operation: {:?}", op); } @@ -6553,10 +6578,58 @@ fn int_abs_with_overflow<'a, 'ctx, 'env>( )) } +#[repr(u8)] +pub enum FloatWidth { + F32, + F64, + F128, +} + +#[repr(u8)] +pub enum IntWidth { + U8, + U16, + U32, + U64, + U128, + I8, + I16, + I32, + I64, + I128, + Usize, +} + +impl From> 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!(), + } + } +} + +impl From> for IntWidth { + fn from(layout: Layout) -> Self { + match layout { + Layout::Builtin(builtin) => IntWidth::from(builtin), + _ => unreachable!(), + } + } +} + fn build_float_unary_op<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, arg: FloatValue<'ctx>, op: LowLevel, + float_width: FloatWidth, ) -> BasicValueEnum<'ctx> { use roc_module::low_level::LowLevel::*; @@ -6565,12 +6638,9 @@ fn build_float_unary_op<'a, 'ctx, 'env>( // TODO: Handle different sized floats match op { NumNeg => bd.build_float_neg(arg, "negate_float").into(), - NumAbs => env.call_intrinsic(LLVM_FABS_F64, &[arg.into()]), + NumAbs => call_float_intrinsic(env, LLVM_FABS, &[arg.into()], float_width), NumSqrtUnchecked => env.call_intrinsic(LLVM_SQRT_F64, &[arg.into()]), NumLogUnchecked => env.call_intrinsic(LLVM_LOG_F64, &[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 */ NumCeiling => env.builder.build_cast( InstructionOpcode::FPToSI, @@ -6584,15 +6654,102 @@ fn build_float_unary_op<'a, 'ctx, 'env>( env.context.i64_type(), "num_floor", ), - NumIsFinite => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_IS_FINITE), - NumAtan => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_ATAN), - NumAcos => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_ACOS), - NumAsin => call_bitcode_fn(env, &[arg.into()], bitcode::NUM_ASIN), + NumIsFinite => { + call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[arg.into()], float_width) + } + + NumRound => call_bitcode_float_fn(env, bitcode::NUM_ROUND, &[arg.into()], float_width), + + // trigonometry + NumSin => env.call_intrinsic(LLVM_SIN_F64, &[arg.into()]), + NumCos => env.call_intrinsic(LLVM_COS_F64, &[arg.into()]), + + NumAtan => call_bitcode_float_fn(env, bitcode::NUM_ATAN, &[arg.into()], float_width), + NumAcos => call_bitcode_float_fn(env, bitcode::NUM_ACOS, &[arg.into()], float_width), + NumAsin => call_bitcode_float_fn(env, bitcode::NUM_ASIN, &[arg.into()], float_width), + _ => { 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)), + IntWidth::Usize => call_bitcode_fn(env, args, &format!("{}_usize", 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"), + } +} + +pub fn call_float_intrinsic<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + fn_name: &str, + args: &[BasicValueEnum<'ctx>], + float_width: FloatWidth, +) -> BasicValueEnum<'ctx> { + let suffix = match float_width { + FloatWidth::F32 => "f32", + FloatWidth::F64 => "f64", + FloatWidth::F128 => "f128", + }; + + env.call_intrinsic(&format!("{}.{}", fn_name, suffix), args) +} + +pub fn call_int_intrinsic<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + fn_name: &str, + args: &[BasicValueEnum<'ctx>], + int_width: IntWidth, +) -> BasicValueEnum<'ctx> { + let suffix = match int_width { + IntWidth::I8 => "i8", + IntWidth::I16 => "162", + IntWidth::I32 => "i32", + IntWidth::I64 => "i64", + IntWidth::I128 => "i128", + IntWidth::U8 => "i8", + IntWidth::U16 => "162", + IntWidth::U32 => "i32", + IntWidth::U64 => "i64", + IntWidth::U128 => "i128", + IntWidth::Usize => match env.ptr_bytes { + 4 => "i32", + 8 => "i64", + _ => unreachable!("unsupported pointer size"), + }, + }; + + env.call_intrinsic(&format!("{}.{}", fn_name, suffix), args) +} + fn define_global_str_literal_ptr<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, message: &str, diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index ddc6cd645b..cec5b79205 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -502,38 +502,6 @@ pub fn list_walk_generic<'a, 'ctx, 'env>( 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> 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) pub fn list_range<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -552,7 +520,7 @@ pub fn list_range<'a, 'ctx, 'env>( let int_width = env .context .i8_type() - .const_int(IntWidth::from(builtin) as u64, false) + .const_int(crate::llvm::build::IntWidth::from(builtin) as u64, false) .into(); call_bitcode_fn( From 9fc832d8ef78c53e5c2b8b2b6f6814494126139d Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 15:18:02 +0200 Subject: [PATCH 03/10] new intrinsic approach --- compiler/builtins/src/bitcode.rs | 90 ++++++++++++ compiler/gen_llvm/src/llvm/build.rs | 171 ++++++++++++----------- compiler/gen_llvm/src/llvm/build_list.rs | 2 +- 3 files changed, 179 insertions(+), 84 deletions(-) diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 976c4cb9a1..9bddc3ce2e 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -1,8 +1,98 @@ +use std::ops::Index; + pub const OBJ_PATH: &str = env!( "BUILTINS_O", "Env var BUILTINS_O not found. Is there a problem with the build script?" ); +#[derive(Default)] +pub struct IntrinsicName { + pub options: [ &'static str; 12 ], + pub is_float: bool, + pub is_int: bool, +} + +impl IntrinsicName { + pub const fn default() -> Self { + Self { + options: [ ""; 12 ], + is_float: false, + is_int: false, + } + } + + pub fn intrinsics<'a>(&'a self) -> impl Iterator { + let start_index = if self.is_float { 0} else { 3 }; + let end_index = if self.is_int { 12 } else { 3 }; + + let slice = &self.options[start_index..end_index]; + + slice.iter() + } +} + + +#[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 for IntrinsicName { + type Output = str; + + fn index(&self, index: FloatWidth) -> &Self::Output { + match index { + FloatWidth::F32 => self.options[0], + FloatWidth::F64 => self.options[1], + FloatWidth::F128 => self.options[2], + } + } +} + +impl Index for IntrinsicName { + type Output = str; + + fn index(&self, index: IntWidth) -> &Self::Output { + match index { + IntWidth::U8 => self.options[3], + IntWidth::U16 => self.options[4], + IntWidth::U32 => self.options[5], + IntWidth::U64 => self.options[6], + IntWidth::U128 => self.options[7], + IntWidth::I8 => self.options[8], + IntWidth::I16 => self.options[9], + IntWidth::I32 => self.options[10], + IntWidth::I64 => self.options[11], + IntWidth::I128 => self.options[12], + } + } +} + + + + pub const NUM_ASIN: &str = "roc_builtins.num.asin"; pub const NUM_ACOS: &str = "roc_builtins.num.acos"; pub const NUM_ATAN: &str = "roc_builtins.num.atan"; diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index ef4872c777..4a5c574be1 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -48,7 +48,7 @@ use inkwell::{AddressSpace, IntPredicate}; use morphic_lib::{ CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar, }; -use roc_builtins::bitcode; +use roc_builtins::bitcode::{self, IntrinsicName, IntWidth, FloatWidth, DecWidth}; use roc_collections::all::{ImMap, MutMap, MutSet}; use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, ModuleId, Symbol}; @@ -487,16 +487,19 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { i64_type.fn_type(&[f64_type.into()], false), ); + + for name in LLVM_POW.intrinsics() { + add_intrinsic( + module, + name, + f64_type.fn_type(&[f64_type.into(), f64_type.into()], false), + ); + } + for width in ["f32", "f64"] { let name = format!("{}.{}", LLVM_FABS, width); add_intrinsic(module, &name, f64_type.fn_type(&[f64_type.into()], false)); - let name = format!("{}.{}", LLVM_POW, width); - add_intrinsic( - module, - &name, - f64_type.fn_type(&[f64_type.into(), f64_type.into()], false), - ); } add_intrinsic( @@ -572,6 +575,57 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { }); } +macro_rules! define_float_intrinsic { + ($name:literal, $output:expr) => { + $output.options[0] = concat!($name, ".f32"); + $output.options[1] = concat!($name, ".f64"); + $output.options[2] = concat!($name, ".f128"); + }; +} + +macro_rules! define_int_intrinsic { + ($name:literal, $output:expr) => { + $output.options[3] = concat!($name, ".i8"); + $output.options[4] = concat!($name, ".i16"); + $output.options[5] = concat!($name, ".i32"); + $output.options[6] = concat!($name, ".i64"); + $output.options[7] = concat!($name, ".i128"); + $output.options[8] = concat!($name, ".i8"); + $output.options[9] = concat!($name, ".i16"); + $output.options[10] = concat!($name, ".i32"); + $output.options[11] = concat!($name, ".i64"); + $output.options[12] = concat!($name, ".i128"); + }; + +} + +macro_rules! float_intrinsic { + ($name:literal) => { { + let mut output = IntrinsicName::default(); + + define_float_intrinsic!($name, output); + + output.is_float = true; + + output + }}; +} + +macro_rules! int_intrinsic { + ($name:literal) => { { + let mut output = IntrinsicName::default(); + + define_int_intrinsic!($name, output); + + output.is_int = true; + + output + }}; +} + +// pub const LLVM_FABS: IntrinsicName = float_intrinsic!("llvm.fabs"); +static LLVM_POW: IntrinsicName = float_intrinsic!("llvm.pow"); + static LLVM_MEMSET_I64: &str = "llvm.memset.p0i8.i64"; static LLVM_MEMSET_I32: &str = "llvm.memset.p0i8.i32"; static LLVM_SQRT_F64: &str = "llvm.sqrt.f64"; @@ -580,7 +634,6 @@ static LLVM_LROUND_I64_F64: &str = "llvm.lround.i64.f64"; static LLVM_FABS: &str = "llvm.fabs"; static LLVM_SIN_F64: &str = "llvm.sin.f64"; static LLVM_COS_F64: &str = "llvm.cos.f64"; -static LLVM_POW: &str = "llvm.pow"; static LLVM_CEILING_F64: &str = "llvm.ceil.f64"; static LLVM_FLOOR_F64: &str = "llvm.floor.f64"; @@ -5902,6 +5955,31 @@ fn throw_on_overflow<'a, 'ctx, 'env>( .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>( env: &Env<'a, 'ctx, 'env>, parent: FunctionValue<'ctx>, @@ -5916,7 +5994,7 @@ fn build_int_binop<'a, 'ctx, 'env>( let bd = env.builder; - let int_width = IntWidth::from(*lhs_layout); + let int_width = intwidth_from_layout(*lhs_layout, env.ptr_bytes); match op { NumAdd => { @@ -6311,7 +6389,7 @@ fn build_float_binop<'a, 'ctx, 'env>( NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(), NumRemUnchecked => bd.build_float_rem(lhs, rhs, "rem_float").into(), NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(), - NumPow => call_float_intrinsic(env, LLVM_POW, &[lhs.into(), rhs.into()], float_width), + NumPow => env.call_intrinsic(&LLVM_POW[float_width], &[lhs.into(), rhs.into()]), _ => { unreachable!("Unrecognized int binary operation: {:?}", op); } @@ -6549,52 +6627,6 @@ fn int_abs_with_overflow<'a, 'ctx, 'env>( )) } -#[repr(u8)] -pub enum FloatWidth { - F32, - F64, - F128, -} - -#[repr(u8)] -pub enum IntWidth { - U8, - U16, - U32, - U64, - U128, - I8, - I16, - I32, - I64, - I128, - Usize, -} - -impl From> 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!(), - } - } -} - -impl From> for IntWidth { - fn from(layout: Layout) -> Self { - match layout { - Layout::Builtin(builtin) => IntWidth::from(builtin), - _ => unreachable!(), - } - } -} fn build_float_unary_op<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -6662,7 +6694,6 @@ pub fn call_bitcode_int_fn<'a, 'ctx, 'env>( 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)), - IntWidth::Usize => call_bitcode_fn(env, args, &format!("{}_usize", fn_name)), } } @@ -6694,32 +6725,6 @@ pub fn call_float_intrinsic<'a, 'ctx, 'env>( env.call_intrinsic(&format!("{}.{}", fn_name, suffix), args) } -pub fn call_int_intrinsic<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - fn_name: &str, - args: &[BasicValueEnum<'ctx>], - int_width: IntWidth, -) -> BasicValueEnum<'ctx> { - let suffix = match int_width { - IntWidth::I8 => "i8", - IntWidth::I16 => "162", - IntWidth::I32 => "i32", - IntWidth::I64 => "i64", - IntWidth::I128 => "i128", - IntWidth::U8 => "i8", - IntWidth::U16 => "162", - IntWidth::U32 => "i32", - IntWidth::U64 => "i64", - IntWidth::U128 => "i128", - IntWidth::Usize => match env.ptr_bytes { - 4 => "i32", - 8 => "i64", - _ => unreachable!("unsupported pointer size"), - }, - }; - - env.call_intrinsic(&format!("{}.{}", fn_name, suffix), args) -} fn define_global_str_literal_ptr<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index cec5b79205..9050dc0fb7 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -520,7 +520,7 @@ pub fn list_range<'a, 'ctx, 'env>( let int_width = env .context .i8_type() - .const_int(crate::llvm::build::IntWidth::from(builtin) as u64, false) + .const_int(crate::llvm::build::intwidth_from_builtin(builtin, env.ptr_bytes) as u64, false) .into(); call_bitcode_fn( From ab34c2a55e51adcd6bea4c2e3eb9ccdbedf6090b Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 16:21:57 +0200 Subject: [PATCH 04/10] generalize all number intrinsics --- compiler/builtins/src/bitcode.rs | 53 ++--- compiler/gen_llvm/src/llvm/build.rs | 347 +++++++++++++--------------- 2 files changed, 182 insertions(+), 218 deletions(-) diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 9bddc3ce2e..4387aebad6 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -5,25 +5,27 @@ pub const OBJ_PATH: &str = env!( "Env var BUILTINS_O not found. Is there a problem with the build script?" ); -#[derive(Default)] -pub struct IntrinsicName { - pub options: [ &'static str; 12 ], +#[derive(Debug, Default)] +pub struct IntrinsicName { + pub base: &'static str, + pub options: [&'static str; 13], pub is_float: bool, pub is_int: bool, } -impl IntrinsicName { - pub const fn default() -> Self { - Self { - options: [ ""; 12 ], +impl IntrinsicName { + pub const fn default() -> Self { + Self { + base: "", + options: [""; 13], is_float: false, is_int: false, } } - pub fn intrinsics<'a>(&'a self) -> impl Iterator { - let start_index = if self.is_float { 0} else { 3 }; - let end_index = if self.is_int { 12 } else { 3 }; + pub fn intrinsics<'a>(&'a self) -> impl Iterator { + let start_index = if self.is_float { 0 } else { 3 }; + let end_index = if self.is_int { 13 } else { 3 }; let slice = &self.options[start_index..end_index]; @@ -31,7 +33,6 @@ impl IntrinsicName { } } - #[repr(u8)] pub enum DecWidth { Dec, @@ -58,15 +59,14 @@ pub enum IntWidth { I128, } - impl Index for IntrinsicName { type Output = str; fn index(&self, index: FloatWidth) -> &Self::Output { match index { - FloatWidth::F32 => self.options[0], - FloatWidth::F64 => self.options[1], - FloatWidth::F128 => self.options[2], + FloatWidth::F32 => self.options[0], + FloatWidth::F64 => self.options[1], + FloatWidth::F128 => self.options[2], } } } @@ -76,23 +76,20 @@ impl Index for IntrinsicName { fn index(&self, index: IntWidth) -> &Self::Output { match index { - IntWidth::U8 => self.options[3], - IntWidth::U16 => self.options[4], - IntWidth::U32 => self.options[5], - IntWidth::U64 => self.options[6], - IntWidth::U128 => self.options[7], - IntWidth::I8 => self.options[8], - IntWidth::I16 => self.options[9], - IntWidth::I32 => self.options[10], - IntWidth::I64 => self.options[11], - IntWidth::I128 => self.options[12], + IntWidth::U8 => self.options[3], + IntWidth::U16 => self.options[4], + IntWidth::U32 => self.options[5], + IntWidth::U64 => self.options[6], + IntWidth::U128 => self.options[7], + IntWidth::I8 => self.options[8], + IntWidth::I16 => self.options[9], + IntWidth::I32 => self.options[10], + IntWidth::I64 => self.options[11], + IntWidth::I128 => self.options[12], } } } - - - pub const NUM_ASIN: &str = "roc_builtins.num.asin"; pub const NUM_ACOS: &str = "roc_builtins.num.acos"; pub const NUM_ATAN: &str = "roc_builtins.num.atan"; diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 4a5c574be1..b85f491fa1 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -48,7 +48,7 @@ use inkwell::{AddressSpace, IntPredicate}; use morphic_lib::{ CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar, }; -use roc_builtins::bitcode::{self, IntrinsicName, IntWidth, FloatWidth, DecWidth}; +use roc_builtins::bitcode::{self, DecWidth, FloatWidth, IntWidth, IntrinsicName}; use roc_collections::all::{ImMap, MutMap, MutSet}; use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, ModuleId, Symbol}; @@ -430,6 +430,58 @@ pub fn module_from_builtins<'ctx>( 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>) { // List of all supported LLVM intrinsics: // @@ -438,7 +490,6 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { let i1_type = ctx.bool_type(); let i8_type = ctx.i8_type(); let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic); - let i16_type = ctx.i16_type(); let i32_type = ctx.i32_type(); let i64_type = ctx.i64_type(); let void_type = ctx.void_type(); @@ -475,167 +526,105 @@ 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_LOG_F64, - f64_type.fn_type(&[f64_type.into()], false), - ); - add_intrinsic( module, LLVM_LROUND_I64_F64, i64_type.fn_type(&[f64_type.into()], 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)); - for name in LLVM_POW.intrinsics() { - add_intrinsic( - module, - name, - f64_type.fn_type(&[f64_type.into(), f64_type.into()], false), - ); - } - - for width in ["f32", "f64"] { - let name = format!("{}.{}", LLVM_FABS, width); - add_intrinsic(module, &name, f64_type.fn_type(&[f64_type.into()], false)); - - } - - add_intrinsic( - module, - 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_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()]; + add_int_intrinsic(ctx, module, &LLVM_SADD_WITH_OVERFLOW, |t| { + let fields = [t.into(), i1_type.into()]; 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, { - let fields = [i16_type.into(), i1_type.into()]; + add_int_intrinsic(ctx, module, &LLVM_SSUB_WITH_OVERFLOW, |t| { + let fields = [t.into(), i1_type.into()]; 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, { - let fields = [i32_type.into(), i1_type.into()]; + add_int_intrinsic(ctx, module, &LLVM_SMUL_WITH_OVERFLOW, |t| { + let fields = [t.into(), i1_type.into()]; ctx.struct_type(&fields, false) - .fn_type(&[i32_type.into(), i32_type.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) + .fn_type(&[t.into(), t.into()], false) }); } -macro_rules! define_float_intrinsic { - ($name:literal, $output:expr) => { +macro_rules! define_float_intrinsic { + ($name:literal, $output:expr) => { $output.options[0] = concat!($name, ".f32"); $output.options[1] = concat!($name, ".f64"); $output.options[2] = concat!($name, ".f128"); }; } -macro_rules! define_int_intrinsic { - ($name:literal, $output:expr) => { - $output.options[3] = concat!($name, ".i8"); - $output.options[4] = concat!($name, ".i16"); - $output.options[5] = concat!($name, ".i32"); - $output.options[6] = concat!($name, ".i64"); - $output.options[7] = concat!($name, ".i128"); - $output.options[8] = concat!($name, ".i8"); - $output.options[9] = concat!($name, ".i16"); - $output.options[10] = concat!($name, ".i32"); - $output.options[11] = concat!($name, ".i64"); - $output.options[12] = concat!($name, ".i128"); +macro_rules! define_int_intrinsic { + ($name:literal, $output:expr) => { + $output.options[3] = concat!($name, ".i8"); + $output.options[4] = concat!($name, ".i16"); + $output.options[5] = concat!($name, ".i32"); + $output.options[6] = concat!($name, ".i64"); + $output.options[7] = concat!($name, ".i128"); + $output.options[8] = concat!($name, ".i8"); + $output.options[9] = concat!($name, ".i16"); + $output.options[10] = concat!($name, ".i32"); + $output.options[11] = concat!($name, ".i64"); + $output.options[12] = concat!($name, ".i128"); }; - } -macro_rules! float_intrinsic { - ($name:literal) => { { - let mut output = IntrinsicName::default(); +macro_rules! float_intrinsic { + ($name:literal) => {{ + let mut output = IntrinsicName::default(); define_float_intrinsic!($name, output); output.is_float = true; + output.base = $name; output }}; } -macro_rules! int_intrinsic { - ($name:literal) => { { - let mut output = IntrinsicName::default(); +macro_rules! int_intrinsic { + ($name:literal) => {{ + let mut output = IntrinsicName::default(); define_int_intrinsic!($name, output); output.is_int = true; + output.base = $name; output }}; } -// pub const LLVM_FABS: IntrinsicName = float_intrinsic!("llvm.fabs"); -static LLVM_POW: IntrinsicName = float_intrinsic!("llvm.pow"); +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_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_FABS: &str = "llvm.fabs"; -static LLVM_SIN_F64: &str = "llvm.sin.f64"; -static LLVM_COS_F64: &str = "llvm.cos.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.p0i8"; @@ -644,19 +633,9 @@ static LLVM_STACK_SAVE: &str = "llvm.stacksave"; static LLVM_SETJMP: &str = "llvm.eh.sjlj.setjmp"; pub static LLVM_LONGJMP: &str = "llvm.eh.sjlj.longjmp"; -pub static LLVM_SADD_WITH_OVERFLOW_I8: &str = "llvm.sadd.with.overflow.i8"; -pub static LLVM_SADD_WITH_OVERFLOW_I16: &str = "llvm.sadd.with.overflow.i16"; -pub static LLVM_SADD_WITH_OVERFLOW_I32: &str = "llvm.sadd.with.overflow.i32"; -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"; +const LLVM_SADD_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.sadd.with.overflow"); +const LLVM_SSUB_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.ssub.with.overflow"); +const LLVM_SMUL_WITH_OVERFLOW: IntrinsicName = int_intrinsic!("llvm.smul.with.overflow"); fn add_intrinsic<'ctx>( module: &Module<'ctx>, @@ -5955,29 +5934,29 @@ fn throw_on_overflow<'a, 'ctx, 'env>( .unwrap() } -pub fn intwidth_from_builtin(builtin: Builtin<'_>, ptr_bytes: u32) -> IntWidth { - use IntWidth::*; +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!(), - } + 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 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>( @@ -5998,60 +5977,50 @@ fn build_int_binop<'a, 'ctx, 'env>( match op { 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 - .call_intrinsic(intrinsic, &[lhs.into(), rhs.into()]) + .call_intrinsic( + &LLVM_SADD_WITH_OVERFLOW[int_width], + &[lhs.into(), rhs.into()], + ) .into_struct_value(); throw_on_overflow(env, parent, result, "integer addition overflowed!") } 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 => { - 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 - .call_intrinsic(intrinsic, &[lhs.into(), rhs.into()]) + .call_intrinsic( + &LLVM_SSUB_WITH_OVERFLOW[int_width], + &[lhs.into(), rhs.into()], + ) .into_struct_value(); throw_on_overflow(env, parent, result, "integer subtraction overflowed!") } 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 => { 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(); throw_on_overflow(env, parent, result, "integer multiplication overflowed!") } 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(), NumGte => bd.build_int_compare(SGE, lhs, rhs, "int_gte").into(), NumLt => bd.build_int_compare(SLT, lhs, rhs, "int_lt").into(), @@ -6627,7 +6596,6 @@ fn int_abs_with_overflow<'a, 'ctx, 'env>( )) } - fn build_float_unary_op<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, arg: FloatValue<'ctx>, @@ -6641,19 +6609,19 @@ fn build_float_unary_op<'a, 'ctx, 'env>( // TODO: Handle different sized floats match op { NumNeg => bd.build_float_neg(arg, "negate_float").into(), - NumAbs => call_float_intrinsic(env, LLVM_FABS, &[arg.into()], float_width), - NumSqrtUnchecked => env.call_intrinsic(LLVM_SQRT_F64, &[arg.into()]), - NumLogUnchecked => env.call_intrinsic(LLVM_LOG_F64, &[arg.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()]), NumToFloat => arg.into(), /* Converting from Float to Float is a no-op */ NumCeiling => env.builder.build_cast( InstructionOpcode::FPToSI, - env.call_intrinsic(LLVM_CEILING_F64, &[arg.into()]), + env.call_intrinsic(&LLVM_CEILING[float_width], &[arg.into()]), env.context.i64_type(), "num_ceiling", ), NumFloor => env.builder.build_cast( InstructionOpcode::FPToSI, - env.call_intrinsic(LLVM_FLOOR_F64, &[arg.into()]), + env.call_intrinsic(&LLVM_FLOOR[float_width], &[arg.into()]), env.context.i64_type(), "num_floor", ), @@ -6664,8 +6632,8 @@ fn build_float_unary_op<'a, 'ctx, 'env>( NumRound => call_bitcode_float_fn(env, bitcode::NUM_ROUND, &[arg.into()], float_width), // trigonometry - NumSin => env.call_intrinsic(LLVM_SIN_F64, &[arg.into()]), - NumCos => env.call_intrinsic(LLVM_COS_F64, &[arg.into()]), + NumSin => env.call_intrinsic(&LLVM_SIN[float_width], &[arg.into()]), + NumCos => env.call_intrinsic(&LLVM_COS[float_width], &[arg.into()]), NumAtan => call_bitcode_float_fn(env, bitcode::NUM_ATAN, &[arg.into()], float_width), NumAcos => call_bitcode_float_fn(env, bitcode::NUM_ACOS, &[arg.into()], float_width), @@ -6725,7 +6693,6 @@ pub fn call_float_intrinsic<'a, 'ctx, 'env>( env.call_intrinsic(&format!("{}.{}", fn_name, suffix), args) } - fn define_global_str_literal_ptr<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, message: &str, From 63b1aaad4e6d17c2e884b6d97a64c0a013f2a68d Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 16:43:39 +0200 Subject: [PATCH 05/10] hook up polymorphic zig builtins --- compiler/builtins/bitcode/src/main.zig | 16 ++-- compiler/builtins/bitcode/src/num.zig | 9 ++- compiler/builtins/src/bitcode.rs | 101 +++++++++++++++---------- compiler/gen_dev/src/lib.rs | 12 +-- compiler/gen_llvm/src/llvm/build.rs | 70 ++++++++--------- 5 files changed, 114 insertions(+), 94 deletions(-) diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index 4993256c33..c34f16a144 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -78,26 +78,26 @@ comptime { // Num Module const num = @import("num.zig"); -const INTEGERS = [_]type{ i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize }; +const INTEGERS = [_]type{ i8, i16, i32, i64, i128, u8, u16, u32, u64, u128 }; const FLOATS = [_]type{ f32, f64 }; const NUMBERS = INTEGERS ++ FLOATS; comptime { - exportNumFn(num.divCeil, "div_ceil"); exportNumFn(num.bytesToU16C, "bytes_to_u16"); exportNumFn(num.bytesToU32C, "bytes_to_u32"); inline for (INTEGERS) |T| { - num.exportPow(T, ROC_BUILTINS ++ "." ++ NUM ++ ".pow_int_"); + 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 ++ ".acos_"); - num.exportAcos(T, ROC_BUILTINS ++ "." ++ NUM ++ ".asin_"); - num.exportAtan(T, ROC_BUILTINS ++ "." ++ NUM ++ ".atan_"); + num.exportAsin(T, ROC_BUILTINS ++ "." ++ NUM ++ ".acos."); + num.exportAcos(T, ROC_BUILTINS ++ "." ++ NUM ++ ".asin."); + num.exportAtan(T, ROC_BUILTINS ++ "." ++ NUM ++ ".atan."); - num.exportIsFinite(T, ROC_BUILTINS ++ "." ++ NUM ++ ".is_finite_"); - num.exportRound(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round_"); + num.exportIsFinite(T, ROC_BUILTINS ++ "." ++ NUM ++ ".is_finite."); + num.exportRound(T, ROC_BUILTINS ++ "." ++ NUM ++ ".round."); } } diff --git a/compiler/builtins/bitcode/src/num.zig b/compiler/builtins/bitcode/src/num.zig index 0884d693a7..a3cfdcbb54 100644 --- a/compiler/builtins/bitcode/src/num.zig +++ b/compiler/builtins/bitcode/src/num.zig @@ -57,8 +57,13 @@ pub fn exportRound(comptime T: type, comptime name: []const u8) void { @export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong }); } -pub fn divCeil(numerator: i64, denominator: i64) callconv(.C) i64 { - return @call(.{ .modifier = always_inline }, math.divCeil, .{ i64, numerator, denominator }) catch unreachable; +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 { diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 4387aebad6..7365ae0170 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -7,29 +7,12 @@ pub const OBJ_PATH: &str = env!( #[derive(Debug, Default)] pub struct IntrinsicName { - pub base: &'static str, - pub options: [&'static str; 13], - pub is_float: bool, - pub is_int: bool, + pub options: [&'static str; 14], } impl IntrinsicName { pub const fn default() -> Self { - Self { - base: "", - options: [""; 13], - is_float: false, - is_int: false, - } - } - - pub fn intrinsics<'a>(&'a self) -> impl Iterator { - let start_index = if self.is_float { 0 } else { 3 }; - let end_index = if self.is_int { 13 } else { 3 }; - - let slice = &self.options[start_index..end_index]; - - slice.iter() + Self { options: [""; 14] } } } @@ -59,14 +42,22 @@ pub enum IntWidth { I128, } +impl Index for IntrinsicName { + type Output = str; + + fn index(&self, _: DecWidth) -> &Self::Output { + self.options[0] + } +} + impl Index for IntrinsicName { type Output = str; fn index(&self, index: FloatWidth) -> &Self::Output { match index { - FloatWidth::F32 => self.options[0], - FloatWidth::F64 => self.options[1], - FloatWidth::F128 => self.options[2], + FloatWidth::F32 => self.options[1], + FloatWidth::F64 => self.options[2], + FloatWidth::F128 => self.options[3], } } } @@ -76,29 +67,61 @@ impl Index for IntrinsicName { fn index(&self, index: IntWidth) -> &Self::Output { match index { - IntWidth::U8 => self.options[3], - IntWidth::U16 => self.options[4], - IntWidth::U32 => self.options[5], - IntWidth::U64 => self.options[6], - IntWidth::U128 => self.options[7], - IntWidth::I8 => self.options[8], - IntWidth::I16 => self.options[9], - IntWidth::I32 => self.options[10], - IntWidth::I64 => self.options[11], - IntWidth::I128 => self.options[12], + 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], } } } -pub const NUM_ASIN: &str = "roc_builtins.num.asin"; -pub const NUM_ACOS: &str = "roc_builtins.num.acos"; -pub const NUM_ATAN: &str = "roc_builtins.num.atan"; -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"; +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_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_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_COUNT_SEGMENTS: &str = "roc_builtins.str.count_segments"; diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 6c06c85fec..6f8efe440c 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -3,7 +3,7 @@ #![allow(clippy::large_enum_variant, clippy::upper_case_acronyms)] use bumpalo::{collections::Vec, Bump}; -use roc_builtins::bitcode; +use roc_builtins::bitcode::{self, IntWidth}; use roc_collections::all::{MutMap, MutSet}; use roc_module::ident::{ModuleName, TagName}; use roc_module::low_level::LowLevel; @@ -400,21 +400,21 @@ where } LowLevel::NumAcos => self.build_fn_call( sym, - format!("{}_i64", bitcode::NUM_ACOS), + bitcode::NUM_ACOS[IntWidth::I64].to_string(), args, arg_layouts, ret_layout, ), LowLevel::NumAsin => self.build_fn_call( sym, - format!("{}_i64", bitcode::NUM_ASIN), + bitcode::NUM_ASIN[IntWidth::I64].to_string(), args, arg_layouts, ret_layout, ), LowLevel::NumAtan => self.build_fn_call( sym, - format!("{}_i64", bitcode::NUM_ATAN), + bitcode::NUM_ATAN[IntWidth::I64].to_string(), args, arg_layouts, ret_layout, @@ -437,7 +437,7 @@ where } LowLevel::NumPowInt => self.build_fn_call( sym, - format!("{}_i64", bitcode::NUM_POW_INT), + bitcode::NUM_POW_INT[IntWidth::I64].to_string(), args, arg_layouts, ret_layout, @@ -473,7 +473,7 @@ where } LowLevel::NumRound => self.build_fn_call( sym, - bitcode::NUM_ROUND.to_string(), + bitcode::NUM_ROUND[IntWidth::I64].to_string(), args, arg_layouts, ret_layout, diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index b85f491fa1..cef1e28211 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -565,24 +565,24 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { macro_rules! define_float_intrinsic { ($name:literal, $output:expr) => { - $output.options[0] = concat!($name, ".f32"); - $output.options[1] = concat!($name, ".f64"); - $output.options[2] = concat!($name, ".f128"); + $output.options[1] = concat!($name, ".f32"); + $output.options[2] = concat!($name, ".f64"); + $output.options[3] = concat!($name, ".f128"); }; } macro_rules! define_int_intrinsic { ($name:literal, $output:expr) => { - $output.options[3] = concat!($name, ".i8"); - $output.options[4] = concat!($name, ".i16"); - $output.options[5] = concat!($name, ".i32"); - $output.options[6] = concat!($name, ".i64"); - $output.options[7] = concat!($name, ".i128"); - $output.options[8] = concat!($name, ".i8"); - $output.options[9] = concat!($name, ".i16"); - $output.options[10] = concat!($name, ".i32"); - $output.options[11] = concat!($name, ".i64"); - $output.options[12] = concat!($name, ".i128"); + $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"); }; } @@ -592,9 +592,6 @@ macro_rules! float_intrinsic { define_float_intrinsic!($name, output); - output.is_float = true; - output.base = $name; - output }}; } @@ -605,9 +602,6 @@ macro_rules! int_intrinsic { define_int_intrinsic!($name, output); - output.is_int = true; - output.base = $name; - output }}; } @@ -6094,16 +6088,17 @@ fn build_int_binop<'a, 'ctx, 'env>( phi.as_basic_value() } } - NumPowInt => call_bitcode_int_fn( + NumPowInt => call_bitcode_fn( env, - bitcode::NUM_POW_INT, &[lhs.into(), rhs.into()], - int_width, + &bitcode::NUM_POW_INT[int_width], ), NumDivUnchecked => bd.build_int_signed_div(lhs, rhs, "div_int").into(), - NumDivCeilUnchecked => { - call_bitcode_fn(env, &[lhs.into(), rhs.into()], bitcode::NUM_DIV_CEIL) - } + NumDivCeilUnchecked => call_bitcode_fn( + env, + &[lhs.into(), rhs.into()], + &bitcode::NUM_DIV_CEIL[int_width], + ), NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(), NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(), NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(), @@ -6206,7 +6201,7 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_add(lhs, rhs, "add_float"); let is_finite = - call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + 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"); @@ -6228,7 +6223,7 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_add(lhs, rhs, "add_float"); let is_finite = - call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width]) .into_int_value(); let is_infinite = bd.build_not(is_finite, "negate"); @@ -6257,7 +6252,7 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_sub(lhs, rhs, "sub_float"); let is_finite = - call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + 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"); @@ -6279,7 +6274,7 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_sub(lhs, rhs, "sub_float"); let is_finite = - call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width]) .into_int_value(); let is_infinite = bd.build_not(is_finite, "negate"); @@ -6308,7 +6303,7 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_mul(lhs, rhs, "mul_float"); let is_finite = - call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + 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"); @@ -6330,7 +6325,7 @@ fn build_float_binop<'a, 'ctx, 'env>( let result = bd.build_float_mul(lhs, rhs, "mul_float"); let is_finite = - call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[result.into()], float_width) + call_bitcode_fn(env, &[result.into()], &bitcode::NUM_IS_FINITE[float_width]) .into_int_value(); let is_infinite = bd.build_not(is_finite, "negate"); @@ -6625,19 +6620,16 @@ fn build_float_unary_op<'a, 'ctx, 'env>( env.context.i64_type(), "num_floor", ), - NumIsFinite => { - call_bitcode_float_fn(env, bitcode::NUM_IS_FINITE, &[arg.into()], float_width) - } - - NumRound => call_bitcode_float_fn(env, bitcode::NUM_ROUND, &[arg.into()], float_width), + NumIsFinite => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_IS_FINITE[float_width]), + NumRound => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ROUND[float_width]), // trigonometry NumSin => env.call_intrinsic(&LLVM_SIN[float_width], &[arg.into()]), NumCos => env.call_intrinsic(&LLVM_COS[float_width], &[arg.into()]), - NumAtan => call_bitcode_float_fn(env, bitcode::NUM_ATAN, &[arg.into()], float_width), - NumAcos => call_bitcode_float_fn(env, bitcode::NUM_ACOS, &[arg.into()], float_width), - NumAsin => call_bitcode_float_fn(env, bitcode::NUM_ASIN, &[arg.into()], 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]), + NumAsin => call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_ASIN[float_width]), _ => { unreachable!("Unrecognized int unary operation: {:?}", op); From a072d8d1b1534e9e99249da4e296ee3c0300ef99 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 16:56:04 +0200 Subject: [PATCH 06/10] fix things --- compiler/builtins/bitcode/src/main.zig | 4 ++-- compiler/gen_dev/src/lib.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/builtins/bitcode/src/main.zig b/compiler/builtins/bitcode/src/main.zig index c34f16a144..2eea0b6464 100644 --- a/compiler/builtins/bitcode/src/main.zig +++ b/compiler/builtins/bitcode/src/main.zig @@ -92,8 +92,8 @@ comptime { } inline for (FLOATS) |T| { - num.exportAsin(T, ROC_BUILTINS ++ "." ++ NUM ++ ".acos."); - num.exportAcos(T, ROC_BUILTINS ++ "." ++ NUM ++ ".asin."); + 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."); diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 6f8efe440c..bd13de5960 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -3,7 +3,7 @@ #![allow(clippy::large_enum_variant, clippy::upper_case_acronyms)] use bumpalo::{collections::Vec, Bump}; -use roc_builtins::bitcode::{self, IntWidth}; +use roc_builtins::bitcode::{self, FloatWidth, IntWidth}; use roc_collections::all::{MutMap, MutSet}; use roc_module::ident::{ModuleName, TagName}; use roc_module::low_level::LowLevel; @@ -400,21 +400,21 @@ where } LowLevel::NumAcos => self.build_fn_call( sym, - bitcode::NUM_ACOS[IntWidth::I64].to_string(), + bitcode::NUM_ACOS[FloatWidth::F64].to_string(), args, arg_layouts, ret_layout, ), LowLevel::NumAsin => self.build_fn_call( sym, - bitcode::NUM_ASIN[IntWidth::I64].to_string(), + bitcode::NUM_ASIN[FloatWidth::F64].to_string(), args, arg_layouts, ret_layout, ), LowLevel::NumAtan => self.build_fn_call( sym, - bitcode::NUM_ATAN[IntWidth::I64].to_string(), + bitcode::NUM_ATAN[FloatWidth::F64].to_string(), args, arg_layouts, ret_layout, @@ -473,7 +473,7 @@ where } LowLevel::NumRound => self.build_fn_call( sym, - bitcode::NUM_ROUND[IntWidth::I64].to_string(), + bitcode::NUM_ROUND[FloatWidth::F64].to_string(), args, arg_layouts, ret_layout, From f8dec9453bac71b5d9eef8bfb285bfca0258edde Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 16:58:25 +0200 Subject: [PATCH 07/10] make things static again --- compiler/gen_llvm/src/llvm/build.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index cef1e28211..81fa0a0b01 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -48,7 +48,7 @@ use inkwell::{AddressSpace, IntPredicate}; use morphic_lib::{ CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar, }; -use roc_builtins::bitcode::{self, DecWidth, FloatWidth, IntWidth, IntrinsicName}; +use roc_builtins::bitcode::{self, FloatWidth, IntWidth, IntrinsicName}; use roc_collections::all::{ImMap, MutMap, MutSet}; use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, ModuleId, Symbol}; @@ -229,7 +229,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { pub fn call_intrinsic( &self, - intrinsic_name: &str, + intrinsic_name: &'static str, args: &[BasicValueEnum<'ctx>], ) -> BasicValueEnum<'ctx> { let call = self.build_intrinsic_call(intrinsic_name, args); @@ -6670,21 +6670,6 @@ pub fn call_bitcode_float_fn<'a, 'ctx, 'env>( } } -pub fn call_float_intrinsic<'a, 'ctx, 'env>( - env: &Env<'a, 'ctx, 'env>, - fn_name: &str, - args: &[BasicValueEnum<'ctx>], - float_width: FloatWidth, -) -> BasicValueEnum<'ctx> { - let suffix = match float_width { - FloatWidth::F32 => "f32", - FloatWidth::F64 => "f64", - FloatWidth::F128 => "f128", - }; - - env.call_intrinsic(&format!("{}.{}", fn_name, suffix), args) -} - fn define_global_str_literal_ptr<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, message: &str, From 7735ca21eaa9b917789a59b2610fe7990a2c1d72 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 17:03:55 +0200 Subject: [PATCH 08/10] cleanup --- compiler/builtins/bitcode/src/utils.zig | 33 ------------------------- compiler/gen_llvm/src/llvm/build.rs | 2 +- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/compiler/builtins/bitcode/src/utils.zig b/compiler/builtins/bitcode/src/utils.zig index 9f407c5b83..1371afe674 100644 --- a/compiler/builtins/bitcode/src/utils.zig +++ b/compiler/builtins/bitcode/src/utils.zig @@ -261,36 +261,3 @@ pub const UpdateMode = extern enum(u8) { Immutable = 0, InPlace = 1, }; - -/// Functions of the form `a -> b` -pub fn generateAtoB( - comptime A: type, - comptime B: type, - comptime function: fn (A) B, - comptime name: []const u8, -) void { - comptime var f = struct { - fn func(input: A) callconv(.C) B { - return function(input); - } - }.func; - const args = .{ .name = name ++ @typeName(A), .linkage = .Strong }; - @export(f, args); -} - -/// Functions of the form `a, b -> c` -pub fn generateAtoBtoC( - comptime A: type, - comptime B: type, - comptime C: type, - comptime function: fn (A, B) C, - comptime name: []const u8, -) void { - comptime var f = struct { - fn func(input1: A, input2: B) callconv(.C) C { - return function(input1, input2); - } - }.func; - const args = .{ .name = name ++ @typeName(A), .linkage = .Strong }; - @export(f, args); -} diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 81fa0a0b01..d5bfdd4076 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -204,7 +204,7 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { pub fn build_intrinsic_call( &self, - intrinsic_name: &str, + intrinsic_name: &'static str, args: &[BasicValueEnum<'ctx>], ) -> CallSiteValue<'ctx> { let fn_val = self From 76e26e47f331df5bae5dec2a5db14b7976377c73 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 17:05:59 +0200 Subject: [PATCH 09/10] more cleanup --- compiler/builtins/src/bitcode.rs | 2 ++ compiler/gen_llvm/src/llvm/build.rs | 44 +---------------------------- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/compiler/builtins/src/bitcode.rs b/compiler/builtins/src/bitcode.rs index 7365ae0170..2623b2ad3b 100644 --- a/compiler/builtins/src/bitcode.rs +++ b/compiler/builtins/src/bitcode.rs @@ -81,6 +81,7 @@ impl Index for IntrinsicName { } } +#[macro_export] macro_rules! float_intrinsic { ($name:literal) => {{ let mut output = IntrinsicName::default(); @@ -93,6 +94,7 @@ macro_rules! float_intrinsic { }}; } +#[macro_export] macro_rules! int_intrinsic { ($name:literal) => {{ let mut output = IntrinsicName::default(); diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index d5bfdd4076..fc94166f7e 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -49,6 +49,7 @@ use morphic_lib::{ CalleeSpecVar, FuncName, FuncSpec, FuncSpecSolutions, ModSolutions, UpdateMode, UpdateModeVar, }; use roc_builtins::bitcode::{self, FloatWidth, IntWidth, IntrinsicName}; +use roc_builtins::{float_intrinsic, int_intrinsic}; use roc_collections::all::{ImMap, MutMap, MutSet}; use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, ModuleId, Symbol}; @@ -563,49 +564,6 @@ fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) { }); } -macro_rules! define_float_intrinsic { - ($name:literal, $output:expr) => { - $output.options[1] = concat!($name, ".f32"); - $output.options[2] = concat!($name, ".f64"); - $output.options[3] = concat!($name, ".f128"); - }; -} - -macro_rules! define_int_intrinsic { - ($name:literal, $output:expr) => { - $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"); - }; -} - -macro_rules! float_intrinsic { - ($name:literal) => {{ - let mut output = IntrinsicName::default(); - - define_float_intrinsic!($name, output); - - output - }}; -} - -macro_rules! int_intrinsic { - ($name:literal) => {{ - let mut output = IntrinsicName::default(); - - define_int_intrinsic!($name, output); - - output - }}; -} - const LLVM_POW: IntrinsicName = float_intrinsic!("llvm.pow"); const LLVM_FABS: IntrinsicName = float_intrinsic!("llvm.fabs"); static LLVM_SQRT: IntrinsicName = float_intrinsic!("llvm.sqrt"); From dd38d4933546d5193ec3ee0b99269f9f24a7c5b5 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 20 Oct 2021 19:44:26 +0200 Subject: [PATCH 10/10] fix formatting --- compiler/gen_llvm/src/llvm/build_list.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index 9050dc0fb7..3d80912689 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -520,7 +520,10 @@ pub fn list_range<'a, 'ctx, 'env>( let int_width = env .context .i8_type() - .const_int(crate::llvm::build::intwidth_from_builtin(builtin, env.ptr_bytes) as u64, false) + .const_int( + crate::llvm::build::intwidth_from_builtin(builtin, env.ptr_bytes) as u64, + false, + ) .into(); call_bitcode_fn(