mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Merge branch 'trunk' into integrate-linker
This commit is contained in:
commit
8a30b4803a
18 changed files with 352 additions and 88 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -3402,7 +3402,9 @@ dependencies = [
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_constrain",
|
"roc_constrain",
|
||||||
|
"roc_gen_dev",
|
||||||
"roc_gen_llvm",
|
"roc_gen_llvm",
|
||||||
|
"roc_gen_wasm",
|
||||||
"roc_load",
|
"roc_load",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
|
|
|
@ -62,10 +62,7 @@ pub fn build_file<'a>(
|
||||||
let subs_by_module = MutMap::default();
|
let subs_by_module = MutMap::default();
|
||||||
|
|
||||||
// Release builds use uniqueness optimizations
|
// Release builds use uniqueness optimizations
|
||||||
let stdlib = match opt_level {
|
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
|
||||||
OptLevel::Normal => arena.alloc(roc_builtins::std::standard_stdlib()),
|
|
||||||
OptLevel::Optimize => arena.alloc(roc_builtins::std::standard_stdlib()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let loaded = roc_load::file::load_and_monomorphize(
|
let loaded = roc_load::file::load_and_monomorphize(
|
||||||
arena,
|
arena,
|
||||||
|
@ -78,16 +75,7 @@ pub fn build_file<'a>(
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
use target_lexicon::Architecture;
|
use target_lexicon::Architecture;
|
||||||
let emit_wasm = match target.architecture {
|
let emit_wasm = matches!(target.architecture, Architecture::Wasm32);
|
||||||
Architecture::X86_64 => false,
|
|
||||||
Architecture::Aarch64(_) => false,
|
|
||||||
Architecture::Wasm32 => true,
|
|
||||||
Architecture::X86_32(_) => false,
|
|
||||||
_ => panic!(
|
|
||||||
"TODO gracefully handle unsupported architecture: {:?}",
|
|
||||||
target.architecture
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO wasm host extension should be something else ideally
|
// TODO wasm host extension should be something else ideally
|
||||||
// .bc does not seem to work because
|
// .bc does not seem to work because
|
||||||
|
@ -180,15 +168,21 @@ pub fn build_file<'a>(
|
||||||
let loaded = loaded;
|
let loaded = loaded;
|
||||||
|
|
||||||
let binary_path = cwd.join(&*loaded.output_path); // TODO should join ".exe" on Windows
|
let binary_path = cwd.join(&*loaded.output_path); // TODO should join ".exe" on Windows
|
||||||
let code_gen_timing = program::gen_from_mono_module(
|
|
||||||
arena,
|
let code_gen_timing = match opt_level {
|
||||||
loaded,
|
OptLevel::Normal | OptLevel::Optimize => program::gen_from_mono_module_llvm(
|
||||||
&roc_file_path,
|
arena,
|
||||||
target,
|
loaded,
|
||||||
app_o_file,
|
&roc_file_path,
|
||||||
opt_level,
|
target,
|
||||||
emit_debug_info,
|
app_o_file,
|
||||||
);
|
opt_level,
|
||||||
|
emit_debug_info,
|
||||||
|
),
|
||||||
|
OptLevel::Development => {
|
||||||
|
program::gen_from_mono_module_dev(arena, loaded, target, app_o_file)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
buf.push_str(" ");
|
buf.push_str(" ");
|
||||||
|
|
|
@ -28,6 +28,7 @@ pub const CMD_EDIT: &str = "edit";
|
||||||
pub const CMD_DOCS: &str = "docs";
|
pub const CMD_DOCS: &str = "docs";
|
||||||
|
|
||||||
pub const FLAG_DEBUG: &str = "debug";
|
pub const FLAG_DEBUG: &str = "debug";
|
||||||
|
pub const FLAG_DEV: &str = "dev";
|
||||||
pub const FLAG_OPTIMIZE: &str = "optimize";
|
pub const FLAG_OPTIMIZE: &str = "optimize";
|
||||||
pub const FLAG_LIB: &str = "lib";
|
pub const FLAG_LIB: &str = "lib";
|
||||||
pub const FLAG_BACKEND: &str = "backend";
|
pub const FLAG_BACKEND: &str = "backend";
|
||||||
|
@ -55,6 +56,12 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.help("Optimize your compiled Roc program to run faster. (Optimization takes time to complete.)")
|
.help("Optimize your compiled Roc program to run faster. (Optimization takes time to complete.)")
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_DEV)
|
||||||
|
.long(FLAG_DEV)
|
||||||
|
.help("Make compilation as fast as possible. (Runtime performance may suffer)")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(FLAG_BACKEND)
|
Arg::with_name(FLAG_BACKEND)
|
||||||
.long(FLAG_BACKEND)
|
.long(FLAG_BACKEND)
|
||||||
|
@ -98,6 +105,12 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_DEV)
|
||||||
|
.long(FLAG_DEV)
|
||||||
|
.help("Make compilation as fast as possible. (Runtime performance may suffer)")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(FLAG_DEBUG)
|
Arg::with_name(FLAG_DEBUG)
|
||||||
.long(FLAG_DEBUG)
|
.long(FLAG_DEBUG)
|
||||||
|
@ -137,6 +150,12 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.requires(ROC_FILE)
|
.requires(ROC_FILE)
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_DEV)
|
||||||
|
.long(FLAG_DEV)
|
||||||
|
.help("Make compilation as fast as possible. (Runtime performance may suffer)")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(FLAG_DEBUG)
|
Arg::with_name(FLAG_DEBUG)
|
||||||
.long(FLAG_DEBUG)
|
.long(FLAG_DEBUG)
|
||||||
|
@ -223,10 +242,14 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result<i32> {
|
||||||
let filename = matches.value_of(ROC_FILE).unwrap();
|
let filename = matches.value_of(ROC_FILE).unwrap();
|
||||||
|
|
||||||
let original_cwd = std::env::current_dir()?;
|
let original_cwd = std::env::current_dir()?;
|
||||||
let opt_level = if matches.is_present(FLAG_OPTIMIZE) {
|
let opt_level = match (
|
||||||
OptLevel::Optimize
|
matches.is_present(FLAG_OPTIMIZE),
|
||||||
} else {
|
matches.is_present(FLAG_DEV),
|
||||||
OptLevel::Normal
|
) {
|
||||||
|
(true, false) => OptLevel::Optimize,
|
||||||
|
(true, true) => panic!("development cannot be optimized!"),
|
||||||
|
(false, true) => OptLevel::Development,
|
||||||
|
(false, false) => OptLevel::Normal,
|
||||||
};
|
};
|
||||||
let emit_debug_info = matches.is_present(FLAG_DEBUG);
|
let emit_debug_info = matches.is_present(FLAG_DEBUG);
|
||||||
let emit_timings = matches.is_present(FLAG_TIME);
|
let emit_timings = matches.is_present(FLAG_TIME);
|
||||||
|
@ -429,9 +452,7 @@ enum Backend {
|
||||||
Host,
|
Host,
|
||||||
X86_32,
|
X86_32,
|
||||||
X86_64,
|
X86_64,
|
||||||
Dev,
|
|
||||||
Wasm32,
|
Wasm32,
|
||||||
Wasm32Dev,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Backend {
|
impl Default for Backend {
|
||||||
|
@ -446,9 +467,7 @@ impl Backend {
|
||||||
Backend::Host => "host",
|
Backend::Host => "host",
|
||||||
Backend::X86_32 => "x86_32",
|
Backend::X86_32 => "x86_32",
|
||||||
Backend::X86_64 => "x86_64",
|
Backend::X86_64 => "x86_64",
|
||||||
Backend::Dev => "dev",
|
|
||||||
Backend::Wasm32 => "wasm32",
|
Backend::Wasm32 => "wasm32",
|
||||||
Backend::Wasm32Dev => "wasm32_dev",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,9 +476,7 @@ impl Backend {
|
||||||
Backend::Host.as_str(),
|
Backend::Host.as_str(),
|
||||||
Backend::X86_32.as_str(),
|
Backend::X86_32.as_str(),
|
||||||
Backend::X86_64.as_str(),
|
Backend::X86_64.as_str(),
|
||||||
Backend::Dev.as_str(),
|
|
||||||
Backend::Wasm32.as_str(),
|
Backend::Wasm32.as_str(),
|
||||||
Backend::Wasm32Dev.as_str(),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
fn to_triple(&self) -> Triple {
|
fn to_triple(&self) -> Triple {
|
||||||
|
@ -482,8 +499,7 @@ impl Backend {
|
||||||
|
|
||||||
triple
|
triple
|
||||||
}
|
}
|
||||||
Backend::Dev => todo!(),
|
Backend::Wasm32 => {
|
||||||
Backend::Wasm32 | Backend::Wasm32Dev => {
|
|
||||||
triple.architecture = Architecture::Wasm32;
|
triple.architecture = Architecture::Wasm32;
|
||||||
triple.binary_format = BinaryFormat::Wasm;
|
triple.binary_format = BinaryFormat::Wasm;
|
||||||
|
|
||||||
|
@ -507,9 +523,7 @@ impl std::str::FromStr for Backend {
|
||||||
"host" => Ok(Backend::Host),
|
"host" => Ok(Backend::Host),
|
||||||
"x86_32" => Ok(Backend::X86_32),
|
"x86_32" => Ok(Backend::X86_32),
|
||||||
"x86_64" => Ok(Backend::X86_64),
|
"x86_64" => Ok(Backend::X86_64),
|
||||||
"dev" => Ok(Backend::Dev),
|
|
||||||
"wasm32" => Ok(Backend::Wasm32),
|
"wasm32" => Ok(Backend::Wasm32),
|
||||||
"wasm32_dev" => Ok(Backend::Wasm32Dev),
|
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,16 @@ mod cli_run {
|
||||||
let example = $example;
|
let example = $example;
|
||||||
let file_name = example_file(dir_name, example.filename);
|
let file_name = example_file(dir_name, example.filename);
|
||||||
|
|
||||||
|
match example.filename {
|
||||||
|
"Fib.roc" => {
|
||||||
|
// it is broken because the dev and normal backend don't generate the
|
||||||
|
// same name for main. The dev version is expected here.
|
||||||
|
eprintln!("WARNING: skipping testing example {} because the test is broken right now!", example.filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
// Check with and without optimizations
|
// Check with and without optimizations
|
||||||
check_output_with_stdin(
|
check_output_with_stdin(
|
||||||
&file_name,
|
&file_name,
|
||||||
|
@ -224,6 +234,13 @@ mod cli_run {
|
||||||
expected_ending:"Hello, World!\n",
|
expected_ending:"Hello, World!\n",
|
||||||
use_valgrind: true,
|
use_valgrind: true,
|
||||||
},
|
},
|
||||||
|
fib:"fib" => Example {
|
||||||
|
filename: "Fib.roc",
|
||||||
|
executable_filename: "fib",
|
||||||
|
stdin: &[],
|
||||||
|
expected_ending:"55\n",
|
||||||
|
use_valgrind: true,
|
||||||
|
},
|
||||||
quicksort:"quicksort" => Example {
|
quicksort:"quicksort" => Example {
|
||||||
filename: "Quicksort.roc",
|
filename: "Quicksort.roc",
|
||||||
executable_filename: "quicksort",
|
executable_filename: "quicksort",
|
||||||
|
|
|
@ -20,6 +20,8 @@ roc_solve = { path = "../solve" }
|
||||||
roc_mono = { path = "../mono" }
|
roc_mono = { path = "../mono" }
|
||||||
roc_load = { path = "../load" }
|
roc_load = { path = "../load" }
|
||||||
roc_gen_llvm = { path = "../gen_llvm", optional = true }
|
roc_gen_llvm = { path = "../gen_llvm", optional = true }
|
||||||
|
roc_gen_wasm = { path = "../gen_wasm" }
|
||||||
|
roc_gen_dev = { path = "../gen_dev" }
|
||||||
roc_reporting = { path = "../reporting" }
|
roc_reporting = { path = "../reporting" }
|
||||||
roc_std = { path = "../../roc_std" }
|
roc_std = { path = "../../roc_std" }
|
||||||
im = "14" # im and im-rc should always have the same version!
|
im = "14" # im and im-rc should always have the same version!
|
||||||
|
|
|
@ -10,6 +10,8 @@ use roc_mono::ir::OptLevel;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct CodeGenTiming {
|
pub struct CodeGenTiming {
|
||||||
pub code_gen: Duration,
|
pub code_gen: Duration,
|
||||||
|
@ -142,7 +144,7 @@ pub fn report_problems(loaded: &mut MonomorphizedModule) -> usize {
|
||||||
// TODO this should probably use more helper functions
|
// TODO this should probably use more helper functions
|
||||||
// TODO make this polymorphic in the llvm functions so it can be reused for another backend.
|
// TODO make this polymorphic in the llvm functions so it can be reused for another backend.
|
||||||
#[cfg(feature = "llvm")]
|
#[cfg(feature = "llvm")]
|
||||||
pub fn gen_from_mono_module(
|
pub fn gen_from_mono_module_llvm(
|
||||||
arena: &bumpalo::Bump,
|
arena: &bumpalo::Bump,
|
||||||
loaded: MonomorphizedModule,
|
loaded: MonomorphizedModule,
|
||||||
roc_file_path: &Path,
|
roc_file_path: &Path,
|
||||||
|
@ -371,3 +373,78 @@ pub fn gen_from_mono_module(
|
||||||
emit_o_file,
|
emit_o_file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn gen_from_mono_module_dev(
|
||||||
|
arena: &bumpalo::Bump,
|
||||||
|
loaded: MonomorphizedModule,
|
||||||
|
target: &target_lexicon::Triple,
|
||||||
|
app_o_file: &Path,
|
||||||
|
) -> CodeGenTiming {
|
||||||
|
use target_lexicon::Architecture;
|
||||||
|
|
||||||
|
match target.architecture {
|
||||||
|
Architecture::Wasm32 => gen_from_mono_module_dev_wasm32(arena, loaded, app_o_file),
|
||||||
|
Architecture::X86_64 => {
|
||||||
|
gen_from_mono_module_dev_assembly(arena, loaded, target, app_o_file)
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_from_mono_module_dev_wasm32(
|
||||||
|
arena: &bumpalo::Bump,
|
||||||
|
loaded: MonomorphizedModule,
|
||||||
|
app_o_file: &Path,
|
||||||
|
) -> CodeGenTiming {
|
||||||
|
let mut procedures = MutMap::default();
|
||||||
|
|
||||||
|
for (key, proc) in loaded.procedures {
|
||||||
|
procedures.insert(key, proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
let exposed_to_host = loaded
|
||||||
|
.exposed_to_host
|
||||||
|
.keys()
|
||||||
|
.copied()
|
||||||
|
.collect::<MutSet<_>>();
|
||||||
|
|
||||||
|
let env = roc_gen_wasm::Env {
|
||||||
|
arena,
|
||||||
|
interns: loaded.interns,
|
||||||
|
exposed_to_host,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytes = roc_gen_wasm::build_module(&env, procedures).unwrap();
|
||||||
|
|
||||||
|
std::fs::write(&app_o_file, &bytes).expect("failed to write object to file");
|
||||||
|
|
||||||
|
CodeGenTiming::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_from_mono_module_dev_assembly(
|
||||||
|
arena: &bumpalo::Bump,
|
||||||
|
loaded: MonomorphizedModule,
|
||||||
|
target: &target_lexicon::Triple,
|
||||||
|
app_o_file: &Path,
|
||||||
|
) -> CodeGenTiming {
|
||||||
|
let lazy_literals = true;
|
||||||
|
let generate_allocators = false; // provided by the platform
|
||||||
|
|
||||||
|
let env = roc_gen_dev::Env {
|
||||||
|
arena,
|
||||||
|
interns: loaded.interns,
|
||||||
|
exposed_to_host: loaded.exposed_to_host.keys().copied().collect(),
|
||||||
|
lazy_literals,
|
||||||
|
generate_allocators,
|
||||||
|
};
|
||||||
|
|
||||||
|
let module_object = roc_gen_dev::build_module(&env, target, loaded.procedures)
|
||||||
|
.expect("failed to compile module");
|
||||||
|
|
||||||
|
let module_out = module_object
|
||||||
|
.write()
|
||||||
|
.expect("failed to build output object");
|
||||||
|
std::fs::write(&app_o_file, module_out).expect("failed to write object to file");
|
||||||
|
|
||||||
|
CodeGenTiming::default()
|
||||||
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ pub fn target_machine(
|
||||||
#[cfg(feature = "llvm")]
|
#[cfg(feature = "llvm")]
|
||||||
pub fn convert_opt_level(level: OptLevel) -> OptimizationLevel {
|
pub fn convert_opt_level(level: OptLevel) -> OptimizationLevel {
|
||||||
match level {
|
match level {
|
||||||
OptLevel::Normal => OptimizationLevel::None,
|
OptLevel::Development | OptLevel::Normal => OptimizationLevel::None,
|
||||||
OptLevel::Optimize => OptimizationLevel::Aggressive,
|
OptLevel::Optimize => OptimizationLevel::Aggressive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,10 +191,16 @@ fn build_object<'a, B: Backend<'a>>(
|
||||||
let mut layout_ids = roc_mono::layout::LayoutIds::default();
|
let mut layout_ids = roc_mono::layout::LayoutIds::default();
|
||||||
let mut procs = Vec::with_capacity_in(procedures.len(), env.arena);
|
let mut procs = Vec::with_capacity_in(procedures.len(), env.arena);
|
||||||
for ((sym, layout), proc) in procedures {
|
for ((sym, layout), proc) in procedures {
|
||||||
let fn_name = layout_ids
|
let base_name = layout_ids
|
||||||
.get_toplevel(sym, &layout)
|
.get_toplevel(sym, &layout)
|
||||||
.to_symbol_string(sym, &env.interns);
|
.to_symbol_string(sym, &env.interns);
|
||||||
|
|
||||||
|
let fn_name = if env.exposed_to_host.contains(&sym) {
|
||||||
|
format!("roc_{}_exposed", base_name)
|
||||||
|
} else {
|
||||||
|
base_name
|
||||||
|
};
|
||||||
|
|
||||||
let section_id = output.add_section(
|
let section_id = output.add_section(
|
||||||
output.segment_name(StandardSegment::Text).to_vec(),
|
output.segment_name(StandardSegment::Text).to_vec(),
|
||||||
format!(".text.{:x}", sym.as_u64()).as_bytes().to_vec(),
|
format!(".text.{:x}", sym.as_u64()).as_bytes().to_vec(),
|
||||||
|
|
|
@ -94,10 +94,12 @@ pub fn helper<'a>(
|
||||||
let main_fn_layout = loaded.entry_point.layout;
|
let main_fn_layout = loaded.entry_point.layout;
|
||||||
|
|
||||||
let mut layout_ids = roc_mono::layout::LayoutIds::default();
|
let mut layout_ids = roc_mono::layout::LayoutIds::default();
|
||||||
let main_fn_name = layout_ids
|
let main_fn_name_base = layout_ids
|
||||||
.get_toplevel(main_fn_symbol, &main_fn_layout)
|
.get_toplevel(main_fn_symbol, &main_fn_layout)
|
||||||
.to_symbol_string(main_fn_symbol, &interns);
|
.to_symbol_string(main_fn_symbol, &interns);
|
||||||
|
|
||||||
|
let main_fn_name = format!("roc_{}_exposed", main_fn_name_base);
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
// errors whose reporting we delay (so we can see that code gen generates runtime errors)
|
// errors whose reporting we delay (so we can see that code gen generates runtime errors)
|
||||||
let mut delayed_errors = Vec::new();
|
let mut delayed_errors = Vec::new();
|
||||||
|
|
|
@ -10,7 +10,7 @@ use inkwell::types::{BasicType, BasicTypeEnum};
|
||||||
use inkwell::values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue};
|
use inkwell::values::{BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue};
|
||||||
use inkwell::AddressSpace;
|
use inkwell::AddressSpace;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{Layout, LayoutIds, UnionLayout};
|
use roc_mono::layout::{LambdaSet, Layout, LayoutIds, UnionLayout};
|
||||||
|
|
||||||
pub fn call_bitcode_fn<'a, 'ctx, 'env>(
|
pub fn call_bitcode_fn<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
@ -189,7 +189,7 @@ fn build_has_tag_id_help<'a, 'ctx, 'env>(
|
||||||
pub fn build_transform_caller<'a, 'ctx, 'env>(
|
pub fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
function: FunctionValue<'ctx>,
|
function: FunctionValue<'ctx>,
|
||||||
closure_data_layout: Layout<'a>,
|
closure_data_layout: LambdaSet<'a>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let fn_name: &str = &format!(
|
let fn_name: &str = &format!(
|
||||||
|
@ -212,7 +212,7 @@ pub fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
fn build_transform_caller_help<'a, 'ctx, 'env>(
|
fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
closure_data_layout: Layout<'a>,
|
closure_data_layout: LambdaSet<'a>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
|
@ -270,7 +270,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
arguments_cast.push(argument);
|
arguments_cast.push(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
match closure_data_layout {
|
match closure_data_layout.runtime_representation() {
|
||||||
Layout::Struct(&[]) => {
|
Layout::Struct(&[]) => {
|
||||||
// nothing to add
|
// nothing to add
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||||
pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
closure_data_layout: Layout<'a>,
|
closure_data_layout: LambdaSet<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||||
|
@ -595,7 +595,7 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let default = [value1, value2];
|
let default = [value1, value2];
|
||||||
|
|
||||||
let arguments_cast = match closure_data_layout {
|
let arguments_cast = match closure_data_layout.runtime_representation() {
|
||||||
Layout::Struct(&[]) => {
|
Layout::Struct(&[]) => {
|
||||||
// nothing to add
|
// nothing to add
|
||||||
&default
|
&default
|
||||||
|
|
|
@ -638,7 +638,7 @@ pub fn construct_optimization_passes<'a>(
|
||||||
|
|
||||||
let pmb = PassManagerBuilder::create();
|
let pmb = PassManagerBuilder::create();
|
||||||
match opt_level {
|
match opt_level {
|
||||||
OptLevel::Normal => {
|
OptLevel::Development | OptLevel::Normal => {
|
||||||
pmb.set_optimization_level(OptimizationLevel::None);
|
pmb.set_optimization_level(OptimizationLevel::None);
|
||||||
}
|
}
|
||||||
OptLevel::Optimize => {
|
OptLevel::Optimize => {
|
||||||
|
@ -2609,6 +2609,18 @@ pub fn load_symbol_and_layout<'a, 'ctx, 'b>(
|
||||||
None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope),
|
None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_symbol_and_lambda_set<'a, 'ctx, 'b>(
|
||||||
|
scope: &'b Scope<'a, 'ctx>,
|
||||||
|
symbol: &Symbol,
|
||||||
|
) -> (BasicValueEnum<'ctx>, LambdaSet<'a>) {
|
||||||
|
match scope.get(symbol) {
|
||||||
|
Some((Layout::LambdaSet(lambda_set), ptr)) => (*ptr, *lambda_set),
|
||||||
|
Some((other, ptr)) => panic!("Not a lambda set: {:?}, {:?}", other, ptr),
|
||||||
|
None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn access_index_struct_value<'ctx>(
|
fn access_index_struct_value<'ctx>(
|
||||||
builder: &Builder<'ctx>,
|
builder: &Builder<'ctx>,
|
||||||
from_value: StructValue<'ctx>,
|
from_value: StructValue<'ctx>,
|
||||||
|
@ -4102,31 +4114,26 @@ fn roc_function_call<'a, 'ctx, 'env>(
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
transform: FunctionValue<'ctx>,
|
transform: FunctionValue<'ctx>,
|
||||||
closure_data: BasicValueEnum<'ctx>,
|
closure_data: BasicValueEnum<'ctx>,
|
||||||
closure_data_layout: Layout<'a>,
|
lambda_set: LambdaSet<'a>,
|
||||||
closure_data_is_owned: bool,
|
closure_data_is_owned: bool,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
) -> RocFunctionCall<'ctx> {
|
) -> RocFunctionCall<'ctx> {
|
||||||
use crate::llvm::bitcode::{build_inc_n_wrapper, build_transform_caller};
|
use crate::llvm::bitcode::{build_inc_n_wrapper, build_transform_caller};
|
||||||
|
|
||||||
let closure_data_layout = match closure_data_layout {
|
|
||||||
Layout::LambdaSet(lambda_set) => lambda_set.runtime_representation(),
|
|
||||||
_ => panic!("closure argument is not a lambda set!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let closure_data_ptr = env
|
let closure_data_ptr = env
|
||||||
.builder
|
.builder
|
||||||
.build_alloca(closure_data.get_type(), "closure_data_ptr");
|
.build_alloca(closure_data.get_type(), "closure_data_ptr");
|
||||||
env.builder.build_store(closure_data_ptr, closure_data);
|
env.builder.build_store(closure_data_ptr, closure_data);
|
||||||
|
|
||||||
let stepper_caller =
|
let stepper_caller = build_transform_caller(env, transform, lambda_set, argument_layouts)
|
||||||
build_transform_caller(env, transform, closure_data_layout, argument_layouts)
|
|
||||||
.as_global_value()
|
|
||||||
.as_pointer_value();
|
|
||||||
|
|
||||||
let inc_closure_data = build_inc_n_wrapper(env, layout_ids, &closure_data_layout)
|
|
||||||
.as_global_value()
|
.as_global_value()
|
||||||
.as_pointer_value();
|
.as_pointer_value();
|
||||||
|
|
||||||
|
let inc_closure_data =
|
||||||
|
build_inc_n_wrapper(env, layout_ids, &lambda_set.runtime_representation())
|
||||||
|
.as_global_value()
|
||||||
|
.as_pointer_value();
|
||||||
|
|
||||||
let closure_data_is_owned = env
|
let closure_data_is_owned = env
|
||||||
.context
|
.context
|
||||||
.bool_type()
|
.bool_type()
|
||||||
|
@ -4180,7 +4187,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = passed_function_at_index!(2);
|
let function = passed_function_at_index!(2);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[3]);
|
||||||
|
|
||||||
match list_layout {
|
match list_layout {
|
||||||
Layout::Builtin(Builtin::EmptyList) => default,
|
Layout::Builtin(Builtin::EmptyList) => default,
|
||||||
|
@ -4192,7 +4199,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4222,7 +4229,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = passed_function_at_index!(1);
|
let function = passed_function_at_index!(1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
|
||||||
|
|
||||||
match (list_layout, return_layout) {
|
match (list_layout, return_layout) {
|
||||||
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
|
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
|
||||||
|
@ -4237,7 +4244,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4254,7 +4261,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (list2, list2_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
let function = passed_function_at_index!(2);
|
let function = passed_function_at_index!(2);
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[3]);
|
||||||
|
|
||||||
match (list1_layout, list2_layout, return_layout) {
|
match (list1_layout, list2_layout, return_layout) {
|
||||||
(
|
(
|
||||||
|
@ -4269,7 +4276,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4298,7 +4305,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
let (list3, list3_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (list3, list3_layout) = load_symbol_and_layout(scope, &args[2]);
|
||||||
|
|
||||||
let function = passed_function_at_index!(3);
|
let function = passed_function_at_index!(3);
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[4]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[4]);
|
||||||
|
|
||||||
match (list1_layout, list2_layout, list3_layout, return_layout) {
|
match (list1_layout, list2_layout, list3_layout, return_layout) {
|
||||||
(
|
(
|
||||||
|
@ -4315,7 +4322,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4347,7 +4354,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = passed_function_at_index!(1);
|
let function = passed_function_at_index!(1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
|
||||||
|
|
||||||
match (list_layout, return_layout) {
|
match (list_layout, return_layout) {
|
||||||
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
|
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
|
||||||
|
@ -4362,7 +4369,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4380,7 +4387,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = passed_function_at_index!(1);
|
let function = passed_function_at_index!(1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
|
||||||
|
|
||||||
match list_layout {
|
match list_layout {
|
||||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||||
|
@ -4392,7 +4399,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4410,7 +4417,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = passed_function_at_index!(1);
|
let function = passed_function_at_index!(1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
|
||||||
|
|
||||||
match (list_layout, return_layout) {
|
match (list_layout, return_layout) {
|
||||||
(_, Layout::Builtin(Builtin::EmptyList))
|
(_, Layout::Builtin(Builtin::EmptyList))
|
||||||
|
@ -4426,7 +4433,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4454,7 +4461,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = passed_function_at_index!(1);
|
let function = passed_function_at_index!(1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
|
||||||
|
|
||||||
match (list_layout, return_layout) {
|
match (list_layout, return_layout) {
|
||||||
(_, Layout::Builtin(Builtin::EmptyList))
|
(_, Layout::Builtin(Builtin::EmptyList))
|
||||||
|
@ -4470,7 +4477,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4507,7 +4514,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = passed_function_at_index!(1);
|
let function = passed_function_at_index!(1);
|
||||||
|
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[2]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[2]);
|
||||||
|
|
||||||
match list_layout {
|
match list_layout {
|
||||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||||
|
@ -4516,13 +4523,8 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let argument_layouts = &[**element_layout, **element_layout];
|
let argument_layouts = &[**element_layout, **element_layout];
|
||||||
|
|
||||||
let closure_data_layout = match closure_layout {
|
|
||||||
Layout::LambdaSet(lambda_set) => lambda_set.runtime_representation(),
|
|
||||||
_ => panic!("closure argument is not a lambda set!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let compare_wrapper =
|
let compare_wrapper =
|
||||||
build_compare_wrapper(env, function, closure_data_layout, element_layout)
|
build_compare_wrapper(env, function, closure_layout, element_layout)
|
||||||
.as_global_value()
|
.as_global_value()
|
||||||
.as_pointer_value();
|
.as_pointer_value();
|
||||||
|
|
||||||
|
@ -4531,7 +4533,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
@ -4553,7 +4555,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
let (dict, dict_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (dict, dict_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
let function = passed_function_at_index!(2);
|
let function = passed_function_at_index!(2);
|
||||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
let (closure, closure_layout) = load_symbol_and_lambda_set(scope, &args[3]);
|
||||||
|
|
||||||
match dict_layout {
|
match dict_layout {
|
||||||
Layout::Builtin(Builtin::EmptyDict) => {
|
Layout::Builtin(Builtin::EmptyDict) => {
|
||||||
|
@ -4568,7 +4570,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
*closure_layout,
|
closure_layout,
|
||||||
function_owns_closure_data,
|
function_owns_closure_data,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
);
|
);
|
||||||
|
|
|
@ -589,9 +589,9 @@ fn call_spec(
|
||||||
let index = builder.add_make_tuple(block, &[])?;
|
let index = builder.add_make_tuple(block, &[])?;
|
||||||
|
|
||||||
let argument = if closure_env_layout.is_none() {
|
let argument = if closure_env_layout.is_none() {
|
||||||
builder.add_make_tuple(block, &[first, index])?
|
builder.add_make_tuple(block, &[index, first])?
|
||||||
} else {
|
} else {
|
||||||
builder.add_make_tuple(block, &[first, index, closure_env])?
|
builder.add_make_tuple(block, &[index, first, closure_env])?
|
||||||
};
|
};
|
||||||
builder.add_call(block, spec_var, module, name, argument)?;
|
builder.add_call(block, spec_var, module, name, argument)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ macro_rules! return_on_layout_error_help {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum OptLevel {
|
pub enum OptLevel {
|
||||||
|
Development,
|
||||||
Normal,
|
Normal,
|
||||||
Optimize,
|
Optimize,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2017,3 +2017,17 @@ fn lists_with_incompatible_type_param_in_if() {
|
||||||
RocStr
|
RocStr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_with_index_multi_record() {
|
||||||
|
// see https://github.com/rtfeldman/roc/issues/1700
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
List.mapWithIndex [ { x: {}, y: {} } ] \_, _ -> {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocList::from_slice(&[((), ())]),
|
||||||
|
RocList<((), ())>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
1
examples/fib/.gitignore
vendored
Normal file
1
examples/fib/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
add
|
27
examples/fib/Fib.roc
Normal file
27
examples/fib/Fib.roc
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
app "fib"
|
||||||
|
packages { base: "platform" }
|
||||||
|
imports []
|
||||||
|
provides [ main ] to base
|
||||||
|
|
||||||
|
main = \n -> fib n
|
||||||
|
|
||||||
|
|
||||||
|
fib = \n ->
|
||||||
|
if n == 0 then
|
||||||
|
0
|
||||||
|
else if n == 1 then
|
||||||
|
1
|
||||||
|
else
|
||||||
|
(fib (n - 1)) + (fib (n - 2))
|
||||||
|
|
||||||
|
# the clever implementation requires join points
|
||||||
|
# fib = \n, a, b ->
|
||||||
|
# if n == 0 then
|
||||||
|
# a
|
||||||
|
#
|
||||||
|
# else
|
||||||
|
# fib (n - 1) b (a + b)
|
||||||
|
#
|
||||||
|
# fib n 0 1
|
||||||
|
|
||||||
|
|
10
examples/fib/platform/Package-Config.roc
Normal file
10
examples/fib/platform/Package-Config.roc
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
platform examples/add
|
||||||
|
requires {}{ main : I64 -> I64 }
|
||||||
|
exposes []
|
||||||
|
packages {}
|
||||||
|
imports []
|
||||||
|
provides [ mainForHost ]
|
||||||
|
effects fx.Effect {}
|
||||||
|
|
||||||
|
mainForHost : I64 -> I64
|
||||||
|
mainForHost = \a -> main a
|
95
examples/fib/platform/host.zig
Normal file
95
examples/fib/platform/host.zig
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
const expectEqual = testing.expectEqual;
|
||||||
|
const expect = testing.expect;
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
// This is a workaround for https://github.com/ziglang/zig/issues/8218
|
||||||
|
// which is only necessary on macOS.
|
||||||
|
//
|
||||||
|
// Once that issue is fixed, we can undo the changes in
|
||||||
|
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
|
||||||
|
// -fcompiler-rt in link.rs instead of doing this. Note that this
|
||||||
|
// workaround is present in many host.zig files, so make sure to undo
|
||||||
|
// it everywhere!
|
||||||
|
if (std.builtin.os.tag == .macos) {
|
||||||
|
_ = @import("compiler_rt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mem = std.mem;
|
||||||
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
|
extern fn roc__mainForHost_1_exposed(i64) i64;
|
||||||
|
|
||||||
|
const Align = extern struct { a: usize, b: usize };
|
||||||
|
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
|
||||||
|
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void;
|
||||||
|
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void;
|
||||||
|
|
||||||
|
const DEBUG: bool = false;
|
||||||
|
|
||||||
|
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
|
||||||
|
if (DEBUG) {
|
||||||
|
var ptr = malloc(size);
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
stdout.print("alloc: {d} (alignment {d}, size {d})\n", .{ ptr, alignment, size }) catch unreachable;
|
||||||
|
return ptr;
|
||||||
|
} else {
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void {
|
||||||
|
if (DEBUG) {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return realloc(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)), new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
||||||
|
if (DEBUG) {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
||||||
|
_ = tag_id;
|
||||||
|
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
const msg = @ptrCast([*:0]const u8, c_ptr);
|
||||||
|
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
||||||
|
std.process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub export fn main() u8 {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
|
||||||
|
// start time
|
||||||
|
var ts1: std.os.timespec = undefined;
|
||||||
|
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
||||||
|
|
||||||
|
const result = roc__mainForHost_1_exposed(10);
|
||||||
|
|
||||||
|
stdout.print("{d}\n", .{result}) catch unreachable;
|
||||||
|
|
||||||
|
// end time
|
||||||
|
var ts2: std.os.timespec = undefined;
|
||||||
|
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable;
|
||||||
|
|
||||||
|
const delta = to_seconds(ts2) - to_seconds(ts1);
|
||||||
|
|
||||||
|
stderr.print("runtime: {d:.3}ms\n", .{delta * 1000}) catch unreachable;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_seconds(tms: std.os.timespec) f64 {
|
||||||
|
return @intToFloat(f64, tms.tv_sec) + (@intToFloat(f64, tms.tv_nsec) / 1_000_000_000.0);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue