mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Merge remote-tracking branch 'origin/trunk' into tail-call-elimination
This commit is contained in:
commit
380e34d296
10 changed files with 1529 additions and 1804 deletions
|
@ -10,7 +10,7 @@ use roc_can::expected::Expected;
|
|||
use roc_can::expr::{canonicalize_expr, Output};
|
||||
use roc_can::operator;
|
||||
use roc_can::scope::Scope;
|
||||
use roc_collections::all::{ImMap, ImSet, MutMap, SendMap, SendSet};
|
||||
use roc_collections::all::{ImMap, ImSet, MutMap, MutSet, SendMap, SendSet};
|
||||
use roc_constrain::expr::constrain_expr;
|
||||
use roc_constrain::module::{constrain_imported_values, load_builtin_aliases, Import};
|
||||
use roc_gen::layout_id::LayoutIds;
|
||||
|
@ -241,6 +241,7 @@ pub fn gen(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<(String, S
|
|||
module,
|
||||
ptr_bytes,
|
||||
leak: false,
|
||||
exposed_to_host: MutSet::default(),
|
||||
};
|
||||
let mut procs = Procs::default();
|
||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||
|
@ -321,8 +322,7 @@ pub fn gen(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<(String, S
|
|||
|
||||
// Add main to the module.
|
||||
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
||||
let cc =
|
||||
roc_gen::llvm::build::get_call_conventions(target.default_calling_convention().unwrap());
|
||||
let cc = roc_gen::llvm::build::FAST_CALL_CONV;
|
||||
|
||||
main_fn.set_call_conventions(cc);
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ mod cli_run {
|
|||
assert_eq!(&out.stderr, "");
|
||||
assert!(&out
|
||||
.stdout
|
||||
.ends_with("[5, 6, 10, 12, 20, 21, 22, 23, 24, 32, 33, 42, 45, 54]\n"));
|
||||
.ends_with("[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"));
|
||||
assert!(out.status.success());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
use bumpalo::Bump;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::module::Linkage;
|
||||
use inkwell::targets::{
|
||||
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
|
||||
};
|
||||
use inkwell::OptimizationLevel;
|
||||
use roc_collections::all::default_hasher;
|
||||
use roc_gen::layout_id::LayoutIds;
|
||||
use roc_gen::llvm::build::{
|
||||
build_proc, build_proc_header, get_call_conventions, module_from_builtins, OptLevel,
|
||||
};
|
||||
use roc_gen::llvm::build::{build_proc, build_proc_header, module_from_builtins, OptLevel};
|
||||
use roc_load::file::LoadedModule;
|
||||
use roc_mono::ir::{Env, PartialProc, Procs};
|
||||
use roc_mono::layout::{Layout, LayoutCache};
|
||||
|
@ -23,7 +20,7 @@ use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
|
|||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn gen(
|
||||
arena: &Bump,
|
||||
loaded: LoadedModule,
|
||||
mut loaded: LoadedModule,
|
||||
filename: PathBuf,
|
||||
target: Triple,
|
||||
dest_filename: &Path,
|
||||
|
@ -74,17 +71,14 @@ pub fn gen(
|
|||
|
||||
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||
|
||||
// Compile and add all the Procs before adding main
|
||||
let mut env = roc_gen::llvm::build::Env {
|
||||
arena: &arena,
|
||||
builder: &builder,
|
||||
context: &context,
|
||||
interns: loaded.interns,
|
||||
module,
|
||||
ptr_bytes,
|
||||
leak: false,
|
||||
};
|
||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||
let mut exposed_to_host =
|
||||
HashSet::with_capacity_and_hasher(loaded.exposed_vars_by_symbol.len(), default_hasher());
|
||||
|
||||
for (symbol, _) in loaded.exposed_vars_by_symbol {
|
||||
exposed_to_host.insert(symbol);
|
||||
}
|
||||
|
||||
let mut ident_ids = loaded.interns.all_ident_ids.remove(&home).unwrap();
|
||||
let mut layout_ids = LayoutIds::default();
|
||||
let mut procs = Procs::default();
|
||||
let mut mono_problems = std::vec::Vec::new();
|
||||
|
@ -96,12 +90,6 @@ pub fn gen(
|
|||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
};
|
||||
let mut exposed_symbols =
|
||||
HashSet::with_capacity_and_hasher(loaded.exposed_vars_by_symbol.len(), default_hasher());
|
||||
|
||||
for (symbol, _) in loaded.exposed_vars_by_symbol {
|
||||
exposed_symbols.insert(symbol);
|
||||
}
|
||||
|
||||
// Add modules' decls to Procs
|
||||
for (_, mut decls) in decls_by_id
|
||||
|
@ -127,7 +115,7 @@ pub fn gen(
|
|||
// register it as such. Otherwise, since it
|
||||
// never gets called by Roc code, it will never
|
||||
// get specialized!
|
||||
if exposed_symbols.contains(&symbol) {
|
||||
if exposed_to_host.contains(&symbol) {
|
||||
let mut pattern_vars =
|
||||
bumpalo::collections::Vec::with_capacity_in(
|
||||
loc_args.len(),
|
||||
|
@ -178,7 +166,7 @@ pub fn gen(
|
|||
// register it as such. Otherwise, since it
|
||||
// never gets called by Roc code, it will never
|
||||
// get specialized!
|
||||
if exposed_symbols.contains(&symbol) {
|
||||
if exposed_to_host.contains(&symbol) {
|
||||
let pattern_vars = bumpalo::collections::Vec::new_in(arena);
|
||||
let ret_layout = layout_cache.from_var(mono_env.arena, annotation, mono_env.subs).unwrap_or_else(|err|
|
||||
todo!("TODO gracefully handle the situation where we expose a function to the host which doesn't have a valid layout (e.g. maybe the function wasn't monomorphic): {:?}", err)
|
||||
|
@ -225,6 +213,18 @@ pub fn gen(
|
|||
}
|
||||
}
|
||||
|
||||
// Compile and add all the Procs before adding main
|
||||
let mut env = roc_gen::llvm::build::Env {
|
||||
arena: &arena,
|
||||
builder: &builder,
|
||||
context: &context,
|
||||
interns: loaded.interns,
|
||||
module,
|
||||
ptr_bytes,
|
||||
leak: false,
|
||||
exposed_to_host,
|
||||
};
|
||||
|
||||
// Populate Procs further and get the low-level Expr from the canonical Expr
|
||||
let mut headers = {
|
||||
let num_headers = match &procs.pending_specializations {
|
||||
|
@ -274,27 +274,6 @@ pub fn gen(
|
|||
}
|
||||
}
|
||||
|
||||
// Set exposed functions to external linkage and C calling conventions
|
||||
{
|
||||
let cc = get_call_conventions(target.default_calling_convention().unwrap());
|
||||
let interns = &env.interns;
|
||||
|
||||
for symbol in exposed_symbols {
|
||||
// Since it was exposed, it must have been monomorphic,
|
||||
// meaning its LLVM name will be ___#1 (e.g. "main#1")
|
||||
let fn_name = format!("{}#1", symbol.ident_string(interns));
|
||||
let fn_val = env.module.get_function(&fn_name).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"module.get_function({:?}) did not find a function registered with LLVM",
|
||||
fn_name
|
||||
)
|
||||
});
|
||||
|
||||
fn_val.set_linkage(Linkage::External);
|
||||
fn_val.set_call_conventions(cc);
|
||||
}
|
||||
}
|
||||
|
||||
mpm.run_on(module);
|
||||
|
||||
// Verify the module
|
||||
|
|
File diff suppressed because it is too large
Load diff
1388
compiler/gen/src/llvm/build_list.rs
Normal file
1388
compiler/gen/src/llvm/build_list.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,4 @@
|
|||
pub mod build;
|
||||
pub mod build_list;
|
||||
pub mod compare;
|
||||
pub mod convert;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use roc_collections::all::MutSet;
|
||||
use roc_types::subs::Subs;
|
||||
|
||||
pub fn helper_without_uniqueness<'a>(
|
||||
|
@ -88,6 +89,7 @@ pub fn helper_without_uniqueness<'a>(
|
|||
module,
|
||||
ptr_bytes,
|
||||
leak: leak,
|
||||
exposed_to_host: MutSet::default(),
|
||||
};
|
||||
let mut procs = roc_mono::ir::Procs::default();
|
||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||
|
@ -160,8 +162,7 @@ pub fn helper_without_uniqueness<'a>(
|
|||
|
||||
// Add main to the module.
|
||||
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
||||
let cc =
|
||||
roc_gen::llvm::build::get_call_conventions(target.default_calling_convention().unwrap());
|
||||
let cc = roc_gen::llvm::build::FAST_CALL_CONV;
|
||||
|
||||
main_fn.set_call_conventions(cc);
|
||||
|
||||
|
@ -279,6 +280,7 @@ pub fn helper_with_uniqueness<'a>(
|
|||
module,
|
||||
ptr_bytes,
|
||||
leak: leak,
|
||||
exposed_to_host: MutSet::default(),
|
||||
};
|
||||
let mut procs = roc_mono::ir::Procs::default();
|
||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||
|
@ -350,8 +352,7 @@ pub fn helper_with_uniqueness<'a>(
|
|||
|
||||
// Add main to the module.
|
||||
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
||||
let cc =
|
||||
roc_gen::llvm::build::get_call_conventions(target.default_calling_convention().unwrap());
|
||||
let cc = roc_gen::llvm::build::FAST_CALL_CONV;
|
||||
|
||||
main_fn.set_call_conventions(cc);
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@ mod helpers;
|
|||
// Test monomorphization
|
||||
#[cfg(test)]
|
||||
mod test_mono {
|
||||
use crate::helpers::with_larger_debug_stack;
|
||||
|
||||
// NOTE because the Show instance of module names is different in --release mode,
|
||||
// these tests would all fail. In the future, when we do interesting optimizations,
|
||||
// we'll likely want some tests for --release too.
|
||||
|
@ -932,7 +930,7 @@ mod test_mono {
|
|||
|
||||
#[allow(dead_code)]
|
||||
fn quicksort_help() {
|
||||
with_larger_debug_stack(|| {
|
||||
crate::helpers::with_larger_debug_stack(|| {
|
||||
compiles_to_ir(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -960,7 +958,7 @@ mod test_mono {
|
|||
|
||||
#[allow(dead_code)]
|
||||
fn quicksort_partition_help() {
|
||||
with_larger_debug_stack(|| {
|
||||
crate::helpers::with_larger_debug_stack(|| {
|
||||
compiles_to_ir(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -994,7 +992,7 @@ mod test_mono {
|
|||
|
||||
#[allow(dead_code)]
|
||||
fn quicksort_full() {
|
||||
with_larger_debug_stack(|| {
|
||||
crate::helpers::with_larger_debug_stack(|| {
|
||||
compiles_to_ir(
|
||||
indoc!(
|
||||
r#"
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
|
||||
#[link(name = "roc_app", kind = "static")]
|
||||
|
@ -12,84 +7,31 @@ extern "C" {
|
|||
fn quicksort(list: Box<[i64]>) -> Box<[i64]>;
|
||||
}
|
||||
|
||||
pub fn example_dir(dir_name: &str) -> PathBuf {
|
||||
let mut path = env::current_exe().ok().unwrap();
|
||||
|
||||
// Get rid of the filename in target/debug/deps/cli_run-99c65e4e9a1fbd06
|
||||
path.pop();
|
||||
|
||||
// If we're in deps/ get rid of deps/ in target/debug/deps/
|
||||
if path.ends_with("deps") {
|
||||
path.pop();
|
||||
}
|
||||
|
||||
// Get rid of target/debug/ so we're back at the project root
|
||||
path.pop();
|
||||
path.pop();
|
||||
|
||||
// Descend into examples/{dir_name}
|
||||
path.push("examples");
|
||||
path.push(dir_name);
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
pub fn example_file(dir_name: &str, file_name: &str) -> PathBuf {
|
||||
let mut path = example_dir(dir_name);
|
||||
|
||||
path.push(file_name);
|
||||
|
||||
path
|
||||
}
|
||||
const NUM_NUMS: usize = 1_000_000;
|
||||
|
||||
pub fn main() {
|
||||
let filename = example_file("quicksort", "unsorted.csv");
|
||||
let nums: Box<[i64]> = {
|
||||
let mut nums = Vec::with_capacity(NUM_NUMS);
|
||||
|
||||
let mut nums = {
|
||||
match File::open(filename.clone()) {
|
||||
Ok(file) => {
|
||||
let mut contents = String::new();
|
||||
let mut buf_reader = BufReader::new(file);
|
||||
for index in 0..nums.capacity() {
|
||||
let num = index as i64 % 12345;
|
||||
|
||||
buf_reader
|
||||
.read_to_string(&mut contents)
|
||||
.expect("error reading file to string");
|
||||
|
||||
contents
|
||||
.split(",")
|
||||
.map(|string| {
|
||||
string.trim().parse::<i64>().unwrap_or_else(|err| {
|
||||
panic!("Invalid number: {:?} - error was: {:?}", string, err)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<i64>>()
|
||||
}
|
||||
Err(err) => {
|
||||
println!(
|
||||
"INFO: Couldn't open the CSV file {:?} because {:?}, so falling back on a hardcoded list of numbers.", err, filename
|
||||
);
|
||||
|
||||
vec![10, 24, 54, 23, 21, 22, 45, 5, 32, 33, 6, 20, 12, 42]
|
||||
}
|
||||
nums.push(num);
|
||||
}
|
||||
nums.into()
|
||||
};
|
||||
|
||||
// TODO FIXME don't truncate! This is just for testing.
|
||||
nums.truncate(1_000_000);
|
||||
|
||||
let nums: Box<[i64]> = nums.into();
|
||||
|
||||
println!("Running Roc quicksort on {} numbers...", nums.len());
|
||||
let start_time = SystemTime::now();
|
||||
let answer = unsafe { quicksort(nums) };
|
||||
let end_time = SystemTime::now();
|
||||
let duration = end_time.duration_since(start_time).unwrap();
|
||||
|
||||
// hardcode test output, so stdout is not swamped
|
||||
println!(
|
||||
"Roc quicksort took {:.4} ms to compute this answer: {:?}",
|
||||
duration.as_secs_f64() * 1000.0,
|
||||
vec![5, 6, 10, 12, 20, 21, 22, 23, 24, 32, 33, 42, 45, 54]
|
||||
// truncate the answer, so stdout is not swamped
|
||||
&answer[0..20]
|
||||
);
|
||||
|
||||
// the pointer is to the first _element_ of the list,
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
10,24,54,23,21,22,45,5,32,33,6,20,12,42
|
|
Loading…
Add table
Add a link
Reference in a new issue