fix compilation: insert procedures at front, ltvm: use 0 as default entrypoint

This commit is contained in:
Michael Sippel 2024-10-18 21:22:56 +02:00
parent 5c2a610d31
commit 6b577e91f8
Signed by: senvas
GPG key ID: F96CF119C34B64A6
4 changed files with 126 additions and 135 deletions

View file

@ -20,7 +20,12 @@ pub struct ProcedureCompiler {
proc_symbol: String, proc_symbol: String,
scope: Arc<RwLock<Scope>>, scope: Arc<RwLock<Scope>>,
asm: tisc::Assembler, asm: tisc::Assembler,
subroutines: Vec<tisc::assembler::AssemblyWord>, subroutine_count: u32,
frame_size: u32,
in_types: Vec< laddertypes::TypeTerm >,
out_types: Vec< laddertypes::TypeTerm >,
pub linker: tisc::Linker, pub linker: tisc::Linker,
pub diagnostics: Vec<( InputRegionTag, String )> pub diagnostics: Vec<( InputRegionTag, String )>
} }
@ -30,48 +35,36 @@ impl ProcedureCompiler {
ProcedureCompiler { ProcedureCompiler {
proc_symbol, proc_symbol,
scope, scope,
subroutines: Vec::new(), subroutine_count: 0,
frame_size: 0,
in_types: vec![],
out_types: vec![],
asm: tisc::Assembler::new(), asm: tisc::Assembler::new(),
linker: tisc::Linker::new(), linker: tisc::Linker::new(),
diagnostics: Vec::new() diagnostics: Vec::new()
} }
} }
/*
pub fn export_symbols(&self) -> Vec<(String, SymbolDef)> { pub fn make_subroutine_symbol(&mut self) -> String {
let mut scope = self.scope.write().unwrap(); let id = self.subroutine_count;
scope.update_link_addresses(&self.proc_symbol, &self.linker); self.subroutine_count += 1;
scope.export() format!("__{}_sub_{}__", self.proc_symbol, id)
} }
*/
pub fn get_bytecode(mut self, ret: bool) -> ( pub fn get_bytecode(mut self) -> (
Vec<(String, SymbolDef)>, Vec<(String, SymbolDef)>,
Vec<tisc::assembler::AssemblyWord> Vec<tisc::assembler::AssemblyWord>
) { ) {
let frame_size = self.scope.read().unwrap().get_frame_size(); if self.frame_size > 0 {
if frame_size > 0 {
let alloc_asm = tisc::Assembler::new() let alloc_asm = tisc::Assembler::new()
.lit(frame_size as tisc::VM_Word).call("data-frame-alloc"); .lit(self.frame_size as tisc::VM_Word).call("data-frame-alloc");
let drop_asm = tisc::Assembler::new() let drop_asm = tisc::Assembler::new()
.lit(frame_size as tisc::VM_Word).call("data-frame-drop"); .lit(self.frame_size as tisc::VM_Word).call("data-frame-drop");
self.asm = alloc_asm.join( self.asm ).join( drop_asm ); self.asm = alloc_asm.join( self.asm ).join( drop_asm );
} }
let main_section = self.asm.build(); self.linker.add_procedure_front( &self.proc_symbol, self.asm.build() );
//self.linker.add_procedure( &self.proc_symbol, main_section );
// ^--- this would insert the asm section at the end,
// we however need it an the beginning of the bytecode
// insert section at front
self.linker.next_addr += main_section.len() as i64;
for (name,section) in self.linker.symbols.iter_mut() {
section.addr += main_section.len() as i64;
}
self.linker.symbols.insert(
self.proc_symbol.clone(),
tisc::linker::Section { addr: 0, data: main_section }
);
// replace all symbol definitions from subroutines // replace all symbol definitions from subroutines
// with relative LinkAddr`s // with relative LinkAddr`s
@ -80,16 +73,21 @@ impl ProcedureCompiler {
&self.linker &self.linker
); );
let code =
self.linker.link_relative(&self.proc_symbol).expect("link error");
let mut export_symbols = self.scope.read().unwrap().export();
//eprintln!("proc compiler export = {:?}\ncode= {:?}", export_symbols, code);
( (
self.scope.read().unwrap().export(), export_symbols,
self.linker.link_relative( &self.proc_symbol ).expect("link error") code
) )
} }
pub fn compile_statement(mut self, statement: &Statement, enable_export: bool) -> Self { pub fn compile_statement(mut self, statement: &Statement, enable_export: bool) -> Self {
match statement { match statement {
Statement::Assignment { name_region, var_id, val_expr } => { Statement::Assignment { name_region, var_id, val_expr } => {
self = self.compile_expr(val_expr); self = self.compile_expr(val_expr, true);
match self.scope.read().unwrap().get(var_id) { match self.scope.read().unwrap().get(var_id) {
Some(SymbolDef::FrameRef { typ, stack_ref }) => { Some(SymbolDef::FrameRef { typ, stack_ref }) => {
@ -127,35 +125,20 @@ impl ProcedureCompiler {
} => { } => {
let val_type = self.scope.read().unwrap() let val_type = self.scope.read().unwrap()
.get(var_id).unwrap() .get(var_id).unwrap()
.get_type(&mut self.scope.clone()); .get_type(&mut self.scope.clone())
let val_type = val_type.sugar(&mut self.scope.clone()); .sugar(&mut self.scope.clone());
match val_type { match val_type {
laddertypes::SugaredTypeTerm::Func(mut f_types) => { laddertypes::SugaredTypeTerm::Func(mut f_types) => {
let mut c = ProcedureCompiler::new( let mut c =
var_id.clone(), ProcedureCompiler::new(
self.scope.clone() var_id.clone(), self.scope.clone()
); ).compile_expr( val_expr, true );
c = c.compile_expr( val_expr );
self.diagnostics.append(&mut c.diagnostics); self.diagnostics.append(&mut c.diagnostics);
let (symbols,code) = c.get_bytecode( true ); let (symbols,code) = c.get_bytecode();
eprintln!("LET assign compiled {}", var_id);
for (i,l) in tisc::assembler::disassemble( &code ).iter().enumerate() {
eprintln!("{}+{} ... {}", var_id, i, l);
}
self.linker.add_procedure(var_id, code); self.linker.add_procedure(var_id, code);
/*
let out_types = vec![ f_types.pop().unwrap().desugar(&mut self.scope.clone()) ];
let in_types = f_types.into_iter().map(|t| t.desugar(&mut self.scope.clone())).collect();
self.scope.write().unwrap().declare_proc(
var_id.clone(),
in_types,
out_types,
true
);
*/
} }
_ => { _ => {
@ -164,20 +147,27 @@ impl ProcedureCompiler {
var_id: var_id.clone(), var_id: var_id.clone(),
val_expr: val_expr.clone(), val_expr: val_expr.clone(),
}, false); }, false);
self.frame_size += 1;
} }
} }
} }
Statement::Expr(expr) => { Statement::Expr(expr) => {
self = self.compile_expr(expr); self = self.compile_expr(expr, true);
} }
Statement::Return(expr) => { Statement::Return(expr) => {
self = self.compile_expr(expr); self = self.compile_expr(expr, true);
} }
} }
self self
} }
pub fn compile_expr(mut self, expr: &LTExpr) -> Self { pub fn compile_expr(mut self, expr: &LTExpr, call: bool) -> Self {
/*
self.out_types.push(
expr.infer_type( &self.scope ).expect("type error")
);
*/
match expr { match expr {
LTExpr::Symbol { region, typ, symbol } => match self.scope.read().unwrap().get(symbol) { LTExpr::Symbol { region, typ, symbol } => match self.scope.read().unwrap().get(symbol) {
Some(SymbolDef::FrameRef { typ, stack_ref }) => { Some(SymbolDef::FrameRef { typ, stack_ref }) => {
@ -192,7 +182,11 @@ impl ProcedureCompiler {
link_addr, link_addr,
export export
}) => { }) => {
self.asm = self.asm.call_symbol(link_addr); if call {
self.asm = self.asm.call_symbol(link_addr);
} else {
self.asm = self.asm.ref_symbol( link_addr );
}
} }
None => { None => {
self.diagnostics.push( self.diagnostics.push(
@ -210,10 +204,10 @@ impl ProcedureCompiler {
self.asm = self.asm.lit(*val); self.asm = self.asm.lit(*val);
} }
LTExpr::Ascend { region, typ, expr } => { LTExpr::Ascend { region, typ, expr } => {
self = self.compile_expr(expr); self = self.compile_expr(expr, call);
} }
LTExpr::Descend { region, typ, expr } => { LTExpr::Descend { region, typ, expr } => {
self = self.compile_expr(expr); self = self.compile_expr(expr, call);
} }
LTExpr::Branch { LTExpr::Branch {
region, region,
@ -221,14 +215,14 @@ impl ProcedureCompiler {
if_expr, if_expr,
else_expr, else_expr,
} => { } => {
self = self.compile_expr(condition); self = self.compile_expr(condition, true);
let asm = self.asm; let asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
self = self.compile_expr(if_expr); self = self.compile_expr(if_expr, true);
let if_asm = self.asm; let if_asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
self = self.compile_expr(else_expr); self = self.compile_expr(else_expr, true);
let else_asm = self.asm; let else_asm = self.asm;
self.asm = asm; self.asm = asm;
self.asm = self.asm.branch(if_asm, else_asm); self.asm = self.asm.branch(if_asm, else_asm);
@ -237,11 +231,11 @@ impl ProcedureCompiler {
let asm = self.asm; let asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
self = self.compile_expr(condition); self = self.compile_expr(condition, true);
let cond_asm = self.asm; let cond_asm = self.asm;
self.asm = tisc::Assembler::new(); self.asm = tisc::Assembler::new();
self = self.compile_expr(body); self = self.compile_expr(body, true);
let body_asm = self.asm; let body_asm = self.asm;
self.asm = asm; self.asm = asm;
@ -249,22 +243,22 @@ impl ProcedureCompiler {
} }
LTExpr::Application { region, typ, head, body } => { LTExpr::Application { region, typ, head, body } => {
for arg in body.iter().rev() { for arg in body.iter().rev() {
self = self.compile_expr(arg); self = self.compile_expr(arg, false);
} }
self = self.compile_expr(head); self = self.compile_expr(head, true);
} }
LTExpr::Abstraction { region, scope, args, body } => { LTExpr::Abstraction { region, scope, args, body } => {
let mut abs_compiler = ProcedureCompiler::new("__abs__".into(), scope.clone()); let abs_symbol = self.make_subroutine_symbol();
let mut abs_compiler = ProcedureCompiler::new(abs_symbol.clone(), scope.clone());
for (region, arg_name, arg_type) in args.iter() { for (region, arg_name, arg_type) in args.iter() {
match scope.read().unwrap().get(arg_name) { match scope.read().unwrap().get(arg_name) {
Some(SymbolDef::FrameRef{ typ, stack_ref }) => { Some(SymbolDef::FrameRef{ typ, stack_ref }) => {
eprintln!("Arg {} stack ref = {}", arg_name, stack_ref);
// TODO: aknowledge actual size of arguments // TODO: aknowledge actual size of arguments
// let arg_size = typ.get_size() // let arg_size = typ.get_size()
let arg_size = 1; let arg_size = 1;
abs_compiler.frame_size += 1;
for i in 0..arg_size { for i in 0..arg_size {
abs_compiler.asm = abs_compiler.asm abs_compiler.asm = abs_compiler.asm
.lit(stack_ref + i) .lit(stack_ref + i)
@ -280,48 +274,22 @@ impl ProcedureCompiler {
} }
} }
abs_compiler = abs_compiler.compile_expr( body ); abs_compiler = abs_compiler.compile_expr( body, true );
let (abs_symbols, mut abs_code) = abs_compiler.get_bytecode( false ); let (abs_export_symbols, mut abs_code) = abs_compiler.get_bytecode();
self.scope.write().unwrap().import( abs_export_symbols );
for (s,def) in abs_symbols.iter() { self.linker.add_procedure( &abs_symbol, abs_code );
eprintln!("{} = {:?}", s, def); self.asm = self.asm.call( &abs_symbol );
}
for (i, l) in tisc::assembler::disassemble(&abs_code).into_iter().enumerate() {
eprintln!("__abs__+{} .. {}", i, l);
}
self.asm.words.append( &mut abs_code );
/*
self.linker.add_procedure(
"__abs__".into(),
abs_code
);*/
} }
LTExpr::Block { region, scope, statements } => { LTExpr::Block { region, scope, statements } => {
let mut block_compiler = ProcedureCompiler::new( let block_symbol = self.make_subroutine_symbol();
"__block__".into(), let mut block_compiler = ProcedureCompiler::new( block_symbol.clone(), scope.clone() );
scope.clone()
);
for stmnt in statements.iter() { for stmnt in statements.iter() {
block_compiler = block_compiler.compile_statement( stmnt, true ); block_compiler = block_compiler.compile_statement( stmnt, true );
} }
let (block_export_symbols, mut block_code) = block_compiler.get_bytecode();
let (block_symbols, mut block_code) = block_compiler.get_bytecode( true ); self.scope.write().unwrap().import( block_export_symbols );
self.linker.add_procedure( &block_symbol, block_code.clone() );
eprintln!("BLOCK compiler:"); self.asm = self.asm.call( &block_symbol );
for (s,def) in block_symbols.iter() {
eprintln!("{} = {:?}", s, def);
}
for (i,l) in tisc::assembler::disassemble( &block_code ).into_iter().enumerate() {
eprintln!("block+{} .. {}", i, l);
}
self.linker.
self.scope.write().unwrap().import(
block_symbols
);
self.asm.words.append(&mut block_code);
} }
LTExpr::ExportBlock{ region, scope, statements } => { LTExpr::ExportBlock{ region, scope, statements } => {
} }

View file

@ -207,25 +207,39 @@ impl Scope {
linker: &tisc::Linker linker: &tisc::Linker
) { ) {
for (name, def) in self.symbols.iter_mut() { for (name, def) in self.symbols.iter_mut() {
if let Some(offset) = linker.get_link_addr( name ) { match def {
match def { SymbolDef::Procedure {
SymbolDef::Procedure { in_types:_,
in_types:_,out_types:_, out_types:_,
link_addr, link_addr,
export:_ export:_
} => { } => {
if let Some(offset) = linker.get_link_addr( name ) {
eprintln!("update link addr {} @ {} + {}", name, base_symbol, offset);
*link_addr = LinkAddr::Relative{ *link_addr = LinkAddr::Relative{
symbol: base_symbol.clone(), symbol: base_symbol.clone(),
offset offset
}; };
}, } else {
_ => {} match link_addr {
LinkAddr::Relative{ symbol, offset } => {
if let Some(base_symb_offset) = linker.get_link_addr( &symbol ) {
*symbol = base_symbol.clone();
*offset += base_symb_offset;
}
},
_ => {}
}
}
}
_ => {
// TODO: what about StaticRef??
} }
} }
} }
} }
//<><><><><><> //<><><><><><>
pub fn declare_proc_parse( pub fn declare_proc_parse(
@ -258,7 +272,7 @@ impl Scope {
} }
}) })
.collect(), .collect(),
false true
); );
} }

View file

@ -77,9 +77,9 @@ fn main() {
} }
} }
compiler = compiler.compile_expr(&ast); compiler = compiler.compile_expr(&ast, true);
let diagnostics = compiler.diagnostics.clone(); let diagnostics = compiler.diagnostics.clone();
let (exports, proc_code) = compiler.get_bytecode(false); let (exports, proc_code) = compiler.get_bytecode();
for (region, message) in diagnostics { for (region, message) in diagnostics {
crate::diagnostic::print_diagnostic( crate::diagnostic::print_diagnostic(
@ -89,8 +89,7 @@ fn main() {
); );
} }
eprintln!("{} {}\n{}", "Compiled".green(), path.bold(), "---------------".green());
eprintln!("{} {}", "Compiled".green(), path.bold());
for (name, def) in exports.iter() { for (name, def) in exports.iter() {
eprintln!("export {}:", name.yellow().bold()); eprintln!("export {}:", name.yellow().bold());
let mut t = def.get_type(&mut main_scope); let mut t = def.get_type(&mut main_scope);
@ -106,11 +105,12 @@ fn main() {
/* link assembly-program to symbols /* link assembly-program to symbols
*/ */
eprintln!("generated bytecode ({})", proc_code.len() ); linker.add_procedure_front(path.as_str(), proc_code);
for (i,l) in tisc::assembler::disassemble(&proc_code).iter().enumerate() {
eprintln!("{} .... {}", i,l); main_scope.write().unwrap().update_link_addresses(
} &path,
linker.add_procedure(path.as_str(), proc_code); &linker
);
} }
Err( (region, parse_error) ) => { Err( (region, parse_error) ) => {
crate::diagnostic::print_diagnostic( crate::diagnostic::print_diagnostic(
@ -125,6 +125,7 @@ fn main() {
} }
} }
eprintln!("write output file {}", args.output); eprintln!("write output file {}", args.output);
let obj_file = tisc::linker::ObjectFile { let obj_file = tisc::linker::ObjectFile {
symbols: Arc::into_inner(main_scope).unwrap().into_inner().unwrap() symbols: Arc::into_inner(main_scope).unwrap().into_inner().unwrap()
@ -135,12 +136,12 @@ fn main() {
if export { if export {
match link_addr { match link_addr {
tisc::LinkAddr::Absolute(w) => { tisc::LinkAddr::Absolute(w) => {
eprintln!("add symbol {} -> {}", symbol, w); // eprintln!("add symbol {} -> {}", symbol, w);
Some(( symbol, w )) Some(( symbol, w ))
} }
tisc::LinkAddr::Relative{ symbol: b, offset } => { tisc::LinkAddr::Relative{ symbol: b, offset } => {
let addr = linker.get_link_addr(&b).unwrap_or(-1); let addr = linker.get_link_addr(&b).unwrap_or(-1);
eprintln!("relative symbol {} -> {}({})+{}", symbol, b, addr, offset); // eprintln!("relative symbol {} -> {}({})+{}", symbol, b, addr, offset);
Some((symbol, addr + offset )) Some((symbol, addr + offset ))
} }
} }

View file

@ -32,13 +32,21 @@ fn main() {
std::fs::File::open(source_path).expect("Failed to open file") std::fs::File::open(source_path).expect("Failed to open file")
); );
linker.import( source_path, bincode::deserialize_from( input ).expect("") ); let obj_file : tisc::linker::ObjectFile = bincode::deserialize_from( input ).expect("");
for (name, addr) in obj_file.symbols.iter() {
symbols.insert(
name.clone(),
tisc::LinkAddr::Relative{
symbol: source_path.clone(),
offset: *addr
}
);
}
linker.import( source_path, obj_file );
} }
let entry_addr = linker.get_link_addr(&args.entry).unwrap_or(0); let entry_addr = linker.get_link_addr(&args.entry).unwrap_or(0);
/*
.expect(&format!("cant find entry symbol '{}'", args.entry));
*/
let bytecode = linker.link_total().expect("Link error:"); let bytecode = linker.link_total().expect("Link error:");
eprintln!("{} ({} bytes)", "Loaded bytecode.".green(), bytecode.len()); eprintln!("{} ({} bytes)", "Loaded bytecode.".green(), bytecode.len());