Merge pull request #201 from rtfeldman/mono

Use Symbol in `mono::Expr`
This commit is contained in:
Richard Feldman 2020-02-25 01:42:33 -05:00 committed by GitHub
commit c225ccc029
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 179 additions and 139 deletions

View File

@ -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 (&param, (_, arg_name, var)) in builder.ebb_params(block).iter().zip(args) {
for (&param, (_, 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);

View File

@ -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<'_>) {

View File

@ -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

View File

@ -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>,

View File

@ -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!");
}
}