mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 00:09:33 +03:00
Add intrinsics for sqrt and round
This commit is contained in:
parent
0191910715
commit
b43e582c7a
@ -323,6 +323,12 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||
SolvedType::Func(vec![float_type()], Box::new(float_type())),
|
||||
);
|
||||
|
||||
// round : Float -> Int
|
||||
add_type(
|
||||
Symbol::FLOAT_ROUND,
|
||||
SolvedType::Func(vec![float_type()], Box::new(int_type())),
|
||||
);
|
||||
|
||||
// highest : Float
|
||||
add_type(Symbol::FLOAT_HIGHEST, float_type());
|
||||
|
||||
|
@ -386,6 +386,12 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||
unique_function(vec![float_type(UVAR1)], float_type(UVAR2)),
|
||||
);
|
||||
|
||||
// round : Float -> Int
|
||||
add_type(
|
||||
Symbol::FLOAT_ROUND,
|
||||
unique_function(vec![float_type(UVAR1)], int_type(UVAR2)),
|
||||
);
|
||||
|
||||
// highest : Float
|
||||
add_type(Symbol::FLOAT_HIGHEST, float_type(UVAR1));
|
||||
|
||||
|
@ -5,7 +5,7 @@ use inkwell::context::Context;
|
||||
use inkwell::memory_buffer::MemoryBuffer;
|
||||
use inkwell::module::{Linkage, Module};
|
||||
use inkwell::passes::{PassManager, PassManagerBuilder};
|
||||
use inkwell::types::{BasicTypeEnum, IntType, StructType};
|
||||
use inkwell::types::{BasicTypeEnum, FunctionType, IntType, StructType};
|
||||
use inkwell::values::BasicValueEnum::{self, *};
|
||||
use inkwell::values::{FunctionValue, IntValue, PointerValue, StructValue};
|
||||
use inkwell::{FloatPredicate, IntPredicate, OptimizationLevel};
|
||||
@ -57,8 +57,48 @@ pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Modu
|
||||
let memory_buffer =
|
||||
MemoryBuffer::create_from_memory_range(include_bytes!("builtins.bc"), module_name);
|
||||
|
||||
Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
||||
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err))
|
||||
let module = Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
||||
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err));
|
||||
|
||||
// Add LLVM intrinsics.
|
||||
add_intrinsics(ctx, &module);
|
||||
|
||||
module
|
||||
}
|
||||
|
||||
fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
|
||||
// List of all supported LLVM intrinsics:
|
||||
//
|
||||
// https://releases.llvm.org/10.0.0/docs/LangRef.html#standard-c-library-intrinsics
|
||||
let i64_type = ctx.i64_type();
|
||||
let f64_type = ctx.f64_type();
|
||||
|
||||
add_intrinsic(
|
||||
module,
|
||||
LLVM_SQRT_F64,
|
||||
f64_type.fn_type(&[f64_type.into()], false),
|
||||
);
|
||||
|
||||
add_intrinsic(
|
||||
module,
|
||||
LLVM_LROUND_I64_F64,
|
||||
i64_type.fn_type(&[f64_type.into()], false),
|
||||
);
|
||||
}
|
||||
|
||||
static LLVM_SQRT_F64: &str = "llvm.sqrt.f64";
|
||||
static LLVM_LROUND_I64_F64: &str = "llvm.lround.i64.f64";
|
||||
|
||||
fn add_intrinsic<'ctx>(
|
||||
module: &Module<'ctx>,
|
||||
intrinsic_name: &'static str,
|
||||
fn_type: FunctionType<'ctx>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
let fn_val = module.add_function(intrinsic_name, fn_type, None);
|
||||
|
||||
fn_val.set_call_conventions(C_CALL_CONV);
|
||||
|
||||
fn_val
|
||||
}
|
||||
|
||||
pub fn add_passes(fpm: &PassManager<FunctionValue<'_>>, opt_level: OptLevel) {
|
||||
@ -1182,6 +1222,8 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||
}
|
||||
}
|
||||
}
|
||||
Symbol::FLOAT_SQRT => call_intrinsic(LLVM_SQRT_F64, env, args),
|
||||
Symbol::FLOAT_ROUND => call_intrinsic(LLVM_LROUND_I64_F64, env, args),
|
||||
Symbol::LIST_SET => list_set(parent, args, env, InPlace::Clone),
|
||||
Symbol::LIST_SET_IN_PLACE => list_set(parent, args, env, InPlace::InPlace),
|
||||
_ => {
|
||||
@ -1209,6 +1251,36 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||
}
|
||||
}
|
||||
|
||||
fn call_intrinsic<'a, 'ctx, 'env>(
|
||||
intrinsic_name: &'static str,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
args: &[(BasicValueEnum<'ctx>, &'a Layout<'a>)],
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let fn_val = env
|
||||
.module
|
||||
.get_function(intrinsic_name)
|
||||
.unwrap_or_else(|| panic!("Unrecognized intrinsic function: {}", intrinsic_name));
|
||||
|
||||
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(args.len(), env.arena);
|
||||
|
||||
for (arg, _layout) in args.iter() {
|
||||
arg_vals.push(*arg);
|
||||
}
|
||||
|
||||
let call = env
|
||||
.builder
|
||||
.build_call(fn_val, arg_vals.into_bump_slice(), "call");
|
||||
|
||||
call.set_call_convention(fn_val.get_call_conventions());
|
||||
|
||||
call.try_as_basic_value().left().unwrap_or_else(|| {
|
||||
panic!(
|
||||
"LLVM error: Invalid call by name for intrinsic {}",
|
||||
intrinsic_name
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn load_list_len<'ctx>(
|
||||
builder: &Builder<'ctx>,
|
||||
wrapper_struct: StructValue<'ctx>,
|
||||
|
@ -27,6 +27,16 @@ mod gen_builtins {
|
||||
use roc_mono::layout::Layout;
|
||||
use roc_types::subs::Subs;
|
||||
|
||||
#[test]
|
||||
fn f64_sqrt() {
|
||||
assert_evals_to!("Float.sqrt 144", 12.0, f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f64_round() {
|
||||
assert_evals_to!("Float.round 3.6", 4, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_list_literal() {
|
||||
assert_evals_to!("[]", &[], &'static [i64]);
|
||||
|
Loading…
Reference in New Issue
Block a user