mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-14 22:38:46 +00:00
HW8 (2)
InferenceGraph 구현
This commit is contained in:
@@ -5,7 +5,7 @@ use std::ops::Deref;
|
||||
use lang_c::ast;
|
||||
|
||||
use crate::ir::HasDtype;
|
||||
use crate::opt::opt_utils;
|
||||
use crate::opt::opt_utils::*;
|
||||
use crate::{Translate, asm, ir};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -35,6 +35,167 @@ impl Translate<ir::TranslationUnit> for Asmgen {
|
||||
}
|
||||
}
|
||||
|
||||
struct InferenceGraph {
|
||||
edges: HashSet<(ir::RegisterId, ir::RegisterId)>,
|
||||
}
|
||||
|
||||
impl InferenceGraph {
|
||||
fn new(code: &ir::FunctionDefinition) -> Self {
|
||||
let cfg = make_cfg(code);
|
||||
let reverse_cfg = reverse_cfg(&cfg);
|
||||
let domtree = Domtree::new(code.bid_init, &cfg, &reverse_cfg);
|
||||
|
||||
let mut lives = HashMap::new();
|
||||
|
||||
loop {
|
||||
let mut changed = false;
|
||||
|
||||
for bid in domtree.rpo() {
|
||||
let block = &code.blocks[bid];
|
||||
let len = block.instructions.len();
|
||||
let mut uses = HashSet::new();
|
||||
|
||||
for (i, inst) in block.instructions.iter().enumerate() {
|
||||
match inst.deref() {
|
||||
ir::Instruction::BinOp { lhs, rhs, .. } => {
|
||||
mark_as_used(lhs, &mut uses);
|
||||
mark_as_used(rhs, &mut uses);
|
||||
}
|
||||
ir::Instruction::UnaryOp { operand, .. } => {
|
||||
mark_as_used(operand, &mut uses);
|
||||
}
|
||||
ir::Instruction::Store { ptr, value } => {
|
||||
mark_as_used(ptr, &mut uses);
|
||||
mark_as_used(value, &mut uses);
|
||||
}
|
||||
ir::Instruction::Load { ptr } => {
|
||||
mark_as_used(ptr, &mut uses);
|
||||
}
|
||||
ir::Instruction::Call { callee, args, .. } => {
|
||||
mark_as_used(callee, &mut uses);
|
||||
for arg in args {
|
||||
mark_as_used(arg, &mut uses);
|
||||
}
|
||||
}
|
||||
ir::Instruction::TypeCast { value, .. } => {
|
||||
mark_as_used(value, &mut uses);
|
||||
}
|
||||
ir::Instruction::GetElementPtr { ptr, offset, .. } => {
|
||||
mark_as_used(ptr, &mut uses);
|
||||
mark_as_used(offset, &mut uses);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let mut next_lives = lives
|
||||
.entry(ir::RegisterId::temp(*bid, i + 1))
|
||||
.or_insert_with(HashSet::new)
|
||||
.clone();
|
||||
let _ = next_lives.remove(&ir::RegisterId::temp(*bid, i));
|
||||
uses.extend(next_lives);
|
||||
changed = extend_set(
|
||||
lives
|
||||
.entry(ir::RegisterId::temp(*bid, i))
|
||||
.or_insert_with(HashSet::new),
|
||||
std::mem::take(&mut uses),
|
||||
) || changed;
|
||||
}
|
||||
|
||||
let mut uses = HashSet::new();
|
||||
match &block.exit {
|
||||
ir::BlockExit::Jump { arg } => {
|
||||
for arg in &arg.args {
|
||||
mark_as_used(arg, &mut uses);
|
||||
}
|
||||
}
|
||||
ir::BlockExit::ConditionalJump {
|
||||
condition,
|
||||
arg_then,
|
||||
arg_else,
|
||||
} => {
|
||||
mark_as_used(condition, &mut uses);
|
||||
for arg in &arg_then.args {
|
||||
mark_as_used(arg, &mut uses);
|
||||
}
|
||||
for arg in &arg_else.args {
|
||||
mark_as_used(arg, &mut uses);
|
||||
}
|
||||
}
|
||||
ir::BlockExit::Switch {
|
||||
value,
|
||||
default,
|
||||
cases,
|
||||
} => {
|
||||
mark_as_used(value, &mut uses);
|
||||
for arg in &default.args {
|
||||
mark_as_used(arg, &mut uses);
|
||||
}
|
||||
for (_, arg) in cases {
|
||||
for arg in &arg.args {
|
||||
mark_as_used(arg, &mut uses);
|
||||
}
|
||||
}
|
||||
}
|
||||
ir::BlockExit::Return { value } => {
|
||||
mark_as_used(value, &mut uses);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let successors = cfg[bid].iter().map(|arg| arg.bid).collect::<Vec<_>>();
|
||||
let mut successor_lives = HashSet::<ir::RegisterId>::new();
|
||||
for succ in &successors {
|
||||
if let Some(succ_lives) = lives.get(&ir::RegisterId::temp(*succ, 0)) {
|
||||
successor_lives.extend(succ_lives);
|
||||
}
|
||||
}
|
||||
|
||||
uses.extend(successor_lives);
|
||||
changed = extend_set(
|
||||
lives
|
||||
.entry(ir::RegisterId::temp(*bid, len))
|
||||
.or_insert_with(HashSet::new),
|
||||
uses,
|
||||
) || changed;
|
||||
}
|
||||
|
||||
if !changed {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut edges = HashSet::new();
|
||||
|
||||
for (_, lives) in &lives {
|
||||
for rid1 in lives {
|
||||
for rid2 in lives {
|
||||
if rid1 != rid2 {
|
||||
let _ = edges.insert((*rid1, *rid2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Inference graph: {:?}", edges);
|
||||
|
||||
InferenceGraph { edges }
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_as_used(operand: &ir::Operand, uses: &mut HashSet<ir::RegisterId>) {
|
||||
if let ir::Operand::Register { rid, .. } = operand {
|
||||
if !matches!(rid, ir::RegisterId::Local { .. }) {
|
||||
let _ = uses.insert(*rid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_set(set: &mut HashSet<ir::RegisterId>, other: HashSet<ir::RegisterId>) -> bool {
|
||||
let len = set.len();
|
||||
set.extend(other);
|
||||
set.len() != len
|
||||
}
|
||||
|
||||
struct Context {
|
||||
insts: Vec<asm::Instruction>,
|
||||
stack_offsets: HashMap<ir::RegisterId, u64>,
|
||||
@@ -95,6 +256,9 @@ impl Asmgen {
|
||||
definition,
|
||||
} => {
|
||||
if let Some(definition) = definition {
|
||||
// TEMP
|
||||
let graph = InferenceGraph::new(definition);
|
||||
|
||||
let mut context = self.translate_prologue(signature, definition, structs);
|
||||
self.translate_block(
|
||||
name,
|
||||
|
||||
@@ -122,7 +122,7 @@ impl Domtree {
|
||||
};
|
||||
for (bid_pred, _) in preds {
|
||||
let mut runner = *bid_pred;
|
||||
while !Self::dominates(&idoms, runner, *bid) {
|
||||
while idoms.contains_key(&runner) && !Self::dominates(&idoms, runner, *bid) {
|
||||
frontiers.entry(runner).or_insert_with(Vec::new).push(*bid);
|
||||
runner = idoms[&runner];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user