mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
commit
c225ccc029
@ -12,15 +12,15 @@ use cranelift_codegen::ir::{immediates::Offset32, types, InstBuilder, Signature,
|
||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||
use cranelift_codegen::Context;
|
||||
use cranelift_module::{Backend, FuncId, Linkage, Module};
|
||||
use inlinable_string::InlinableString;
|
||||
|
||||
use crate::collections::ImMap;
|
||||
use crate::crane::convert::{sig_from_layout, type_from_layout};
|
||||
use crate::module::symbol::{Interns, Symbol};
|
||||
use crate::mono::expr::{Expr, Proc, Procs};
|
||||
use crate::mono::layout::{Builtin, Layout};
|
||||
use crate::subs::{Subs, Variable};
|
||||
|
||||
type Scope = ImMap<InlinableString, ScopeEntry>;
|
||||
type Scope = ImMap<Symbol, ScopeEntry>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ScopeEntry {
|
||||
@ -34,6 +34,7 @@ pub struct Env<'a> {
|
||||
pub arena: &'a Bump,
|
||||
pub cfg: TargetFrontendConfig,
|
||||
pub subs: Subs,
|
||||
pub interns: Interns,
|
||||
}
|
||||
|
||||
pub fn build_expr<'a, B: Backend>(
|
||||
@ -119,43 +120,32 @@ pub fn build_expr<'a, B: Backend>(
|
||||
// access itself!
|
||||
scope = im_rc::HashMap::clone(&scope);
|
||||
|
||||
scope.insert(name.clone(), ScopeEntry::Stack { expr_type, slot });
|
||||
scope.insert(*name, ScopeEntry::Stack { expr_type, slot });
|
||||
}
|
||||
|
||||
build_expr(env, &scope, module, builder, ret, procs)
|
||||
}
|
||||
CallByName(ref name, ref args) => {
|
||||
// TODO try one of these alternative strategies (preferably the latter):
|
||||
//
|
||||
// 1. use SIMD string comparison to compare these strings faster
|
||||
// 2. pre-register Bool.or using module.add_function, and see if LLVM inlines it
|
||||
// 3. intern all these strings
|
||||
if name == "Bool.or" {
|
||||
panic!("TODO create a branch for ||");
|
||||
} else if name == "Bool.and" {
|
||||
panic!("TODO create a branch for &&");
|
||||
} else {
|
||||
let mut arg_vals = Vec::with_capacity_in(args.len(), env.arena);
|
||||
CallByName(ref symbol, ref args) => {
|
||||
let mut arg_vals = Vec::with_capacity_in(args.len(), env.arena);
|
||||
|
||||
for arg in args.iter() {
|
||||
arg_vals.push(build_expr(env, scope, module, builder, arg, procs));
|
||||
}
|
||||
for arg in args.iter() {
|
||||
arg_vals.push(build_expr(env, scope, module, builder, arg, procs));
|
||||
}
|
||||
|
||||
let fn_id = match scope.get(name) {
|
||||
let fn_id = match scope.get(symbol) {
|
||||
Some(ScopeEntry::Func{ func_id, .. }) => *func_id,
|
||||
other => panic!(
|
||||
"CallByName could not find function named {:?} in scope; instead, found {:?} in scope {:?}",
|
||||
name, other, scope
|
||||
symbol, other, scope
|
||||
),
|
||||
};
|
||||
let local_func = module.declare_func_in_func(fn_id, &mut builder.func);
|
||||
let call = builder.ins().call(local_func, &arg_vals);
|
||||
let results = builder.inst_results(call);
|
||||
let local_func = module.declare_func_in_func(fn_id, &mut builder.func);
|
||||
let call = builder.ins().call(local_func, &arg_vals);
|
||||
let results = builder.inst_results(call);
|
||||
|
||||
debug_assert!(results.len() == 1);
|
||||
debug_assert!(results.len() == 1);
|
||||
|
||||
results[0]
|
||||
}
|
||||
results[0]
|
||||
}
|
||||
FunctionPointer(ref name) => {
|
||||
let fn_id = match scope.get(name) {
|
||||
@ -432,7 +422,7 @@ fn build_switch<'a, B: Backend>(
|
||||
pub fn declare_proc<'a, B: Backend>(
|
||||
env: &Env<'a>,
|
||||
module: &mut Module<B>,
|
||||
name: InlinableString,
|
||||
symbol: Symbol,
|
||||
proc: &Proc<'a>,
|
||||
) -> (FuncId, Signature) {
|
||||
let args = proc.args;
|
||||
@ -459,8 +449,8 @@ pub fn declare_proc<'a, B: Backend>(
|
||||
|
||||
// Declare the function in the module
|
||||
let fn_id = module
|
||||
.declare_function(&name, Linkage::Local, &sig)
|
||||
.unwrap_or_else(|err| panic!("Error when building function {:?} - {:?}", name, err));
|
||||
.declare_function(symbol.ident_string(&env.interns), Linkage::Local, &sig)
|
||||
.unwrap_or_else(|err| panic!("Error when building function {:?} - {:?}", symbol, err));
|
||||
|
||||
(fn_id, sig)
|
||||
}
|
||||
@ -498,7 +488,7 @@ pub fn define_proc_body<'a, B: Backend>(
|
||||
builder.append_ebb_params_for_function_params(block);
|
||||
|
||||
// Add args to scope
|
||||
for (¶m, (_, arg_name, var)) in builder.ebb_params(block).iter().zip(args) {
|
||||
for (¶m, (_, arg_symbol, var)) in builder.ebb_params(block).iter().zip(args) {
|
||||
let content = subs.get_without_compacting(*var).content;
|
||||
// TODO this Layout::from_content is duplicated when building this Proc
|
||||
//
|
||||
@ -507,7 +497,7 @@ pub fn define_proc_body<'a, B: Backend>(
|
||||
});
|
||||
let expr_type = type_from_layout(cfg, &layout);
|
||||
|
||||
scope.insert(arg_name.clone(), ScopeEntry::Arg { expr_type, param });
|
||||
scope.insert(*arg_symbol, ScopeEntry::Arg { expr_type, param });
|
||||
}
|
||||
|
||||
let body = build_expr(env, &scope, module, &mut builder, &proc.body, procs);
|
||||
|
@ -7,10 +7,10 @@ use inkwell::types::BasicTypeEnum;
|
||||
use inkwell::values::BasicValueEnum::{self, *};
|
||||
use inkwell::values::{FunctionValue, IntValue, PointerValue};
|
||||
use inkwell::{FloatPredicate, IntPredicate};
|
||||
use inlinable_string::InlinableString;
|
||||
|
||||
use crate::collections::ImMap;
|
||||
use crate::llvm::convert::{basic_type_from_layout, get_fn_type};
|
||||
use crate::module::symbol::{Interns, Symbol};
|
||||
use crate::mono::expr::{Expr, Proc, Procs};
|
||||
use crate::mono::layout::Layout;
|
||||
use crate::subs::{Subs, Variable};
|
||||
@ -23,13 +23,14 @@ const PRINT_FN_VERIFICATION_OUTPUT: bool = true;
|
||||
#[cfg(not(debug_assertions))]
|
||||
const PRINT_FN_VERIFICATION_OUTPUT: bool = false;
|
||||
|
||||
type Scope<'ctx> = ImMap<InlinableString, (Variable, PointerValue<'ctx>)>;
|
||||
type Scope<'ctx> = ImMap<Symbol, (Variable, PointerValue<'ctx>)>;
|
||||
|
||||
pub struct Env<'a, 'ctx, 'env> {
|
||||
pub arena: &'a Bump,
|
||||
pub context: &'ctx Context,
|
||||
pub builder: &'env Builder<'ctx>,
|
||||
pub module: &'ctx Module<'ctx>,
|
||||
pub interns: Interns,
|
||||
pub subs: Subs,
|
||||
}
|
||||
|
||||
@ -93,14 +94,19 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||
let subs = &env.subs;
|
||||
let context = &env.context;
|
||||
|
||||
for (name, var, expr) in stores.iter() {
|
||||
for (symbol, var, expr) in stores.iter() {
|
||||
let content = subs.get_without_compacting(*var).content;
|
||||
let layout = Layout::from_content(env.arena, content, &subs).unwrap_or_else(|_| {
|
||||
panic!("TODO generate a runtime error in build_branch2 here!")
|
||||
});
|
||||
let val = build_expr(env, &scope, parent, &expr, procs);
|
||||
let expr_bt = basic_type_from_layout(context, &layout);
|
||||
let alloca = create_entry_block_alloca(env, parent, expr_bt, &name);
|
||||
let alloca = create_entry_block_alloca(
|
||||
env,
|
||||
parent,
|
||||
expr_bt,
|
||||
symbol.ident_string(&env.interns),
|
||||
);
|
||||
|
||||
env.builder.build_store(alloca, val);
|
||||
|
||||
@ -111,22 +117,19 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||
// access itself!
|
||||
scope = im_rc::HashMap::clone(&scope);
|
||||
|
||||
scope.insert(name.clone(), (*var, alloca));
|
||||
scope.insert(*symbol, (*var, alloca));
|
||||
}
|
||||
|
||||
build_expr(env, &scope, parent, ret, procs)
|
||||
}
|
||||
CallByName(ref name, ref args) => {
|
||||
// TODO try one of these alternative strategies (preferably the latter):
|
||||
//
|
||||
// 1. use SIMD string comparison to compare these strings faster
|
||||
// 2. pre-register Bool.or using module.add_function, and see if LLVM inlines it
|
||||
// 3. intern all these strings
|
||||
if name == "Bool.or" {
|
||||
CallByName(ref symbol, ref args) => match *symbol {
|
||||
Symbol::BOOL_OR => {
|
||||
panic!("TODO create a phi node for ||");
|
||||
} else if name == "Bool.and" {
|
||||
}
|
||||
Symbol::BOOL_AND => {
|
||||
panic!("TODO create a phi node for &&");
|
||||
} else {
|
||||
}
|
||||
_ => {
|
||||
let mut arg_vals: Vec<BasicValueEnum> =
|
||||
Vec::with_capacity_in(args.len(), env.arena);
|
||||
|
||||
@ -136,23 +139,21 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||
|
||||
let fn_val = env
|
||||
.module
|
||||
.get_function(name)
|
||||
.unwrap_or_else(|| panic!("Unrecognized function: {:?}", name));
|
||||
.get_function(symbol.ident_string(&env.interns))
|
||||
.unwrap_or_else(|| panic!("Unrecognized function: {:?}", symbol));
|
||||
|
||||
let call = env.builder.build_call(fn_val, arg_vals.as_slice(), "tmp");
|
||||
|
||||
call.try_as_basic_value().left().unwrap_or_else(|| {
|
||||
panic!("LLVM error: Invalid call by name for name {:?}", name)
|
||||
panic!("LLVM error: Invalid call by name for name {:?}", symbol)
|
||||
})
|
||||
}
|
||||
}
|
||||
FunctionPointer(ref fn_name) => {
|
||||
},
|
||||
FunctionPointer(ref symbol) => {
|
||||
let ptr = env
|
||||
.module
|
||||
.get_function(fn_name)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Could not get pointer to unknown function {:?}", fn_name)
|
||||
})
|
||||
.get_function(symbol.ident_string(&env.interns))
|
||||
.unwrap_or_else(|| panic!("Could not get pointer to unknown function {:?}", symbol))
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
|
||||
@ -182,9 +183,11 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."))
|
||||
}
|
||||
|
||||
Load(name) => match scope.get(name) {
|
||||
Some((_, ptr)) => env.builder.build_load(*ptr, name),
|
||||
None => panic!("Could not find a var for {:?} in scope {:?}", name, scope),
|
||||
Load(symbol) => match scope.get(symbol) {
|
||||
Some((_, ptr)) => env
|
||||
.builder
|
||||
.build_load(*ptr, symbol.ident_string(&env.interns)),
|
||||
None => panic!("Could not find a var for {:?} in scope {:?}", symbol, scope),
|
||||
},
|
||||
_ => {
|
||||
panic!("I don't yet know how to LLVM build {:?}", expr);
|
||||
@ -398,12 +401,11 @@ pub fn create_entry_block_alloca<'a, 'ctx>(
|
||||
builder.build_alloca(basic_type, name)
|
||||
}
|
||||
|
||||
pub fn build_proc<'a, 'ctx, 'env>(
|
||||
pub fn build_proc_header<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
name: InlinableString,
|
||||
proc: Proc<'a>,
|
||||
procs: &Procs<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
symbol: Symbol,
|
||||
proc: &Proc<'a>,
|
||||
) -> (FunctionValue<'ctx>, Vec<'a, BasicTypeEnum<'ctx>>) {
|
||||
let args = proc.args;
|
||||
let arena = env.arena;
|
||||
let subs = &env.subs;
|
||||
@ -414,20 +416,35 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_proc here!"));
|
||||
let ret_type = basic_type_from_layout(context, &ret_layout);
|
||||
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
|
||||
let mut arg_names = Vec::new_in(arena);
|
||||
let mut arg_symbols = Vec::new_in(arena);
|
||||
|
||||
for (layout, name, _var) in args.iter() {
|
||||
for (layout, arg_symbol, _var) in args.iter() {
|
||||
let arg_type = basic_type_from_layout(env.context, &layout);
|
||||
|
||||
arg_basic_types.push(arg_type);
|
||||
arg_names.push(name);
|
||||
arg_symbols.push(arg_symbol);
|
||||
}
|
||||
|
||||
let fn_type = get_fn_type(&ret_type, &arg_basic_types);
|
||||
|
||||
let fn_val = env
|
||||
.module
|
||||
.add_function(&name, fn_type, Some(Linkage::Private));
|
||||
let fn_val = env.module.add_function(
|
||||
symbol.ident_string(&env.interns),
|
||||
fn_type,
|
||||
Some(Linkage::Private),
|
||||
);
|
||||
|
||||
(fn_val, arg_basic_types)
|
||||
}
|
||||
|
||||
pub fn build_proc<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
proc: Proc<'a>,
|
||||
procs: &Procs<'a>,
|
||||
fn_val: FunctionValue<'ctx>,
|
||||
arg_basic_types: Vec<'a, BasicTypeEnum<'ctx>>,
|
||||
) {
|
||||
let args = proc.args;
|
||||
let context = &env.context;
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = context.append_basic_block(fn_val, "entry");
|
||||
@ -438,23 +455,22 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||
let mut scope = ImMap::default();
|
||||
|
||||
// Add args to scope
|
||||
for ((arg_val, arg_type), (_, arg_name, var)) in
|
||||
for ((arg_val, arg_type), (_, arg_symbol, var)) in
|
||||
fn_val.get_param_iter().zip(arg_basic_types).zip(args)
|
||||
{
|
||||
set_name(arg_val, arg_name);
|
||||
set_name(arg_val, arg_symbol.ident_string(&env.interns));
|
||||
|
||||
let alloca = create_entry_block_alloca(env, fn_val, arg_type, arg_name);
|
||||
let alloca =
|
||||
create_entry_block_alloca(env, fn_val, arg_type, arg_symbol.ident_string(&env.interns));
|
||||
|
||||
builder.build_store(alloca, arg_val);
|
||||
|
||||
scope.insert(arg_name.clone(), (*var, alloca));
|
||||
scope.insert(*arg_symbol, (*var, alloca));
|
||||
}
|
||||
|
||||
let body = build_expr(env, &scope, fn_val, &proc.body, procs);
|
||||
|
||||
builder.build_return(Some(&body));
|
||||
|
||||
fn_val
|
||||
}
|
||||
|
||||
pub fn verify_fn(fn_val: FunctionValue<'_>) {
|
||||
|
@ -89,10 +89,6 @@ impl Symbol {
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit(self) -> InlinableString {
|
||||
format!("${}", self.0).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Rather than displaying as this:
|
||||
@ -553,8 +549,9 @@ macro_rules! define_builtins {
|
||||
|
||||
define_builtins! {
|
||||
0 ATTR: "Attr" => {
|
||||
0 ATTR_ATTR: "Attr" // the Attr.Attr type alias, used in uniqueness types
|
||||
1 ATTR_AT_ATTR: "@Attr" // the Attr.@Attr private tag
|
||||
0 UNDERSCORE: "_" // the _ used in pattern matches. This is Symbol 0.
|
||||
1 ATTR_ATTR: "Attr" // the Attr.Attr type alias, used in uniqueness types
|
||||
2 ATTR_AT_ATTR: "@Attr" // the Attr.@Attr private tag
|
||||
}
|
||||
1 NUM: "Num" => {
|
||||
0 NUM_NUM: "Num" imported // the Num.Num type alias
|
||||
|
@ -1,26 +1,31 @@
|
||||
use crate::can::pattern::Pattern;
|
||||
use crate::can::{self, ident::Lowercase};
|
||||
use crate::can::{
|
||||
self,
|
||||
ident::{Lowercase, TagName},
|
||||
};
|
||||
use crate::collections::MutMap;
|
||||
use crate::module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use crate::mono::layout::{Builtin, Layout};
|
||||
use crate::region::Located;
|
||||
use crate::subs::{Subs, Variable};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use inlinable_string::InlinableString;
|
||||
|
||||
pub type Procs<'a> = MutMap<InlinableString, Option<Proc<'a>>>;
|
||||
pub type Procs<'a> = MutMap<Symbol, Option<Proc<'a>>>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Proc<'a> {
|
||||
pub args: &'a [(Layout<'a>, InlinableString, Variable)],
|
||||
pub args: &'a [(Layout<'a>, Symbol, Variable)],
|
||||
pub body: Expr<'a>,
|
||||
pub closes_over: Layout<'a>,
|
||||
pub ret_var: Variable,
|
||||
}
|
||||
|
||||
struct Env<'a> {
|
||||
struct Env<'a, 'i> {
|
||||
pub arena: &'a Bump,
|
||||
pub subs: &'a Subs,
|
||||
pub home: ModuleId,
|
||||
pub ident_ids: &'i mut IdentIds,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -40,12 +45,12 @@ pub enum Expr<'a> {
|
||||
Byte(u8),
|
||||
|
||||
// Load/Store
|
||||
Load(InlinableString),
|
||||
Store(&'a [(InlinableString, Variable, Expr<'a>)], &'a Expr<'a>),
|
||||
Load(Symbol),
|
||||
Store(&'a [(Symbol, Variable, Expr<'a>)], &'a Expr<'a>),
|
||||
|
||||
// Functions
|
||||
FunctionPointer(InlinableString),
|
||||
CallByName(InlinableString, &'a [Expr<'a>]),
|
||||
FunctionPointer(Symbol),
|
||||
CallByName(Symbol, &'a [Expr<'a>]),
|
||||
CallByPointer(&'a Expr<'a>, &'a [Expr<'a>], Variable),
|
||||
|
||||
// Exactly two conditional branches, e.g. if/else
|
||||
@ -87,7 +92,7 @@ pub enum Expr<'a> {
|
||||
Tag {
|
||||
variant_var: Variable,
|
||||
ext_var: Variable,
|
||||
name: InlinableString,
|
||||
name: TagName,
|
||||
arguments: &'a [Expr<'a>],
|
||||
},
|
||||
Struct {
|
||||
@ -109,18 +114,25 @@ impl<'a> Expr<'a> {
|
||||
subs: &'a Subs,
|
||||
can_expr: can::expr::Expr,
|
||||
procs: &mut Procs<'a>,
|
||||
home: ModuleId,
|
||||
ident_ids: &mut IdentIds,
|
||||
) -> Self {
|
||||
let env = Env { arena, subs };
|
||||
let mut env = Env {
|
||||
arena,
|
||||
subs,
|
||||
home,
|
||||
ident_ids,
|
||||
};
|
||||
|
||||
from_can(&env, can_expr, procs, None)
|
||||
from_can(&mut env, can_expr, procs, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn from_can<'a>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a, '_>,
|
||||
can_expr: can::expr::Expr,
|
||||
procs: &mut Procs<'a>,
|
||||
name: Option<InlinableString>,
|
||||
name: Option<Symbol>,
|
||||
) -> Expr<'a> {
|
||||
use crate::can::expr::Expr::*;
|
||||
use crate::can::pattern::Pattern::*;
|
||||
@ -129,7 +141,7 @@ fn from_can<'a>(
|
||||
Int(_, val) => Expr::Int(val),
|
||||
Float(_, val) => Expr::Float(val),
|
||||
Str(string) | BlockStr(string) => Expr::Str(env.arena.alloc(string)),
|
||||
Var(symbol) => Expr::Load(symbol.emit()),
|
||||
Var(symbol) => Expr::Load(symbol),
|
||||
LetNonRec(def, ret_expr, _, _) => {
|
||||
let arena = env.arena;
|
||||
let loc_pattern = def.loc_pattern;
|
||||
@ -153,7 +165,7 @@ fn from_can<'a>(
|
||||
if let Closure(_, _, _, _, _) = &loc_expr.value {
|
||||
// Extract Procs, but discard the resulting Expr::Load.
|
||||
// That Load looks up the pointer, which we won't use here!
|
||||
from_can(env, loc_expr.value, procs, Some(symbol.emit()));
|
||||
from_can(env, loc_expr.value, procs, Some(*symbol));
|
||||
|
||||
// Discard this LetNonRec by replacing it with its ret_expr.
|
||||
return from_can(env, ret_expr.value, procs, None);
|
||||
@ -177,11 +189,12 @@ fn from_can<'a>(
|
||||
Expr::Store(stored.into_bump_slice(), arena.alloc(ret))
|
||||
}
|
||||
|
||||
Closure(_, _symbol, _, loc_args, boxed_body) => {
|
||||
Closure(_, _, _, loc_args, boxed_body) => {
|
||||
let (loc_body, ret_var) = *boxed_body;
|
||||
let name = name.unwrap_or_else(|| gen_closure_name(procs));
|
||||
let symbol =
|
||||
name.unwrap_or_else(|| gen_closure_name(procs, &mut env.ident_ids, env.home));
|
||||
|
||||
add_closure(env, name, loc_body.value, ret_var, &loc_args, procs)
|
||||
add_closure(env, symbol, loc_body.value, ret_var, &loc_args, procs)
|
||||
}
|
||||
|
||||
Call(boxed, loc_args, _) => {
|
||||
@ -279,8 +292,8 @@ fn from_can<'a>(
|
||||
}
|
||||
|
||||
fn add_closure<'a>(
|
||||
env: &Env<'a>,
|
||||
name: InlinableString,
|
||||
env: &mut Env<'a, '_>,
|
||||
symbol: Symbol,
|
||||
can_body: can::expr::Expr,
|
||||
ret_var: Variable,
|
||||
loc_args: &[(Variable, Located<Pattern>)],
|
||||
@ -297,14 +310,14 @@ fn add_closure<'a>(
|
||||
Ok(layout) => layout,
|
||||
Err(()) => {
|
||||
// Invalid closure!
|
||||
procs.insert(name.clone(), None);
|
||||
procs.insert(symbol, None);
|
||||
|
||||
return Expr::FunctionPointer(name);
|
||||
return Expr::FunctionPointer(symbol);
|
||||
}
|
||||
};
|
||||
|
||||
let arg_name: InlinableString = match &loc_arg.value {
|
||||
Pattern::Identifier(symbol) => symbol.emit(),
|
||||
let arg_name: Symbol = match &loc_arg.value {
|
||||
Pattern::Identifier(symbol) => *symbol,
|
||||
_ => {
|
||||
panic!("TODO determine arg_name for pattern {:?}", loc_arg.value);
|
||||
}
|
||||
@ -320,18 +333,18 @@ fn add_closure<'a>(
|
||||
ret_var,
|
||||
};
|
||||
|
||||
procs.insert(name.clone(), Some(proc));
|
||||
procs.insert(symbol, Some(proc));
|
||||
|
||||
Expr::FunctionPointer(name)
|
||||
Expr::FunctionPointer(symbol)
|
||||
}
|
||||
|
||||
fn store_pattern<'a>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a, '_>,
|
||||
can_pat: Pattern,
|
||||
can_expr: can::expr::Expr,
|
||||
var: Variable,
|
||||
procs: &mut Procs<'a>,
|
||||
stored: &mut Vec<'a, (InlinableString, Variable, Expr<'a>)>,
|
||||
stored: &mut Vec<'a, (Symbol, Variable, Expr<'a>)>,
|
||||
) {
|
||||
use crate::can::pattern::Pattern::*;
|
||||
|
||||
@ -349,12 +362,14 @@ fn store_pattern<'a>(
|
||||
// identity 5
|
||||
//
|
||||
match can_pat {
|
||||
Identifier(symbol) => {
|
||||
stored.push((symbol.emit(), var, from_can(env, can_expr, procs, None)))
|
||||
}
|
||||
Identifier(symbol) => stored.push((symbol, var, from_can(env, can_expr, procs, None))),
|
||||
Underscore => {
|
||||
// Since _ is never read, it's safe to reassign it.
|
||||
stored.push(("_".into(), var, from_can(env, can_expr, procs, None)))
|
||||
stored.push((
|
||||
Symbol::UNDERSCORE,
|
||||
var,
|
||||
from_can(env, can_expr, procs, None),
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
panic!("TODO store_pattern for {:?}", can_pat);
|
||||
@ -362,14 +377,14 @@ fn store_pattern<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_closure_name(procs: &Procs<'_>) -> InlinableString {
|
||||
// Give the closure a name like "_0" or "_1".
|
||||
// We know procs.len() will be unique!
|
||||
format!("_{}", procs.len()).into()
|
||||
fn gen_closure_name(procs: &Procs<'_>, ident_ids: &mut IdentIds, home: ModuleId) -> Symbol {
|
||||
let ident_id = ident_ids.add(format!("_{}", procs.len()).into());
|
||||
|
||||
Symbol::new(home, ident_id)
|
||||
}
|
||||
|
||||
fn from_can_when<'a>(
|
||||
env: &Env<'a>,
|
||||
env: &mut Env<'a, '_>,
|
||||
cond_var: Variable,
|
||||
expr_var: Variable,
|
||||
loc_cond: Located<can::expr::Expr>,
|
||||
|
@ -29,7 +29,7 @@ mod test_gen {
|
||||
use roc::crane::build::{declare_proc, define_proc_body, ScopeEntry};
|
||||
use roc::crane::convert::type_from_layout;
|
||||
use roc::infer::infer_expr;
|
||||
use roc::llvm::build::build_proc;
|
||||
use roc::llvm::build::{build_proc, build_proc_header};
|
||||
use roc::llvm::convert::basic_type_from_layout;
|
||||
use roc::mono::expr::Expr;
|
||||
use roc::mono::layout::Layout;
|
||||
@ -45,7 +45,7 @@ mod test_gen {
|
||||
let mut ctx = module.make_context();
|
||||
let mut func_ctx = FunctionBuilderContext::new();
|
||||
|
||||
let CanExprOut { loc_expr, var_store, var, constraint, .. } = can_expr($src);
|
||||
let CanExprOut { loc_expr, var_store, var, constraint, home, interns, .. } = can_expr($src);
|
||||
let subs = Subs::new(var_store.into());
|
||||
let mut unify_problems = Vec::new();
|
||||
let (content, solved) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||
@ -75,14 +75,20 @@ mod test_gen {
|
||||
|
||||
// Compile and add all the Procs before adding main
|
||||
let mut procs = MutMap::default();
|
||||
let env = roc::crane::build::Env {
|
||||
let mut env = roc::crane::build::Env {
|
||||
arena: &arena,
|
||||
subs,
|
||||
interns,
|
||||
cfg,
|
||||
};
|
||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||
|
||||
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
||||
let mono_expr = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs);
|
||||
let mono_expr = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
||||
|
||||
// Put this module's ident_ids back in the interns
|
||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||
|
||||
let mut scope = ImMap::default();
|
||||
let mut declared = Vec::with_capacity(procs.len());
|
||||
|
||||
@ -172,7 +178,7 @@ mod test_gen {
|
||||
macro_rules! assert_llvm_evals_to {
|
||||
($src:expr, $expected:expr, $ty:ty) => {
|
||||
let arena = Bump::new();
|
||||
let CanExprOut { loc_expr, var_store, var, constraint, .. } = can_expr($src);
|
||||
let CanExprOut { loc_expr, var_store, var, constraint, home, interns, .. } = can_expr($src);
|
||||
let subs = Subs::new(var_store.into());
|
||||
let mut unify_problems = Vec::new();
|
||||
let (content, solved) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||
@ -207,33 +213,49 @@ mod test_gen {
|
||||
let main_fn_name = "$Test.main";
|
||||
|
||||
// Compile and add all the Procs before adding main
|
||||
let mut procs = MutMap::default();
|
||||
let env = roc::llvm::build::Env {
|
||||
let mut env = roc::llvm::build::Env {
|
||||
arena: &arena,
|
||||
subs,
|
||||
builder: &builder,
|
||||
context: &context,
|
||||
interns,
|
||||
module: arena.alloc(module),
|
||||
};
|
||||
let mut procs = MutMap::default();
|
||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||
|
||||
// Populate Procs and get the low-level Expr from the canonical Expr
|
||||
let main_body = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs);
|
||||
let main_body = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, &mut ident_ids);
|
||||
|
||||
// Add all the Procs to the module
|
||||
for (name, opt_proc) in procs.clone() {
|
||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||
|
||||
let mut headers = Vec::with_capacity(procs.len());
|
||||
|
||||
// Add all the Proc headers to the module.
|
||||
// We have to do this in a separate pass first,
|
||||
// because their bodies may reference each other.
|
||||
for (symbol, opt_proc) in procs.clone().into_iter() {
|
||||
if let Some(proc) = opt_proc {
|
||||
// NOTE: This is here to be uncommented in case verification fails.
|
||||
// (This approach means we don't have to defensively clone name here.)
|
||||
//
|
||||
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
||||
let fn_val = build_proc(&env, name, proc, &procs);
|
||||
let (fn_val, arg_basic_types) = build_proc_header(&env, symbol, &proc);
|
||||
|
||||
if fn_val.verify(true) {
|
||||
fpm.run_on(&fn_val);
|
||||
} else {
|
||||
// NOTE: If this fails, uncomment the above println to debug.
|
||||
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
||||
}
|
||||
headers.push((proc, fn_val, arg_basic_types));
|
||||
}
|
||||
}
|
||||
|
||||
// Build each proc using its header info.
|
||||
for (proc, fn_val, arg_basic_types) in headers {
|
||||
// NOTE: This is here to be uncommented in case verification fails.
|
||||
// (This approach means we don't have to defensively clone name here.)
|
||||
//
|
||||
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
||||
build_proc(&env, proc, &procs, fn_val, arg_basic_types);
|
||||
|
||||
if fn_val.verify(true) {
|
||||
fpm.run_on(&fn_val);
|
||||
} else {
|
||||
// NOTE: If this fails, uncomment the above println to debug.
|
||||
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user