Add a block garbage-collector that will delete an unused block at end

This commit is contained in:
Sofia 2025-07-09 21:57:48 +03:00
parent d757ac4eb3
commit 94c4ec0613
6 changed files with 88 additions and 16 deletions

View File

@ -143,6 +143,17 @@ impl Builder {
} }
} }
pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> Result<(), ()> {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(block.0.0.0);
let function = module.functions.get_unchecked_mut(block.0.1);
let block = function.blocks.get_unchecked_mut(block.1);
block.data.deleted = true;
Ok(())
}
}
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData { pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData {
unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() } unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() }
@ -242,6 +253,39 @@ impl Builder {
} }
} }
} }
pub fn is_block_used(&self, block_v: BlockValue) -> bool {
unsafe {
let modules = self.modules.borrow();
let module = modules.get_unchecked(block_v.0.0.0);
let function = module.functions.get_unchecked(block_v.0.1);
let block = function.blocks.get_unchecked(block_v.1);
if block.instructions.len() > 0 || block.data.terminator.is_some() {
return true;
}
for other in &function.blocks {
if let Some(term) = &other.data.terminator {
match term {
TerminatorKind::Ret(_) => {}
TerminatorKind::Br(other_val) => {
if other_val == &block_v {
return true;
}
}
TerminatorKind::CondBr(_, then_other_v, else_other_v) => {
if then_other_v == &block_v || else_other_v == &block_v {
return true;
}
}
}
}
}
false
}
}
} }
impl InstructionValue { impl InstructionValue {

View File

@ -205,6 +205,10 @@ impl FunctionHolder {
let own_function = *module.functions.get(&self.value).unwrap(); let own_function = *module.functions.get(&self.value).unwrap();
for block in &self.blocks { for block in &self.blocks {
if block.data.deleted {
continue;
}
let block_ref = LLVMCreateBasicBlockInContext( let block_ref = LLVMCreateBasicBlockInContext(
module.context_ref, module.context_ref,
into_cstring(&self.data.name).as_ptr(), into_cstring(&self.data.name).as_ptr(),
@ -223,6 +227,10 @@ impl FunctionHolder {
impl BlockHolder { impl BlockHolder {
unsafe fn compile(&self, module: &mut LLVMModule, function: &LLVMFunction) { unsafe fn compile(&self, module: &mut LLVMModule, function: &LLVMFunction) {
unsafe { unsafe {
if self.data.deleted {
return;
}
let block_ref = *module.blocks.get(&self.value).unwrap(); let block_ref = *module.blocks.get(&self.value).unwrap();
LLVMPositionBuilderAtEnd(module.builder_ref, block_ref); LLVMPositionBuilderAtEnd(module.builder_ref, block_ref);

View File

@ -32,10 +32,14 @@ impl Debug for FunctionHolder {
impl Debug for BlockHolder { impl Debug for BlockHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(&format!("{}[{:?}]", &self.data.name, &self.value)) let deleted = if self.data.deleted { " (deleted)" } else { "" };
.field(&self.instructions) f.debug_tuple(&format!(
.field(&self.data.terminator) "{}[{:?}]{} ",
.finish() &self.data.name, &self.value, deleted
))
.field(&self.instructions)
.field(&self.data.terminator)
.finish()
} }
} }

View File

@ -95,6 +95,7 @@ impl<'ctx> Function<'ctx> {
BlockData { BlockData {
name: name.to_owned(), name: name.to_owned(),
terminator: None, terminator: None,
deleted: false,
}, },
), ),
} }
@ -110,6 +111,7 @@ impl<'ctx> Function<'ctx> {
pub struct BlockData { pub struct BlockData {
name: String, name: String,
terminator: Option<TerminatorKind>, terminator: Option<TerminatorKind>,
deleted: bool,
} }
pub struct Block<'builder> { pub struct Block<'builder> {
@ -130,6 +132,16 @@ impl<'builder> Block<'builder> {
unsafe { self.builder.terminate(&self.value, instruction) } unsafe { self.builder.terminate(&self.value, instruction) }
} }
pub fn delete_if_unused(&mut self) -> Result<(), ()> {
unsafe {
if !self.builder.is_block_used(self.value()) {
self.builder.delete_block(&self.value)
} else {
Ok(())
}
}
}
pub fn value(&self) -> BlockValue { pub fn value(&self) -> BlockValue {
self.value self.value
} }

View File

@ -1,14 +1,13 @@
// Main // Main
fn main() -> bool { fn main() -> bool {
return (5 == fibonacci(5)) && false; return 5 == fibonacci(5);
} }
// Fibonacci // Fibonacci
fn fibonacci(value: u16) -> u16 { fn fibonacci(value: u16) -> u16 {
let ret = if value <= 2 { if value <= 2 {
1 return 1;
} else { } else {
fibonacci(value - 1) + fibonacci(value - 2) return fibonacci(value - 1) + fibonacci(value - 2);
}; }
ret
} }

View File

@ -89,6 +89,8 @@ impl mir::Module {
mir::FunctionDefinitionKind::Local(block, _) => { mir::FunctionDefinitionKind::Local(block, _) => {
if let Some(ret) = block.codegen(&mut scope) { if let Some(ret) = block.codegen(&mut scope) {
scope.block.terminate(Term::Ret(ret)).unwrap(); scope.block.terminate(Term::Ret(ret)).unwrap();
} else {
scope.block.delete_if_unused().unwrap();
} }
} }
mir::FunctionDefinitionKind::Extern => {} mir::FunctionDefinitionKind::Extern => {}
@ -298,13 +300,16 @@ impl mir::Block {
} }
if let Some((kind, expr)) = &self.return_expression { if let Some((kind, expr)) = &self.return_expression {
let ret = expr.codegen(&mut scope).unwrap(); if let Some(ret) = expr.codegen(&mut scope) {
match kind { match kind {
mir::ReturnKind::Hard => { mir::ReturnKind::Hard => {
scope.block.terminate(Term::Ret(ret)).unwrap(); scope.block.terminate(Term::Ret(ret)).unwrap();
None None
}
mir::ReturnKind::Soft => Some(ret),
} }
mir::ReturnKind::Soft => Some(ret), } else {
None
} }
} else { } else {
None None