Skip to content

Commit

Permalink
feat: add debugger for licm pass, add test case for licm and dom
Browse files Browse the repository at this point in the history
  • Loading branch information
Solo-steven committed Sep 24, 2024
1 parent 38c8b47 commit ac1ce55
Show file tree
Hide file tree
Showing 12 changed files with 592 additions and 152 deletions.
85 changes: 85 additions & 0 deletions compilers/rustyc/optimizer/src/ir_optimizer/pass/licm/debugger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use super::LICMPass;
use crate::ir::function::Function;
use crate::ir_optimizer::pass::DebuggerPass;
use crate::ir_optimizer::print_table_helper::{
get_max_block_id_len, print_divider, print_header, print_table_row, sort_block_ids,
};

impl<'a> DebuggerPass for LICMPass<'a> {
fn debugger(&self, function: &Function) -> String {
let mut output_string = String::new();
let len_of_right = get_max_block_id_len(function) + 2 + 3 /* len of "BB<space>" */;
let len_of_left = "Header".len() + 2;
let len_of_row = len_of_right + len_of_left + 1;
// print natural loop
let mut index = 1;
for natural_loop in &self.loops {
output_string.push_str(print_divider(len_of_row).as_str());
output_string.push_str(print_header(&format!("Loop {}", index), len_of_row).as_str());
output_string.push_str(print_divider(len_of_row).as_str());
output_string.push_str(
print_table_row(
"Header",
format!("BB {}", &natural_loop.header.0).as_str(),
len_of_left,
len_of_right,
)
.as_str(),
);
output_string.push_str(
print_table_row(
"Tail",
format!("BB {}", &natural_loop.tails.0).as_str(),
len_of_left,
len_of_right,
)
.as_str(),
);
output_string.push_str(print_divider(len_of_row).as_str());
let mut inner_index = 0 as usize;
let blocks = sort_block_ids(natural_loop.blocks.iter().map(|b| b.clone()).collect());
for block in blocks {
let left = format!(
"{}",
if inner_index == natural_loop.blocks.len() / 2 {
"Blocks"
} else {
" "
}
);
output_string.push_str(&print_table_row(
left.as_str(),
format!("BB {}", block.0).as_str(),
len_of_left,
len_of_right,
));
inner_index += 1;
}
output_string.push_str(print_divider(len_of_row).as_str());
let mut inner_index = 0 as usize;
let sorted_exits =
sort_block_ids(natural_loop.exits.iter().map(|b| b.clone()).collect());
for block in &sorted_exits {
let left = format!(
"{}",
if inner_index == natural_loop.exits.len() / 2 {
"Exits"
} else {
" "
}
);
output_string.push_str(&print_table_row(
left.as_str(),
format!("BB {}", block.0).as_str(),
len_of_left,
len_of_right,
));
inner_index += 1;
}
output_string.push_str(print_divider(len_of_row).as_str());

index += 1;
}
output_string
}
}
3 changes: 3 additions & 0 deletions compilers/rustyc/optimizer/src/ir_optimizer/pass/licm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod debugger;
mod util;
use std::collections::HashSet;
use util::get_def_values;
Expand All @@ -19,6 +20,7 @@ struct NaturalLoop {

/// ## Loop-Invariant-Code-Motion Pass
/// perform LICM. require dom table and use-def-table.
/// reference: https://www.cs.cmu.edu/afs/cs/academic/class/15745-s19/www/lectures/L9-LICM.pdf
pub struct LICMPass<'a> {
use_def_table: &'a UseDefTable,
dom_table: &'a DomTable,
Expand Down Expand Up @@ -67,6 +69,7 @@ impl<'a> LICMPass<'a> {
}
/// ## Fins Backward Edges
/// Using simple dfs traversal to find the edge that revisit the visited block.
/// please note that backward edge is construct as (tail, head).
fn find_backward_edges(&self, function: &Function) -> HashSet<Edge> {
let mut table: HashSet<Edge> = HashSet::new();
self.dfs_visit_to_find_backward_edges(
Expand Down
107 changes: 50 additions & 57 deletions compilers/rustyc/optimizer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ pub mod ir_converter;
pub mod ir_optimizer;

use crate::ir::function::Function;
use crate::ir::value::IrValueType;
use crate::ir_converter::Converter;
use crate::ir_optimizer::anaylsis::domtree::DomAnaylsier;
use crate::ir_optimizer::anaylsis::use_def_chain::UseDefAnaylsier;
use crate::ir_optimizer::pass::licm;
use ir_optimizer::anaylsis::{DebuggerAnaylsis, OptimizerAnaylsis};
use ir_optimizer::pass::gvn::GVNPass;
use ir_optimizer::pass::licm::LICMPass;
use ir_optimizer::pass::OptimizerPass;
use ir_optimizer::pass::{DebuggerPass, OptimizerPass};
use rustyc_frontend::parser::Parser;
use std::fs::File;
use std::io::Write;
Expand All @@ -18,7 +20,7 @@ fn write_string_to_file(file_string: String) {
let mut file1 = File::create("./test.txt").unwrap();
write!(file1, "{}", file_string).unwrap();
}

#[allow(dead_code)]
fn converter_example() {
let program = Parser::new(
"
Expand Down Expand Up @@ -54,19 +56,31 @@ fn converter_example() {
write_string_to_file(module.print_to_string());
}

#[allow(dead_code)]
fn anaylsiser_example() {
let fun = create_backward_edge_example();
let mut anaylsiser = DomAnaylsier::new();
let table = anaylsiser.anaylsis(&fun);
let output = anaylsiser.debugger(&fun, &table);
write_string_to_file(output);
}

#[allow(dead_code)]
fn optimizer_example() {
let mut fun = create_licm_graph_example_from_cmu();
write_string_to_file(fun.print_to_string());
let mut dom = DomAnaylsier::new();
let dom_table = dom.anaylsis(&fun);

let mut use_def = UseDefAnaylsier::new();
let use_def_table = use_def.anaylsis(&fun);
let mut pass = LICMPass::new(&use_def_table, &dom_table);
pass.process(&mut fun);

let mut file1 = File::create("./test1.txt").unwrap();
write!(file1, "{}", fun.print_to_string()).unwrap();
// let mut fun = create_gvn_graph_from_conrnell();
// let mut file1 = File::create("./before.txt").unwrap();
// write!(file1, "{}", fun.print_to_string()).unwrap();
// let mut dom = DomAnaylsier::new();
// let dom_table = dom.anaylsis(&fun);

// let mut use_def = UseDefAnaylsier::new();
// let use_def_table = use_def.anaylsis(&fun);
// let mut pass = GVNPass::new( &dom_table);
// pass.process(&mut fun);

// write_string_to_file(pass.debugger(&fun));
// let mut file1 = File::create("./after.txt").unwrap();
// write!(file1, "{}", fun.print_to_string()).unwrap();
}

fn create_simple_loop() -> Function {
Expand Down Expand Up @@ -114,60 +128,39 @@ fn create_backward_edge_example() -> Function {
function
}

fn create_licm_graph_example_from_cmu() -> Function {
pub fn create_dom_graph_example() -> Function {
let mut function = Function::new(String::from("test_fun"));
// create blocks
let b0 = function.create_block(); // entry
function.mark_as_entry(b0);
let b1 = function.create_block(); // header
let b0 = function.create_block();
let b1 = function.create_block();
let b2 = function.create_block();
let b3 = function.create_block();
let b4 = function.create_block(); // tail
let b5 = function.create_block(); // exit of loop
let b6 = function.create_block(); // exit
function.mark_as_exit(b6);
// connect
let b4 = function.create_block();
let b5 = function.create_block();
let b6 = function.create_block();
let b7 = function.create_block();
let b8 = function.create_block();

function.connect_block(b0, b1);
function.connect_block(b1, b2);
function.connect_block(b2, b4);
function.connect_block(b4, b1);
function.connect_block(b1, b3);
function.connect_block(b3, b5);
function.connect_block(b2, b3);
function.connect_block(b3, b4);
function.connect_block(b3, b1);

function.connect_block(b1, b5);
function.connect_block(b5, b6);
// instructions
// entry
function.switch_to_block(b0);
let i16_10 = function.create_i16_const(10);
let a = function.build_mov_inst(i16_10);
let b = function.build_mov_inst(i16_10);
let c = function.build_mov_inst(i16_10);
function.build_jump_inst(b1);
// header
function.switch_to_block(b1);
function.build_brif_inst(i16_10, b2, b3);
function.switch_to_block(b2);
let a_1 = function.build_add_inst(b, c);
let i16_2 = function.create_i16_const(2);
let _f = function.build_add_inst(a_1, i16_2);
function.build_jump_inst(b4);
function.switch_to_block(b3);
let e = function.build_mov_inst(i16_10);
function.build_brif_inst(e, b4, b5);
function.switch_to_block(b4);
let a_in_b4 = function.build_phi_inst(vec![(b2, a_1), (b0, a)]);
let i16_1 = function.create_i16_const(1);
let _d = function.build_add_inst(a_in_b4, i16_1);
function.build_jump_inst(b1);
function.switch_to_block(b5);
function.build_jump_inst(b6);
function.switch_to_block(b6);
function.build_ret_inst(None);
function.connect_block(b5, b8);
function.connect_block(b6, b7);
function.connect_block(b8, b7);
function.connect_block(b7, b3);

function.mark_as_entry(b0);
function.mark_as_exit(b4);

function
}

fn main() {
// converter_example();
optimizer_example();
// optimizer_example();
anaylsiser_example();
}
99 changes: 98 additions & 1 deletion compilers/rustyc/optimizer/tests/build_ir_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ pub fn create_dom_graph_example() -> Function {

function
}

/// ## Create simple graph to test use-def information:
/// ```markdown
/// t0 = 10;
Expand Down Expand Up @@ -180,3 +179,101 @@ pub fn create_use_def_graph() -> Function {
func.connect_block(b1, b2);
func
}

pub fn create_licm_graph_example_from_cmu() -> Function {
let mut function = Function::new(String::from("test_fun"));
// create blocks
let b0 = function.create_block(); // entry
function.mark_as_entry(b0);
let b1 = function.create_block(); // header
let b2 = function.create_block();
let b3 = function.create_block();
let b4 = function.create_block(); // tail
let b5 = function.create_block(); // exit of loop
let b6 = function.create_block(); // exit
function.mark_as_exit(b6);
// connect
function.connect_block(b0, b1);
function.connect_block(b1, b2);
function.connect_block(b2, b4);
function.connect_block(b4, b1);
function.connect_block(b1, b3);
function.connect_block(b3, b5);
function.connect_block(b3, b4);
function.connect_block(b5, b6);
// instructions
// entry
function.switch_to_block(b0);
let i16_10 = function.create_i16_const(10);
let a = function.build_mov_inst(i16_10);
let b = function.build_mov_inst(i16_10);
let c = function.build_mov_inst(i16_10);
function.build_jump_inst(b1);
// header
function.switch_to_block(b1);
function.build_brif_inst(i16_10, b2, b3);
function.switch_to_block(b2);
let a_1 = function.build_add_inst(b, c);
let i16_2 = function.create_i16_const(2);
let _f = function.build_add_inst(a_1, i16_2);
function.build_jump_inst(b4);
function.switch_to_block(b3);
let e = function.build_mov_inst(i16_10);
function.build_brif_inst(e, b4, b5);
function.switch_to_block(b4);
let a_in_b4 = function.build_phi_inst(vec![(b2, a_1), (b0, a)]);
let i16_1 = function.create_i16_const(1);
let _d = function.build_add_inst(a_in_b4, i16_1);
function.build_jump_inst(b1);
function.switch_to_block(b5);
function.build_jump_inst(b6);
function.switch_to_block(b6);
function.build_ret_inst(None);

function
}

pub fn create_simple_loop() -> Function {
let mut function = Function::new(String::from("test_fun"));
let b1 = function.create_block();
function.mark_as_entry(b1);
let b2 = function.create_block();
function.mark_as_exit(b2);
function.connect_block(b1, b2);
function.connect_block(b2, b1);

function
}

pub fn create_backward_edge_example() -> Function {
let mut function = Function::new(String::from("test_fun"));
// create blocks
let b1 = function.create_block();
function.mark_as_entry(b1);
let b2 = function.create_block();
let b3 = function.create_block();
let b4 = function.create_block();
let b5 = function.create_block();
let b6 = function.create_block();
let b7 = function.create_block();
let b8 = function.create_block();
function.mark_as_exit(b6);
// connect
function.connect_block(b1, b2);
function.connect_block(b2, b3);
function.connect_block(b3, b4);
function.connect_block(b4, b5);
function.connect_block(b5, b6);

function.connect_block(b2, b7);
function.connect_block(b7, b8);
function.connect_block(b8, b5);
function.connect_block(b8, b6);

function.connect_block(b4, b1);
function.connect_block(b5, b2);
function.connect_block(b8, b7);
function.connect_block(b6, b5);

function
}
Loading

0 comments on commit ac1ce55

Please sign in to comment.