mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 16:51:53 +03:00
Remove an accidentally gen-dev addition
This commit is contained in:
parent
1960f429bd
commit
cde83e9078
@ -1728,822 +1728,6 @@ impl<
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_to_string(&self, symbol: Symbol, layout_id: roc_mono::layout::LayoutId) -> String {
|
||||
layout_id.to_symbol_string(symbol, self.interns())
|
||||
}
|
||||
|
||||
fn defined_in_app_module(&self, symbol: Symbol) -> bool {
|
||||
symbol
|
||||
.module_string(self.interns())
|
||||
.starts_with(roc_module::ident::ModuleName::APP)
|
||||
}
|
||||
|
||||
fn build_proc(
|
||||
&mut self,
|
||||
proc: roc_mono::ir::Proc<'a>,
|
||||
layout_ids: &mut roc_mono::layout::LayoutIds<'a>,
|
||||
) -> (Vec<u8>, Vec<Relocation>, Vec<'a, (Symbol, String)>) {
|
||||
let layout_id = layout_ids.get(proc.name.name(), &proc.ret_layout);
|
||||
let proc_name = self.symbol_to_string(proc.name.name(), layout_id);
|
||||
self.reset(proc_name, proc.is_self_recursive);
|
||||
self.load_args(proc.args, &proc.ret_layout);
|
||||
for (layout, sym) in proc.args {
|
||||
self.set_layout_map(*sym, layout);
|
||||
}
|
||||
self.scan_ast(&proc.body);
|
||||
self.create_free_map();
|
||||
self.build_stmt(&proc.body, &proc.ret_layout);
|
||||
let mut helper_proc_names = bumpalo::vec![in self.env().arena];
|
||||
helper_proc_names.reserve(self.helper_proc_symbols().len());
|
||||
for (rc_proc_sym, rc_proc_layout) in self.helper_proc_symbols() {
|
||||
let name = layout_ids
|
||||
.get_toplevel(*rc_proc_sym, rc_proc_layout)
|
||||
.to_symbol_string(*rc_proc_sym, self.interns());
|
||||
|
||||
helper_proc_names.push((*rc_proc_sym, name));
|
||||
}
|
||||
let (bytes, relocs) = self.finalize();
|
||||
(bytes, relocs, helper_proc_names)
|
||||
}
|
||||
|
||||
fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &roc_mono::layout::InLayout<'a>) {
|
||||
match stmt {
|
||||
Stmt::Let(sym, expr, layout, following) => {
|
||||
self.build_expr(sym, expr, layout);
|
||||
self.set_layout_map(*sym, layout);
|
||||
self.free_symbols(stmt);
|
||||
self.build_stmt(following, ret_layout);
|
||||
}
|
||||
Stmt::Ret(sym) => {
|
||||
self.load_literal_symbols(&[*sym]);
|
||||
self.return_symbol(sym, ret_layout);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
Stmt::Refcounting(modify, following) => {
|
||||
let sym = modify.get_symbol();
|
||||
let layout = *self.layout_map().get(&sym).unwrap();
|
||||
|
||||
// Expand the Refcounting statement into more detailed IR with a function call
|
||||
// If this layout requires a new RC proc, we get enough info to create a linker symbol
|
||||
// for it. Here we don't create linker symbols at this time, but in Wasm backend, we do.
|
||||
let (rc_stmt, new_specializations) = {
|
||||
let (module_id, layout_interner, interns, rc_proc_gen) =
|
||||
self.module_interns_helpers_mut();
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
|
||||
|
||||
rc_proc_gen.expand_refcount_stmt(
|
||||
ident_ids,
|
||||
layout_interner,
|
||||
layout,
|
||||
modify,
|
||||
following,
|
||||
)
|
||||
};
|
||||
|
||||
for spec in new_specializations.into_iter() {
|
||||
self.helper_proc_symbols_mut().push(spec);
|
||||
}
|
||||
|
||||
self.build_stmt(rc_stmt, ret_layout)
|
||||
}
|
||||
Stmt::Switch {
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout,
|
||||
} => {
|
||||
self.load_literal_symbols(&[*cond_symbol]);
|
||||
self.build_switch(
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout,
|
||||
);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
Stmt::Join {
|
||||
id,
|
||||
parameters,
|
||||
body,
|
||||
remainder,
|
||||
} => {
|
||||
for param in parameters.iter() {
|
||||
self.set_layout_map(param.symbol, ¶m.layout);
|
||||
}
|
||||
self.build_join(id, parameters, body, remainder, ret_layout);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
Stmt::Jump(id, args) => {
|
||||
let mut arg_layouts: bumpalo::collections::Vec<roc_mono::layout::InLayout<'a>> =
|
||||
bumpalo::vec![in self.env().arena];
|
||||
arg_layouts.reserve(args.len());
|
||||
let layout_map = self.layout_map();
|
||||
for arg in *args {
|
||||
if let Some(layout) = layout_map.get(arg) {
|
||||
arg_layouts.push(*layout);
|
||||
} else {
|
||||
internal_error!("the argument, {:?}, has no know layout", arg);
|
||||
}
|
||||
}
|
||||
self.build_jump(id, args, arg_layouts.into_bump_slice(), ret_layout);
|
||||
self.free_symbols(stmt);
|
||||
}
|
||||
x => todo!("the statement, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_expr(
|
||||
&mut self,
|
||||
sym: &Symbol,
|
||||
expr: &roc_mono::ir::Expr<'a>,
|
||||
layout: &roc_mono::layout::InLayout<'a>,
|
||||
) {
|
||||
match expr {
|
||||
roc_mono::ir::Expr::Literal(lit) => {
|
||||
if self.env().lazy_literals {
|
||||
self.literal_map().insert(*sym, (lit, layout));
|
||||
} else {
|
||||
self.load_literal(sym, layout, lit);
|
||||
}
|
||||
}
|
||||
roc_mono::ir::Expr::Call(roc_mono::ir::Call {
|
||||
call_type,
|
||||
arguments,
|
||||
}) => {
|
||||
match call_type {
|
||||
roc_mono::ir::CallType::ByName {
|
||||
name: func_sym,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
..
|
||||
} => {
|
||||
if let roc_module::low_level::LowLevelWrapperType::CanBeReplacedBy(
|
||||
lowlevel,
|
||||
) =
|
||||
roc_module::low_level::LowLevelWrapperType::from_symbol(func_sym.name())
|
||||
{
|
||||
self.build_run_low_level(
|
||||
sym,
|
||||
&lowlevel,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
)
|
||||
} else if self.defined_in_app_module(func_sym.name()) {
|
||||
let layout_id =
|
||||
roc_mono::layout::LayoutIds::default().get(func_sym.name(), layout);
|
||||
let fn_name = self.symbol_to_string(func_sym.name(), layout_id);
|
||||
// Now that the arguments are needed, load them if they are literals.
|
||||
self.load_literal_symbols(arguments);
|
||||
self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout)
|
||||
} else {
|
||||
self.build_builtin(
|
||||
sym,
|
||||
func_sym.name(),
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
roc_mono::ir::CallType::LowLevel { op: lowlevel, .. } => {
|
||||
let mut arg_layouts: bumpalo::collections::Vec<
|
||||
roc_mono::layout::InLayout<'a>,
|
||||
> = bumpalo::vec![in self.env().arena];
|
||||
arg_layouts.reserve(arguments.len());
|
||||
let layout_map = self.layout_map();
|
||||
for arg in *arguments {
|
||||
if let Some(layout) = layout_map.get(arg) {
|
||||
arg_layouts.push(*layout);
|
||||
} else {
|
||||
internal_error!("the argument, {:?}, has no know layout", arg);
|
||||
}
|
||||
}
|
||||
self.build_run_low_level(
|
||||
sym,
|
||||
lowlevel,
|
||||
arguments,
|
||||
arg_layouts.into_bump_slice(),
|
||||
layout,
|
||||
)
|
||||
}
|
||||
x => todo!("the call type, {:?}", x),
|
||||
}
|
||||
}
|
||||
roc_mono::ir::Expr::EmptyArray => {
|
||||
self.create_empty_array(sym);
|
||||
}
|
||||
roc_mono::ir::Expr::Array { elem_layout, elems } => {
|
||||
let mut syms = bumpalo::vec![in self.env().arena];
|
||||
for sym in elems.iter().filter_map(|x| match x {
|
||||
ListLiteralElement::Symbol(sym) => Some(sym),
|
||||
_ => None,
|
||||
}) {
|
||||
syms.push(*sym);
|
||||
}
|
||||
// TODO: This could be a huge waste.
|
||||
// We probably want to call this within create_array, one element at a time.
|
||||
self.load_literal_symbols(syms.into_bump_slice());
|
||||
self.create_array(sym, elem_layout, elems);
|
||||
}
|
||||
roc_mono::ir::Expr::Struct(fields) => {
|
||||
self.load_literal_symbols(fields);
|
||||
self.create_struct(sym, layout, fields);
|
||||
}
|
||||
roc_mono::ir::Expr::StructAtIndex {
|
||||
index,
|
||||
field_layouts,
|
||||
structure,
|
||||
} => {
|
||||
self.load_struct_at_index(sym, structure, *index, field_layouts);
|
||||
}
|
||||
roc_mono::ir::Expr::UnionAtIndex {
|
||||
structure,
|
||||
tag_id,
|
||||
union_layout,
|
||||
index,
|
||||
} => {
|
||||
self.load_union_at_index(sym, structure, *tag_id, *index, union_layout);
|
||||
}
|
||||
roc_mono::ir::Expr::GetTagId {
|
||||
structure,
|
||||
union_layout,
|
||||
} => {
|
||||
self.get_tag_id(sym, structure, union_layout);
|
||||
}
|
||||
roc_mono::ir::Expr::Tag {
|
||||
tag_layout,
|
||||
tag_id,
|
||||
arguments,
|
||||
..
|
||||
} => {
|
||||
self.load_literal_symbols(arguments);
|
||||
self.tag(sym, arguments, tag_layout, *tag_id);
|
||||
}
|
||||
x => todo!("the expression, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_run_low_level(
|
||||
&mut self,
|
||||
sym: &Symbol,
|
||||
lowlevel: &roc_module::low_level::LowLevel,
|
||||
args: &'a [Symbol],
|
||||
arg_layouts: &[roc_mono::layout::InLayout<'a>],
|
||||
ret_layout: &roc_mono::layout::InLayout<'a>,
|
||||
) {
|
||||
// Now that the arguments are needed, load them if they are literals.
|
||||
self.load_literal_symbols(args);
|
||||
match lowlevel {
|
||||
roc_module::low_level::LowLevel::NumAbs => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
args.len(),
|
||||
"NumAbs: expected to have exactly one argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], *ret_layout,
|
||||
"NumAbs: expected to have the same argument and return layout"
|
||||
);
|
||||
self.build_num_abs(sym, &args[0], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumAdd => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NumAdd: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NumAdd: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], *ret_layout,
|
||||
"NumAdd: expected to have the same argument and return layout"
|
||||
);
|
||||
self.build_num_add(sym, &args[0], &args[1], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumAddChecked => {
|
||||
self.build_num_add_checked(sym, &args[0], &args[1], &arg_layouts[0], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumAcos => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::NUM_ACOS[FloatWidth::F64].to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
roc_module::low_level::LowLevel::NumAsin => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::NUM_ASIN[FloatWidth::F64].to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
roc_module::low_level::LowLevel::NumAtan => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::NUM_ATAN[FloatWidth::F64].to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
roc_module::low_level::LowLevel::NumMul => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NumMul: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NumMul: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], *ret_layout,
|
||||
"NumMul: expected to have the same argument and return layout"
|
||||
);
|
||||
self.build_num_mul(sym, &args[0], &args[1], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumDivTruncUnchecked
|
||||
| roc_module::low_level::LowLevel::NumDivFrac => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NumDiv: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NumDiv: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], *ret_layout,
|
||||
"NumDiv: expected to have the same argument and return layout"
|
||||
);
|
||||
self.build_num_div(sym, &args[0], &args[1], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumNeg => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
args.len(),
|
||||
"NumNeg: expected to have exactly one argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], *ret_layout,
|
||||
"NumNeg: expected to have the same argument and return layout"
|
||||
);
|
||||
self.build_num_neg(sym, &args[0], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumPowInt => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::NUM_POW_INT[IntWidth::I64].to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
roc_module::low_level::LowLevel::NumSub => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NumSub: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NumSub: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], *ret_layout,
|
||||
"NumSub: expected to have the same argument and return layout"
|
||||
);
|
||||
self.build_num_sub(sym, &args[0], &args[1], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumBitwiseAnd => {
|
||||
if let Layout::Builtin(Builtin::Int(int_width)) = self.interner().get(*ret_layout) {
|
||||
self.build_int_bitwise_and(sym, &args[0], &args[1], int_width)
|
||||
} else {
|
||||
internal_error!("bitwise and on a non-integer")
|
||||
}
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumBitwiseOr => {
|
||||
if let Layout::Builtin(Builtin::Int(int_width)) = self.interner().get(*ret_layout) {
|
||||
self.build_int_bitwise_or(sym, &args[0], &args[1], int_width)
|
||||
} else {
|
||||
internal_error!("bitwise or on a non-integer")
|
||||
}
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumBitwiseXor => {
|
||||
if let Layout::Builtin(Builtin::Int(int_width)) = self.interner().get(*ret_layout) {
|
||||
self.build_int_bitwise_xor(sym, &args[0], &args[1], int_width)
|
||||
} else {
|
||||
internal_error!("bitwise xor on a non-integer")
|
||||
}
|
||||
}
|
||||
roc_module::low_level::LowLevel::Eq => {
|
||||
debug_assert_eq!(2, args.len(), "Eq: expected to have exactly two argument");
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"Eq: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::BOOL,
|
||||
*ret_layout,
|
||||
"Eq: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_eq(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
roc_module::low_level::LowLevel::NotEq => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NotEq: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NotEq: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::BOOL,
|
||||
*ret_layout,
|
||||
"NotEq: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_neq(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumLt => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NumLt: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NumLt: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::BOOL,
|
||||
*ret_layout,
|
||||
"NumLt: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_num_lt(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumToFrac => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
args.len(),
|
||||
"NumToFrac: expected to have exactly one argument"
|
||||
);
|
||||
|
||||
debug_assert!(
|
||||
matches!(*ret_layout, Layout::F32 | Layout::F64),
|
||||
"NumToFrac: expected to have return layout of type Float"
|
||||
);
|
||||
self.build_num_to_frac(sym, &args[0], &arg_layouts[0], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumLte => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NumLte: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NumLte: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::BOOL,
|
||||
*ret_layout,
|
||||
"NumLte: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_num_lte(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumGte => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"NumGte: expected to have exactly two argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
arg_layouts[0], arg_layouts[1],
|
||||
"NumGte: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::BOOL,
|
||||
*ret_layout,
|
||||
"NumGte: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_num_gte(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
roc_module::low_level::LowLevel::NumRound => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::NUM_ROUND_F64[IntWidth::I64].to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
roc_module::low_level::LowLevel::ListLen => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
args.len(),
|
||||
"ListLen: expected to have exactly one argument"
|
||||
);
|
||||
self.build_list_len(sym, &args[0])
|
||||
}
|
||||
roc_module::low_level::LowLevel::ListGetUnsafe => {
|
||||
debug_assert_eq!(
|
||||
2,
|
||||
args.len(),
|
||||
"ListGetUnsafe: expected to have exactly two arguments"
|
||||
);
|
||||
self.build_list_get_unsafe(sym, &args[0], &args[1], ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::ListReplaceUnsafe => {
|
||||
debug_assert_eq!(
|
||||
3,
|
||||
args.len(),
|
||||
"ListReplaceUnsafe: expected to have exactly three arguments"
|
||||
);
|
||||
self.build_list_replace_unsafe(sym, args, arg_layouts, ret_layout)
|
||||
}
|
||||
roc_module::low_level::LowLevel::StrConcat => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::STR_CONCAT.to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
roc_module::low_level::LowLevel::PtrCast => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
args.len(),
|
||||
"RefCountGetPtr: expected to have exactly one argument"
|
||||
);
|
||||
self.build_ptr_cast(sym, &args[0])
|
||||
}
|
||||
roc_module::low_level::LowLevel::RefCountDec => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::UTILS_DECREF.to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
roc_module::low_level::LowLevel::RefCountInc => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::UTILS_INCREF.to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
x => todo!("low level, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_builtin(
|
||||
&mut self,
|
||||
sym: &Symbol,
|
||||
func_sym: Symbol,
|
||||
args: &'a [Symbol],
|
||||
arg_layouts: &[roc_mono::layout::InLayout<'a>],
|
||||
ret_layout: &roc_mono::layout::InLayout<'a>,
|
||||
) {
|
||||
self.load_literal_symbols(args);
|
||||
match func_sym {
|
||||
Symbol::NUM_IS_ZERO => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
args.len(),
|
||||
"NumIsZero: expected to have exactly one argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::BOOL,
|
||||
*ret_layout,
|
||||
"NumIsZero: expected to have return layout of type Bool"
|
||||
);
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP,
|
||||
&arg_layouts[0],
|
||||
&Literal::Int(0i128.to_ne_bytes()),
|
||||
);
|
||||
self.build_eq(sym, &args[0], &Symbol::DEV_TMP, &arg_layouts[0]);
|
||||
self.free_symbol(&Symbol::DEV_TMP)
|
||||
}
|
||||
Symbol::LIST_GET | Symbol::LIST_SET | Symbol::LIST_REPLACE => {
|
||||
// TODO: This is probably simple enough to be worth inlining.
|
||||
let layout_id = roc_mono::layout::LayoutIds::default().get(func_sym, ret_layout);
|
||||
let fn_name = self.symbol_to_string(func_sym, layout_id);
|
||||
// Now that the arguments are needed, load them if they are literals.
|
||||
self.load_literal_symbols(args);
|
||||
self.build_fn_call(sym, fn_name, args, arg_layouts, ret_layout)
|
||||
}
|
||||
Symbol::NUM_ADD_CHECKED => {
|
||||
let layout_id = roc_mono::layout::LayoutIds::default().get(func_sym, ret_layout);
|
||||
let fn_name = self.symbol_to_string(func_sym, layout_id);
|
||||
// Now that the arguments are needed, load them if they are literals.
|
||||
self.load_literal_symbols(args);
|
||||
self.build_fn_call(sym, fn_name, args, arg_layouts, ret_layout)
|
||||
}
|
||||
Symbol::BOOL_TRUE => {
|
||||
let bool_layout = Layout::BOOL;
|
||||
self.load_literal(&Symbol::DEV_TMP, &bool_layout, &Literal::Bool(true));
|
||||
self.return_symbol(&Symbol::DEV_TMP, &bool_layout);
|
||||
}
|
||||
Symbol::BOOL_FALSE => {
|
||||
let bool_layout = Layout::BOOL;
|
||||
self.load_literal(&Symbol::DEV_TMP, &bool_layout, &Literal::Bool(false));
|
||||
self.return_symbol(&Symbol::DEV_TMP, &bool_layout);
|
||||
}
|
||||
_ => todo!("the function, {:?}", func_sym),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_literal_symbols(&mut self, syms: &[Symbol]) {
|
||||
if self.env().lazy_literals {
|
||||
for sym in syms {
|
||||
if let Some((lit, layout)) = self.literal_map().remove(sym) {
|
||||
// This operation is always safe but complicates lifetimes.
|
||||
// The map is reset when building a procedure and then used for that single procedure.
|
||||
// Since the lifetime is shorter than the entire backend, we need to use a pointer.
|
||||
let (lit, layout) = unsafe { (*lit, *layout) };
|
||||
self.load_literal(sym, &layout, &lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn free_symbols(&mut self, stmt: &Stmt<'a>) {
|
||||
if let Some(syms) = self.free_map().remove(&(stmt as *const Stmt<'a>)) {
|
||||
for sym in syms {
|
||||
// println!("Freeing symbol: {:?}", sym);
|
||||
self.free_symbol(&sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_last_seen(&mut self, sym: Symbol, stmt: &Stmt<'a>) {
|
||||
self.last_seen_map().insert(sym, stmt);
|
||||
}
|
||||
|
||||
fn set_layout_map(&mut self, sym: Symbol, layout: &roc_mono::layout::InLayout<'a>) {
|
||||
if let Some(old_layout) = self.layout_map().insert(sym, *layout) {
|
||||
// Layout map already contains the symbol. We should never need to overwrite.
|
||||
// If the layout is not the same, that is a bug.
|
||||
if &old_layout != layout {
|
||||
internal_error!(
|
||||
"Overwriting layout for symbol, {:?}: got {:?}, want {:?}",
|
||||
sym,
|
||||
layout,
|
||||
old_layout
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_free_map(&mut self) {
|
||||
let mut free_map = MutMap::default();
|
||||
let arena = self.env().arena;
|
||||
for (sym, stmt) in self.last_seen_map() {
|
||||
let vals = free_map
|
||||
.entry(*stmt)
|
||||
.or_insert_with(|| bumpalo::vec![in arena]);
|
||||
vals.push(*sym);
|
||||
}
|
||||
self.set_free_map(free_map);
|
||||
}
|
||||
|
||||
fn scan_ast(&mut self, stmt: &Stmt<'a>) {
|
||||
// Join map keeps track of join point parameters so that we can keep them around while they still might be jumped to.
|
||||
let mut join_map: MutMap<JoinPointId, &'a [Param<'a>]> = MutMap::default();
|
||||
match stmt {
|
||||
Stmt::Let(sym, expr, _, following) => {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
match expr {
|
||||
roc_mono::ir::Expr::Literal(_) => {}
|
||||
|
||||
roc_mono::ir::Expr::Call(call) => self.scan_ast_call(call, stmt),
|
||||
|
||||
roc_mono::ir::Expr::Tag { arguments, .. } => {
|
||||
for sym in *arguments {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
}
|
||||
roc_mono::ir::Expr::ExprBox { symbol } => {
|
||||
self.set_last_seen(*symbol, stmt);
|
||||
}
|
||||
roc_mono::ir::Expr::ExprUnbox { symbol } => {
|
||||
self.set_last_seen(*symbol, stmt);
|
||||
}
|
||||
roc_mono::ir::Expr::Struct(syms) => {
|
||||
for sym in *syms {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
}
|
||||
roc_mono::ir::Expr::StructAtIndex { structure, .. } => {
|
||||
self.set_last_seen(*structure, stmt);
|
||||
}
|
||||
roc_mono::ir::Expr::GetTagId { structure, .. } => {
|
||||
self.set_last_seen(*structure, stmt);
|
||||
}
|
||||
roc_mono::ir::Expr::UnionAtIndex { structure, .. } => {
|
||||
self.set_last_seen(*structure, stmt);
|
||||
}
|
||||
roc_mono::ir::Expr::Array { elems, .. } => {
|
||||
for elem in *elems {
|
||||
if let ListLiteralElement::Symbol(sym) = elem {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
roc_mono::ir::Expr::Reuse {
|
||||
symbol, arguments, ..
|
||||
} => {
|
||||
self.set_last_seen(*symbol, stmt);
|
||||
for sym in *arguments {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
}
|
||||
roc_mono::ir::Expr::Reset { symbol, .. } => {
|
||||
self.set_last_seen(*symbol, stmt);
|
||||
}
|
||||
roc_mono::ir::Expr::EmptyArray => {}
|
||||
roc_mono::ir::Expr::RuntimeErrorFunction(_) => {}
|
||||
}
|
||||
self.scan_ast(following);
|
||||
}
|
||||
|
||||
Stmt::Switch {
|
||||
cond_symbol,
|
||||
branches,
|
||||
default_branch,
|
||||
..
|
||||
} => {
|
||||
self.set_last_seen(*cond_symbol, stmt);
|
||||
for (_, _, branch) in *branches {
|
||||
self.scan_ast(branch);
|
||||
}
|
||||
self.scan_ast(default_branch.1);
|
||||
}
|
||||
Stmt::Ret(sym) => {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
Stmt::Refcounting(modify, following) => {
|
||||
let sym = modify.get_symbol();
|
||||
|
||||
self.set_last_seen(sym, stmt);
|
||||
self.scan_ast(following);
|
||||
}
|
||||
Stmt::Join {
|
||||
parameters,
|
||||
body: continuation,
|
||||
remainder,
|
||||
id: JoinPointId(sym),
|
||||
..
|
||||
} => {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
join_map.insert(JoinPointId(*sym), parameters);
|
||||
for param in *parameters {
|
||||
self.set_last_seen(param.symbol, stmt);
|
||||
}
|
||||
self.scan_ast(remainder);
|
||||
self.scan_ast(continuation);
|
||||
}
|
||||
Stmt::Jump(JoinPointId(sym), symbols) => {
|
||||
if let Some(parameters) = join_map.get(&JoinPointId(*sym)) {
|
||||
// Keep the parameters around. They will be overwritten when jumping.
|
||||
for param in *parameters {
|
||||
self.set_last_seen(param.symbol, stmt);
|
||||
}
|
||||
}
|
||||
for sym in *symbols {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
Stmt::Dbg { .. } => todo!("dbg not implemented in the dev backend"),
|
||||
Stmt::Expect { .. } => todo!("expect is not implemented in the dev backend"),
|
||||
Stmt::ExpectFx { .. } => todo!("expect-fx is not implemented in the dev backend"),
|
||||
|
||||
Stmt::Crash(..) => todo!("crash is not implemented in the dev backend"),
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_ast_call(&mut self, call: &roc_mono::ir::Call, stmt: &roc_mono::ir::Stmt<'a>) {
|
||||
let roc_mono::ir::Call {
|
||||
call_type,
|
||||
arguments,
|
||||
} = call;
|
||||
|
||||
for sym in *arguments {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
|
||||
match call_type {
|
||||
roc_mono::ir::CallType::ByName { .. } => {}
|
||||
roc_mono::ir::CallType::LowLevel { .. } => {}
|
||||
roc_mono::ir::CallType::HigherOrder { .. } => {}
|
||||
roc_mono::ir::CallType::Foreign { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This impl block is for ir related instructions that need backend specific information.
|
||||
|
Loading…
Reference in New Issue
Block a user