Skip to content

Commit

Permalink
feat(ir): global dce pass
Browse files Browse the repository at this point in the history
  • Loading branch information
JuniMay committed Jul 27, 2024
1 parent 3cea86f commit e305ead
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/target

/.idea/*

/.vscode/*
!settings.json

Expand Down
7 changes: 6 additions & 1 deletion src/bin/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use orzcc::{
fold::{ConstantFolding, CONSTANT_FOLDING},
gcm::{Gcm, GCM},
global2local::{Global2Local, GLOBAL2LOCAL},
global_dce::{GlobalDce, GLOBAL_DCE},
gvn::{GlobalValueNumbering, GVN},
inline::{Inline, INLINE},
instcombine::{InstCombine, INSTCOMBINE},
Expand Down Expand Up @@ -79,7 +80,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// pipeline

let mut opt_pipeline = Pipeline::default();
opt_pipeline.add_pass(GLOBAL2LOCAL);
// opt_pipeline.add_pass(GLOBAL2LOCAL); // FIXME
opt_pipeline.add_pass(MEM2REG);
opt_pipeline.add_pass(CFG_SIMPLIFY);
opt_pipeline.add_pass(CONSTANT_FOLDING);
Expand All @@ -91,6 +92,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
opt_pipeline.add_pass(GVN);
opt_pipeline.add_pass(SIMPLE_DCE);
opt_pipeline.add_pass(INLINE);
// remove functions that are not used after inlining
opt_pipeline.add_pass(GLOBAL_DCE);
opt_pipeline.add_pass(SIMPLE_DCE);
opt_pipeline.add_pass(LOOP_UNROLL);
opt_pipeline.add_pass(SIMPLE_DCE);
Expand Down Expand Up @@ -151,7 +154,9 @@ fn register_passes(passman: &mut PassManager) {
ConstantFolding::register(passman);
InstCombine::register(passman);
Inline::register(passman);

Global2Local::register(passman);
GlobalDce::register(passman);

LoopUnroll::register(passman);
GlobalValueNumbering::register(passman);
Expand Down
37 changes: 36 additions & 1 deletion src/ir/global.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use std::{fmt, hash::Hash};

use super::{debug::CommentPos, source_loc::Span, Block, Constant, Context, Signature, Ty};
use super::{
debug::CommentPos,
remove_all_insts,
source_loc::Span,
Block,
Constant,
Context,
Signature,
Ty,
};
use crate::{
collections::{
linked_list::LinkedListContainerPtr,
Expand Down Expand Up @@ -116,6 +125,32 @@ impl Func {

/// Get the number of instructions in the function.
pub fn insn(self, ctx: &Context) -> usize { self.iter(ctx).map(|block| block.insn(ctx)).sum() }

/// Remove the function and all its blocks and instructions.
pub fn remove(self, ctx: &mut Context) {
let symbol = self.name(ctx).clone();

let mut insts_to_remove = Vec::new();
let mut blocks_to_remove = Vec::new();

for block in self.iter(ctx) {
for inst in block.iter(ctx) {
insts_to_remove.push(inst);
}
blocks_to_remove.push(block);
}

// remove instructions first, to avoid block uses.
remove_all_insts(ctx, insts_to_remove, false);

// remove all blocks
for block in blocks_to_remove {
block.remove(ctx);
}

ctx.symbols.remove(&symbol);
ctx.free(self);
}
}

impl CfgRegion for Func {
Expand Down
91 changes: 91 additions & 0 deletions src/ir/passes/global_dce.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use rustc_hash::FxHashSet;

use crate::{
collections::linked_list::LinkedListContainerPtr,
ir::{
passman::{GlobalPassMut, PassResult, TransformPass},
Context,
InstKind,
Symbol,
SymbolKind,
},
};

pub const GLOBAL_DCE: &str = "global-dce";

pub struct GlobalDce;

impl GlobalPassMut for GlobalDce {
type Output = ();

fn run(&mut self, ctx: &mut Context) -> PassResult<(Self::Output, bool)> {
use InstKind as Ik;

let mut func_uses = FxHashSet::default();
let mut slot_uses = FxHashSet::default();

for func in ctx.funcs() {
for block in func.iter(ctx) {
for inst in block.iter(ctx) {
if let Ik::Call(sym) = inst.kind(ctx) {
if let Some(SymbolKind::FuncDef(callee)) = ctx.lookup_symbol(sym) {
if func != *callee {
// ignore recursive calls
func_uses.insert(*callee);
}
}
} else if let Ik::GetGlobal(sym) = inst.kind(ctx) {
match ctx.lookup_symbol(sym) {
Some(SymbolKind::FuncDef(callee)) => {
if func != *callee {
func_uses.insert(*callee);
}
}
Some(SymbolKind::GlobalSlot(slot)) => {
slot_uses.insert(*slot);
}
_ => {}
}
}
}
}
}

let main_func = ctx.lookup_func(&Symbol::from("main")).unwrap();
func_uses.insert(main_func);

let mut funcs_to_remove = Vec::new();
let mut slots_to_remove = Vec::new();

for func in ctx.funcs() {
if !func_uses.contains(&func) {
funcs_to_remove.push(func);
}
}

for slot in ctx.global_slots() {
if !slot_uses.contains(&slot) {
slots_to_remove.push(slot);
}
}

for func in funcs_to_remove {
func.remove(ctx);
}

for slot in slots_to_remove {
slot.remove(ctx);
}

PassResult::Ok(((), false)) // only run once.
}
}

impl TransformPass for GlobalDce {
fn register(passman: &mut crate::ir::passman::PassManager)
where
Self: Sized,
{
passman.register_transform(GLOBAL_DCE, GlobalDce, Vec::new());
}
}
1 change: 1 addition & 0 deletions src/ir/passes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod control_flow;
pub mod fold;
pub mod gcm;
pub mod global2local;
pub mod global_dce;
pub mod gvn;
pub mod inline;
pub mod instcombine;
Expand Down

0 comments on commit e305ead

Please sign in to comment.