mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge pull request #3407 from rtfeldman/dylib-roc-benchmarks
Dylib roc benchmarks
This commit is contained in:
commit
85d87ab431
11 changed files with 330 additions and 129 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -47,3 +47,8 @@ roc_linux_x86_64.tar.gz
|
||||||
|
|
||||||
# macOS .DS_Store files
|
# macOS .DS_Store files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# files geneated when formatting fails
|
||||||
|
*.roc-format-failed
|
||||||
|
*.roc-format-failed-ast-after
|
||||||
|
*.roc-format-failed-ast-before
|
||||||
|
|
60
Cargo.lock
generated
60
Cargo.lock
generated
|
@ -524,7 +524,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"const_format",
|
"const_format",
|
||||||
"criterion 0.3.5 (git+https://github.com/Anton-4/criterion.rs)",
|
"criterion",
|
||||||
"rlimit",
|
"rlimit",
|
||||||
"roc_cli",
|
"roc_cli",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
@ -916,32 +916,6 @@ dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "criterion"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
|
|
||||||
dependencies = [
|
|
||||||
"atty",
|
|
||||||
"cast",
|
|
||||||
"clap 2.34.0",
|
|
||||||
"criterion-plot 0.4.4",
|
|
||||||
"csv",
|
|
||||||
"itertools 0.10.3",
|
|
||||||
"lazy_static",
|
|
||||||
"num-traits",
|
|
||||||
"oorandom",
|
|
||||||
"plotters 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rayon",
|
|
||||||
"regex",
|
|
||||||
"serde",
|
|
||||||
"serde_cbor",
|
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
|
||||||
"tinytemplate",
|
|
||||||
"walkdir",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "criterion"
|
name = "criterion"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
@ -950,13 +924,13 @@ dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"cast",
|
"cast",
|
||||||
"clap 2.34.0",
|
"clap 2.34.0",
|
||||||
"criterion-plot 0.4.3",
|
"criterion-plot",
|
||||||
"csv",
|
"csv",
|
||||||
"itertools 0.10.3",
|
"itertools 0.10.3",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"oorandom",
|
"oorandom",
|
||||||
"plotters 0.3.1 (git+https://github.com/Anton-4/plotters)",
|
"plotters",
|
||||||
"rayon",
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -976,16 +950,6 @@ dependencies = [
|
||||||
"itertools 0.9.0",
|
"itertools 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "criterion-plot"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
|
|
||||||
dependencies = [
|
|
||||||
"cast",
|
|
||||||
"itertools 0.10.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam"
|
name = "crossbeam"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
@ -2893,19 +2857,6 @@ version = "0.3.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "plotters"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
"plotters-backend",
|
|
||||||
"plotters-svg",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"web-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plotters"
|
name = "plotters"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -3471,7 +3422,7 @@ dependencies = [
|
||||||
"clap 3.2.8",
|
"clap 3.2.8",
|
||||||
"cli_utils",
|
"cli_utils",
|
||||||
"const_format",
|
"const_format",
|
||||||
"criterion 0.3.5 (git+https://github.com/Anton-4/criterion.rs)",
|
"criterion",
|
||||||
"errno",
|
"errno",
|
||||||
"indoc",
|
"indoc",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -3877,7 +3828,7 @@ name = "roc_parse"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"criterion 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"criterion",
|
||||||
"encode_unicode",
|
"encode_unicode",
|
||||||
"indoc",
|
"indoc",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
@ -4762,6 +4713,7 @@ name = "test_gen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
|
"criterion",
|
||||||
"either",
|
"either",
|
||||||
"indoc",
|
"indoc",
|
||||||
"inkwell 0.1.0",
|
"inkwell 0.1.0",
|
||||||
|
|
|
@ -3525,15 +3525,31 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena);
|
let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
let it = args.iter().zip(roc_function.get_type().get_param_types());
|
let it = args
|
||||||
for (arg, fastcc_type) in it {
|
.iter()
|
||||||
|
.zip(roc_function.get_type().get_param_types())
|
||||||
|
.zip(arguments);
|
||||||
|
for ((arg, fastcc_type), layout) in it {
|
||||||
let arg_type = arg.get_type();
|
let arg_type = arg.get_type();
|
||||||
if arg_type == fastcc_type {
|
if arg_type == fastcc_type {
|
||||||
// the C and Fast calling conventions agree
|
// the C and Fast calling conventions agree
|
||||||
arguments_for_call.push(*arg);
|
arguments_for_call.push(*arg);
|
||||||
} else {
|
} else {
|
||||||
let cast = complex_bitcast_check_size(env, *arg, fastcc_type, "to_fastcc_type");
|
match layout {
|
||||||
arguments_for_call.push(cast);
|
Layout::Builtin(Builtin::List(_)) => {
|
||||||
|
let loaded = env
|
||||||
|
.builder
|
||||||
|
.build_load(arg.into_pointer_value(), "load_list_pointer");
|
||||||
|
let cast =
|
||||||
|
complex_bitcast_check_size(env, loaded, fastcc_type, "to_fastcc_type_1");
|
||||||
|
arguments_for_call.push(cast);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let cast =
|
||||||
|
complex_bitcast_check_size(env, *arg, fastcc_type, "to_fastcc_type_1");
|
||||||
|
arguments_for_call.push(cast);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3657,7 +3673,7 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
|
||||||
// the C and Fast calling conventions agree
|
// the C and Fast calling conventions agree
|
||||||
*arg
|
*arg
|
||||||
} else {
|
} else {
|
||||||
complex_bitcast_check_size(env, *arg, *fastcc_type, "to_fastcc_type")
|
complex_bitcast_check_size(env, *arg, *fastcc_type, "to_fastcc_type_2")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,26 @@ pub struct RocCallResult<T> {
|
||||||
value: MaybeUninit<T>,
|
value: MaybeUninit<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> RocCallResult<T> {
|
||||||
|
pub fn new(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
tag: 0,
|
||||||
|
error_msg: std::ptr::null_mut(),
|
||||||
|
value: MaybeUninit::new(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default> Default for RocCallResult<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
tag: 0,
|
||||||
|
error_msg: std::ptr::null_mut(),
|
||||||
|
value: MaybeUninit::new(Default::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
||||||
fn from(call_result: RocCallResult<T>) -> Self {
|
fn from(call_result: RocCallResult<T>) -> Self {
|
||||||
match call_result.tag {
|
match call_result.tag {
|
||||||
|
@ -30,6 +50,29 @@ impl<T: Sized> From<RocCallResult<T>> for Result<T, String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! run_roc_dylib {
|
||||||
|
($lib:expr, $main_fn_name:expr, $argument_type:ty, $return_type:ty, $errors:expr) => {{
|
||||||
|
use inkwell::context::Context;
|
||||||
|
use roc_builtins::bitcode;
|
||||||
|
use roc_gen_llvm::run_roc::RocCallResult;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
|
// NOTE: return value is not first argument currently (may/should change in the future)
|
||||||
|
type Main = unsafe extern "C" fn($argument_type, *mut RocCallResult<$return_type>);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let main: libloading::Symbol<Main> = $lib
|
||||||
|
.get($main_fn_name.as_bytes())
|
||||||
|
.ok()
|
||||||
|
.ok_or(format!("Unable to JIT compile `{}`", $main_fn_name))
|
||||||
|
.expect("errored");
|
||||||
|
|
||||||
|
main
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! run_jit_function {
|
macro_rules! run_jit_function {
|
||||||
($lib: expr, $main_fn_name: expr, $ty:ty, $transform:expr) => {{
|
($lib: expr, $main_fn_name: expr, $ty:ty, $transform:expr) => {{
|
||||||
|
|
|
@ -16,7 +16,7 @@ bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||||
encode_unicode = "0.3.6"
|
encode_unicode = "0.3.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = { version = "0.3.5", features = ["html_reports"] }
|
criterion = { git = "https://github.com/Anton-4/criterion.rs", features = ["html_reports"]}
|
||||||
pretty_assertions = "1.0.0"
|
pretty_assertions = "1.0.0"
|
||||||
indoc = "1.0.3"
|
indoc = "1.0.3"
|
||||||
quickcheck = "1.0.3"
|
quickcheck = "1.0.3"
|
||||||
|
|
|
@ -43,6 +43,7 @@ libloading = "0.7.1"
|
||||||
wasmer-wasi = "2.2.1"
|
wasmer-wasi = "2.2.1"
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
indoc = "1.0.3"
|
indoc = "1.0.3"
|
||||||
|
criterion = { git = "https://github.com/Anton-4/criterion.rs" }
|
||||||
|
|
||||||
# Wasmer singlepass compiler only works on x86_64.
|
# Wasmer singlepass compiler only works on x86_64.
|
||||||
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
|
||||||
|
@ -57,3 +58,7 @@ gen-llvm = []
|
||||||
gen-dev = []
|
gen-dev = []
|
||||||
gen-wasm = []
|
gen-wasm = []
|
||||||
wasm-cli-run = []
|
wasm-cli-run = []
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "list_map"
|
||||||
|
harness = false
|
||||||
|
|
119
crates/compiler/test_gen/benches/list_map.rs
Normal file
119
crates/compiler/test_gen/benches/list_map.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#[path = "../src/helpers/mod.rs"]
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
// defines roc_alloc and friends
|
||||||
|
pub use helpers::platform_functions::*;
|
||||||
|
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
use roc_gen_llvm::{run_roc::RocCallResult, run_roc_dylib};
|
||||||
|
use roc_mono::ir::OptLevel;
|
||||||
|
use roc_std::RocList;
|
||||||
|
|
||||||
|
// results July 6th, 2022
|
||||||
|
//
|
||||||
|
// roc sum map time: [612.73 ns 614.24 ns 615.98 ns]
|
||||||
|
// roc sum map_with_index time: [5.3177 us 5.3218 us 5.3255 us]
|
||||||
|
// rust (debug) time: [24.081 us 24.163 us 24.268 us]
|
||||||
|
|
||||||
|
type Input = RocList<i64>;
|
||||||
|
type Output = i64;
|
||||||
|
|
||||||
|
type Main<I, O> = unsafe extern "C" fn(I, *mut RocCallResult<O>);
|
||||||
|
|
||||||
|
const ROC_LIST_MAP: &str = indoc::indoc!(
|
||||||
|
r#"
|
||||||
|
app "bench" provides [main] to "./platform"
|
||||||
|
|
||||||
|
main : List I64 -> Nat
|
||||||
|
main = \list ->
|
||||||
|
list
|
||||||
|
|> List.map (\x -> x + 2)
|
||||||
|
|> List.len
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
const ROC_LIST_MAP_WITH_INDEX: &str = indoc::indoc!(
|
||||||
|
r#"
|
||||||
|
app "bench" provides [main] to "./platform"
|
||||||
|
|
||||||
|
main : List I64 -> Nat
|
||||||
|
main = \list ->
|
||||||
|
list
|
||||||
|
|> List.mapWithIndex (\x, _ -> x + 2)
|
||||||
|
|> List.len
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
fn roc_function<'a, 'b>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
source: &str,
|
||||||
|
) -> libloading::Symbol<'a, Main<&'b Input, Output>> {
|
||||||
|
let config = helpers::llvm::HelperConfig {
|
||||||
|
is_gen_test: true,
|
||||||
|
ignore_problems: false,
|
||||||
|
add_debug_info: true,
|
||||||
|
opt_level: OptLevel::Optimize,
|
||||||
|
};
|
||||||
|
|
||||||
|
let context = inkwell::context::Context::create();
|
||||||
|
let (main_fn_name, errors, lib) =
|
||||||
|
helpers::llvm::helper(arena, config, source, arena.alloc(context));
|
||||||
|
|
||||||
|
assert!(errors.is_empty(), "Encountered errors:\n{}", errors);
|
||||||
|
|
||||||
|
run_roc_dylib!(arena.alloc(lib), main_fn_name, &Input, Output, errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rust_main(argument: &RocList<i64>, output: &mut RocCallResult<i64>) {
|
||||||
|
let mut answer = 0;
|
||||||
|
|
||||||
|
for x in argument.iter() {
|
||||||
|
answer += x;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = RocCallResult::new(answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_input_list() -> RocList<i64> {
|
||||||
|
let numbers = Vec::from_iter(0..1_000);
|
||||||
|
|
||||||
|
RocList::from_slice(&numbers)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||||
|
let arena = Bump::new();
|
||||||
|
|
||||||
|
let list_map_with_index_main = roc_function(&arena, ROC_LIST_MAP_WITH_INDEX);
|
||||||
|
let list_map_main = roc_function(&arena, ROC_LIST_MAP);
|
||||||
|
|
||||||
|
let input = &*arena.alloc(create_input_list());
|
||||||
|
|
||||||
|
c.bench_function("roc sum map", |b| {
|
||||||
|
b.iter(|| unsafe {
|
||||||
|
let mut main_result = RocCallResult::default();
|
||||||
|
|
||||||
|
list_map_main(black_box(input), &mut main_result);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
c.bench_function("roc sum map_with_index", |b| {
|
||||||
|
b.iter(|| unsafe {
|
||||||
|
let mut main_result = RocCallResult::default();
|
||||||
|
|
||||||
|
list_map_with_index_main(black_box(input), &mut main_result);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let input = &*arena.alloc(create_input_list());
|
||||||
|
c.bench_function("rust", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let mut main_result = RocCallResult::default();
|
||||||
|
|
||||||
|
rust_main(black_box(input), &mut main_result);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, criterion_benchmark);
|
||||||
|
criterion_main!(benches);
|
|
@ -246,39 +246,84 @@ fn create_llvm_module<'a>(
|
||||||
(main_fn_name, delayed_errors.join("\n"), env.module)
|
(main_fn_name, delayed_errors.join("\n"), env.module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct HelperConfig {
|
||||||
|
pub is_gen_test: bool,
|
||||||
|
pub ignore_problems: bool,
|
||||||
|
pub add_debug_info: bool,
|
||||||
|
pub opt_level: OptLevel,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn helper<'a>(
|
pub fn helper<'a>(
|
||||||
arena: &'a bumpalo::Bump,
|
arena: &'a bumpalo::Bump,
|
||||||
|
config: HelperConfig,
|
||||||
src: &str,
|
src: &str,
|
||||||
is_gen_test: bool,
|
|
||||||
ignore_problems: bool,
|
|
||||||
context: &'a inkwell::context::Context,
|
context: &'a inkwell::context::Context,
|
||||||
) -> (&'static str, String, Library) {
|
) -> (&'static str, String, Library) {
|
||||||
let target = target_lexicon::Triple::host();
|
let target = target_lexicon::Triple::host();
|
||||||
|
|
||||||
let opt_level = if cfg!(debug_assertions) {
|
|
||||||
OptLevel::Normal
|
|
||||||
} else {
|
|
||||||
OptLevel::Optimize
|
|
||||||
};
|
|
||||||
|
|
||||||
let (main_fn_name, delayed_errors, module) = create_llvm_module(
|
let (main_fn_name, delayed_errors, module) = create_llvm_module(
|
||||||
arena,
|
arena,
|
||||||
src,
|
src,
|
||||||
is_gen_test,
|
config.is_gen_test,
|
||||||
ignore_problems,
|
config.ignore_problems,
|
||||||
context,
|
context,
|
||||||
&target,
|
&target,
|
||||||
opt_level,
|
config.opt_level,
|
||||||
);
|
);
|
||||||
|
|
||||||
let lib = llvm_module_to_dylib(module, &target, opt_level)
|
let res_lib = if config.add_debug_info {
|
||||||
.expect("Error loading compiled dylib for test");
|
let module = annotate_with_debug_info(module, context);
|
||||||
|
llvm_module_to_dylib(&module, &target, config.opt_level)
|
||||||
|
} else {
|
||||||
|
llvm_module_to_dylib(module, &target, config.opt_level)
|
||||||
|
};
|
||||||
|
|
||||||
|
let lib = res_lib.expect("Error loading compiled dylib for test");
|
||||||
|
|
||||||
(main_fn_name, delayed_errors, lib)
|
(main_fn_name, delayed_errors, lib)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn annotate_with_debug_info<'ctx>(
|
||||||
|
module: &Module<'ctx>,
|
||||||
|
context: &'ctx inkwell::context::Context,
|
||||||
|
) -> Module<'ctx> {
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
let app_ll_file = "/tmp/roc-debugir.ll";
|
||||||
|
let app_dbg_ll_file = "/tmp/roc-debugir.dbg.ll";
|
||||||
|
let app_bc_file = "/tmp/roc-debugir.bc";
|
||||||
|
|
||||||
|
// write the ll code to a file, so we can modify it
|
||||||
|
module.print_to_file(&app_ll_file).unwrap();
|
||||||
|
|
||||||
|
// run the debugir https://github.com/vaivaswatha/debugir tool
|
||||||
|
match Command::new("debugir")
|
||||||
|
.args(&["-instnamer", app_ll_file])
|
||||||
|
.output()
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(error) => {
|
||||||
|
use std::io::ErrorKind;
|
||||||
|
match error.kind() {
|
||||||
|
ErrorKind::NotFound => panic!(
|
||||||
|
r"I could not find the `debugir` tool on the PATH, install it from https://github.com/vaivaswatha/debugir"
|
||||||
|
),
|
||||||
|
_ => panic!("{:?}", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::new("llvm-as")
|
||||||
|
.args(&[app_dbg_ll_file, "-o", app_bc_file])
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
inkwell::module::Module::parse_bitcode_from_path(&app_bc_file, context).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn wasm32_target_tripple() -> Triple {
|
fn wasm32_target_tripple() -> Triple {
|
||||||
use target_lexicon::{Architecture, BinaryFormat};
|
use target_lexicon::{Architecture, BinaryFormat};
|
||||||
|
|
||||||
|
@ -513,13 +558,26 @@ macro_rules! assert_llvm_evals_to {
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use roc_gen_llvm::run_jit_function;
|
use roc_gen_llvm::run_jit_function;
|
||||||
|
use roc_mono::ir::OptLevel;
|
||||||
|
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
|
|
||||||
let is_gen_test = true;
|
let opt_level = if cfg!(debug_assertions) {
|
||||||
|
OptLevel::Normal
|
||||||
|
} else {
|
||||||
|
OptLevel::Optimize
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = $crate::helpers::llvm::HelperConfig {
|
||||||
|
is_gen_test: true,
|
||||||
|
add_debug_info: false,
|
||||||
|
ignore_problems: $ignore_problems,
|
||||||
|
opt_level,
|
||||||
|
};
|
||||||
|
|
||||||
let (main_fn_name, errors, lib) =
|
let (main_fn_name, errors, lib) =
|
||||||
$crate::helpers::llvm::helper(&arena, $src, is_gen_test, $ignore_problems, &context);
|
$crate::helpers::llvm::helper(&arena, config, $src, &context);
|
||||||
|
|
||||||
let transform = |success| {
|
let transform = |success| {
|
||||||
let expected = $expected;
|
let expected = $expected;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
extern crate bumpalo;
|
extern crate bumpalo;
|
||||||
|
|
||||||
|
pub mod platform_functions;
|
||||||
|
|
||||||
#[cfg(feature = "gen-dev")]
|
#[cfg(feature = "gen-dev")]
|
||||||
pub mod dev;
|
pub mod dev;
|
||||||
pub mod from_wasmer_memory;
|
pub mod from_wasmer_memory;
|
||||||
|
|
54
crates/compiler/test_gen/src/helpers/platform_functions.rs
Normal file
54
crates/compiler/test_gen/src/helpers/platform_functions.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
use core::ffi::c_void;
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The Roc application needs this.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
||||||
|
libc::malloc(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The Roc application needs this.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_memcpy(dest: *mut c_void, src: *const c_void, bytes: usize) -> *mut c_void {
|
||||||
|
libc::memcpy(dest, src, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The Roc application needs this.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_realloc(
|
||||||
|
c_ptr: *mut c_void,
|
||||||
|
new_size: usize,
|
||||||
|
_old_size: usize,
|
||||||
|
_alignment: u32,
|
||||||
|
) -> *mut c_void {
|
||||||
|
libc::realloc(c_ptr, new_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The Roc application needs this.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
||||||
|
libc::free(c_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The Roc application needs this.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
|
use roc_gen_llvm::llvm::build::PanicTagId;
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
match PanicTagId::try_from(tag_id) {
|
||||||
|
Ok(PanicTagId::NullTerminatedString) => {
|
||||||
|
let slice = CStr::from_ptr(c_ptr as *const c_char);
|
||||||
|
let string = slice.to_str().unwrap();
|
||||||
|
eprintln!("Roc hit a panic: {}", string);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,57 +22,4 @@ pub mod wasm_str;
|
||||||
#[cfg(feature = "gen-wasm")]
|
#[cfg(feature = "gen-wasm")]
|
||||||
pub mod wasm_linking;
|
pub mod wasm_linking;
|
||||||
|
|
||||||
use core::ffi::c_void;
|
pub use helpers::platform_functions::*;
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// The Roc application needs this.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
|
||||||
libc::malloc(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// The Roc application needs this.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn roc_memcpy(dest: *mut c_void, src: *const c_void, bytes: usize) -> *mut c_void {
|
|
||||||
libc::memcpy(dest, src, bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// The Roc application needs this.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn roc_realloc(
|
|
||||||
c_ptr: *mut c_void,
|
|
||||||
new_size: usize,
|
|
||||||
_old_size: usize,
|
|
||||||
_alignment: u32,
|
|
||||||
) -> *mut c_void {
|
|
||||||
libc::realloc(c_ptr, new_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// The Roc application needs this.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
|
||||||
libc::free(c_ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// The Roc application needs this.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
|
||||||
use roc_gen_llvm::llvm::build::PanicTagId;
|
|
||||||
|
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
|
|
||||||
match PanicTagId::try_from(tag_id) {
|
|
||||||
Ok(PanicTagId::NullTerminatedString) => {
|
|
||||||
let slice = CStr::from_ptr(c_ptr as *const c_char);
|
|
||||||
let string = slice.to_str().unwrap();
|
|
||||||
eprintln!("Roc hit a panic: {}", string);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue