infra for exposed_generic in the dev backend

This commit is contained in:
Folkert 2023-04-30 01:20:58 +02:00
parent 1aeeaed9b7
commit f9f4d5eb49
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
3 changed files with 168 additions and 25 deletions

View file

@ -68,8 +68,17 @@ trait Backend<'a> {
fn interns_mut(&mut self) -> &mut Interns;
fn interner(&self) -> &STLayoutInterner<'a>;
fn interner_mut(&mut self) -> &mut STLayoutInterner<'a> {
self.module_interns_helpers_mut().1
}
fn debug_symbol(&mut self, name: &str) -> Symbol {
let module_id = self.env().module_id;
self.debug_symbol_in(module_id, name)
}
fn debug_symbol_in(&mut self, module_id: ModuleId, name: &str) -> Symbol {
let ident_ids = self
.interns_mut()
.all_ident_ids
@ -77,7 +86,7 @@ trait Backend<'a> {
.unwrap();
let ident_id = ident_ids.add_str(name);
Symbol::new(self.env().module_id, ident_id)
Symbol::new(module_id, ident_id)
}
// This method is suboptimal, but it seems to be the only way to make rust understand
@ -1118,7 +1127,7 @@ trait Backend<'a> {
LowLevel::PtrWrite => {
let element_layout = match self.interner().get(*ret_layout) {
Layout::Boxed(boxed) => boxed,
_ => unreachable!(),
_ => unreachable!("cannot write to {:?}", self.interner().dbg(*ret_layout)),
};
self.build_ptr_write(*sym, args[0], args[1], element_layout);

View file

@ -11,8 +11,9 @@ use roc_collections::all::MutMap;
use roc_error_macros::internal_error;
use roc_module::symbol;
use roc_module::symbol::Interns;
use roc_mono::ir::{Proc, ProcLayout};
use roc_mono::layout::{LayoutIds, STLayoutInterner};
use roc_mono::ir::{Call, CallSpecId, Expr, UpdateModeId};
use roc_mono::ir::{Proc, ProcLayout, Stmt};
use roc_mono::layout::{LambdaName, Layout, LayoutIds, LayoutInterner, STLayoutInterner};
use roc_target::TargetInfo;
use target_lexicon::{Architecture as TargetArch, BinaryFormat as TargetBF, Triple};
@ -238,14 +239,48 @@ fn build_object<'a, B: Backend<'a>>(
// Names and linker data for user procedures
for ((sym, layout), proc) in procedures {
let is_exposed = backend.env().exposed_to_host.contains(&sym);
if is_exposed {
let proc = build_generic_proc(&mut backend, sym, &proc);
#[cfg(debug_assertions)]
{
let module_id = proc.name.name().module_id();
let ident_ids = backend
.interns_mut()
.all_ident_ids
.get_mut(&module_id)
.unwrap();
module_id.register_debug_idents(ident_ids);
}
build_proc_symbol(
&mut output,
&mut layout_ids,
&mut procs,
&mut backend,
proc.name.name(),
layout,
proc,
Exposed::ExposedGeneric,
)
}
build_proc_symbol(
&mut output,
&mut layout_ids,
&mut procs,
&backend,
&mut backend,
sym,
layout,
proc,
if is_exposed {
// Exposed::Exposed
Exposed::NotExposed
} else {
Exposed::NotExposed
},
)
}
@ -350,36 +385,131 @@ fn build_object<'a, B: Backend<'a>>(
output
}
fn build_generic_proc<'a, B: Backend<'a>>(
backend: &mut B,
sym: roc_module::symbol::Symbol,
proc: &Proc<'a>,
) -> Proc<'a> {
let interns = backend.interns();
let ident_string = sym.as_str(interns);
let module_string = interns.module_ids.get_name(sym.module_id()).unwrap();
let fn_name = format!("{}{}", module_string, ident_string);
let platform = sym.module_id();
let generic_proc_name = backend.debug_symbol_in(platform, &fn_name);
let arg_generic = backend.debug_symbol_in(platform, "arg_generic");
let s1 = backend.debug_symbol_in(platform, "s1");
let s2 = backend.debug_symbol_in(platform, "s2");
let s3 = backend.debug_symbol_in(platform, "s3");
let arena = backend.env().arena;
let mut args = bumpalo::collections::Vec::new_in(arena);
let box_layout = backend
.interner_mut()
.insert(roc_mono::layout::Layout::Boxed(proc.ret_layout));
args.extend(proc.args);
args.push((box_layout, arg_generic));
let call_args = bumpalo::collections::Vec::from_iter_in(proc.args.iter().map(|t| t.1), arena);
let call_layouts =
bumpalo::collections::Vec::from_iter_in(proc.args.iter().map(|t| t.0), arena);
let call = Call {
call_type: roc_mono::ir::CallType::ByName {
name: proc.name,
ret_layout: proc.ret_layout,
arg_layouts: call_layouts.into_bump_slice(),
specialization_id: CallSpecId::BACKEND_DUMMY,
},
arguments: call_args.into_bump_slice(),
};
let box_write = Call {
call_type: roc_mono::ir::CallType::LowLevel {
op: roc_module::low_level::LowLevel::PtrWrite,
update_mode: UpdateModeId::BACKEND_DUMMY,
},
arguments: arena.alloc([arg_generic, s1]),
};
let body = Stmt::Let(
s1,
Expr::Call(call),
proc.ret_layout,
arena.alloc(
//
Stmt::Let(
s2,
Expr::Call(box_write),
box_layout,
arena.alloc(
//
Stmt::Let(
s3,
Expr::Struct(&[]),
Layout::UNIT,
arena.alloc(
//
Stmt::Ret(s3),
),
),
),
),
),
);
Proc {
name: LambdaName::no_niche(generic_proc_name),
args: args.into_bump_slice(),
body,
closure_data_layout: None,
ret_layout: roc_mono::layout::Layout::UNIT,
is_self_recursive: roc_mono::ir::SelfRecursive::NotSelfRecursive,
host_exposed_layouts: roc_mono::ir::HostExposedLayouts::NotHostExposed,
}
}
enum Exposed {
ExposedGeneric,
Exposed,
NotExposed,
}
fn build_proc_symbol<'a, B: Backend<'a>>(
output: &mut Object<'a>,
layout_ids: &mut LayoutIds<'a>,
procs: &mut Vec<'a, (String, SectionId, SymbolId, Proc<'a>)>,
backend: &B,
backend: &mut B,
sym: roc_module::symbol::Symbol,
layout: ProcLayout<'a>,
proc: Proc<'a>,
exposed: Exposed,
) {
let base_name = backend.function_symbol_to_string(
sym,
layout.arguments.iter().copied(),
None,
layout.result,
);
let fn_name = if backend.env().exposed_to_host.contains(&sym) {
layout_ids
.get_toplevel(sym, &layout)
.to_exposed_symbol_string(sym, backend.interns())
} else {
base_name
};
let section_id = output.add_section(
output.segment_name(StandardSegment::Text).to_vec(),
format!(".text.{:x}", sym.as_u64()).as_bytes().to_vec(),
SectionKind::Text,
);
let fn_name = match exposed {
Exposed::ExposedGeneric => layout_ids
.get_toplevel(sym, &layout)
.to_exposed_generic_symbol_string(sym, backend.interns()),
Exposed::Exposed => layout_ids
.get_toplevel(sym, &layout)
.to_exposed_symbol_string(sym, backend.interns()),
Exposed::NotExposed => backend.function_symbol_to_string(
sym,
layout.arguments.iter().copied(),
None,
layout.result,
),
};
let proc_symbol = Symbol {
name: fn_name.as_bytes().to_vec(),
value: 0,
@ -387,10 +517,9 @@ fn build_proc_symbol<'a, B: Backend<'a>>(
kind: SymbolKind::Text,
// TODO: Depending on whether we are building a static or dynamic lib, this should change.
// We should use Dynamic -> anyone, Linkage -> static link, Compilation -> this module only.
scope: if backend.env().exposed_to_host.contains(&sym) {
SymbolScope::Dynamic
} else {
SymbolScope::Linkage
scope: match exposed {
Exposed::ExposedGeneric | Exposed::Exposed => SymbolScope::Dynamic,
Exposed::NotExposed => SymbolScope::Linkage,
},
weak: false,
section: SymbolSection::Section(section_id),