mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-14 22:38:46 +00:00
HW3~4 Refactoring
This commit is contained in:
@@ -146,189 +146,6 @@ fn mark_as_inpromotable(inpromotables: &mut HashSet<usize>, operand: &Operand) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_cfg(fdef: &FunctionDefinition) -> HashMap<BlockId, Vec<JumpArg>> {
|
|
||||||
fdef.blocks
|
|
||||||
.iter()
|
|
||||||
.map(|(bid, block)| {
|
|
||||||
let mut args = Vec::new();
|
|
||||||
match &block.exit {
|
|
||||||
BlockExit::Jump { arg } => args.push(arg.clone()),
|
|
||||||
BlockExit::ConditionalJump {
|
|
||||||
arg_then, arg_else, ..
|
|
||||||
} => {
|
|
||||||
args.push(arg_then.clone());
|
|
||||||
args.push(arg_else.clone());
|
|
||||||
}
|
|
||||||
BlockExit::Switch { default, cases, .. } => {
|
|
||||||
args.push(default.clone());
|
|
||||||
for (_, arg) in cases {
|
|
||||||
args.push(arg.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
(*bid, args)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reverse_cfg(cfg: &HashMap<BlockId, Vec<JumpArg>>) -> HashMap<BlockId, Vec<(BlockId, JumpArg)>> {
|
|
||||||
let mut result = HashMap::new();
|
|
||||||
for (bid, jumps) in cfg {
|
|
||||||
for jump in jumps {
|
|
||||||
result
|
|
||||||
.entry(jump.bid)
|
|
||||||
.or_insert_with(Vec::new)
|
|
||||||
.push((*bid, jump.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn traverse_rpo(bid_init: BlockId, cfg: &HashMap<BlockId, Vec<JumpArg>>) -> Vec<BlockId> {
|
|
||||||
fn traverse_po(
|
|
||||||
bid: BlockId,
|
|
||||||
cfg: &HashMap<BlockId, Vec<JumpArg>>,
|
|
||||||
visited: &mut HashSet<BlockId>,
|
|
||||||
post_order: &mut Vec<BlockId>,
|
|
||||||
) {
|
|
||||||
for jump in &cfg[&bid] {
|
|
||||||
if visited.insert(jump.bid) {
|
|
||||||
traverse_po(jump.bid, cfg, visited, post_order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post_order.push(bid);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visited = HashSet::new();
|
|
||||||
let _ = visited.insert(bid_init);
|
|
||||||
let mut order = Vec::new();
|
|
||||||
|
|
||||||
traverse_po(bid_init, cfg, &mut visited, &mut order);
|
|
||||||
order.reverse();
|
|
||||||
order
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Domtree {
|
|
||||||
idoms: HashMap<BlockId, BlockId>,
|
|
||||||
inverse_idoms: HashMap<BlockId, HashSet<BlockId>>,
|
|
||||||
frontiers: HashMap<BlockId, Vec<BlockId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Domtree {
|
|
||||||
fn new(
|
|
||||||
bid_init: BlockId,
|
|
||||||
cfg: &HashMap<BlockId, Vec<JumpArg>>,
|
|
||||||
reverse_cfg: &HashMap<BlockId, Vec<(BlockId, JumpArg)>>,
|
|
||||||
) -> Self {
|
|
||||||
let rpo = traverse_rpo(bid_init, cfg);
|
|
||||||
let irpo = rpo.iter().enumerate().map(|(i, bid)| (*bid, i)).collect();
|
|
||||||
let mut idoms: HashMap<BlockId, BlockId> = HashMap::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut changed = false;
|
|
||||||
|
|
||||||
for bid in &rpo {
|
|
||||||
if *bid == bid_init {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut idom = None;
|
|
||||||
for (bid_pred, _) in &reverse_cfg[bid] {
|
|
||||||
if *bid_pred == bid_init || idoms.contains_key(bid_pred) {
|
|
||||||
idom = Some(intersect_idom(idom, *bid_pred, &irpo, &idoms));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(idom) = idom {
|
|
||||||
let _ = idoms
|
|
||||||
.entry(*bid)
|
|
||||||
.and_modify(|v| {
|
|
||||||
if *v != idom {
|
|
||||||
changed = true;
|
|
||||||
*v = idom;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_insert_with(|| {
|
|
||||||
changed = true;
|
|
||||||
idom
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !changed {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut inverse_idoms = HashMap::new();
|
|
||||||
for (bid, idom) in &idoms {
|
|
||||||
let _ = inverse_idoms
|
|
||||||
.entry(*idom)
|
|
||||||
.or_insert_with(HashSet::new)
|
|
||||||
.insert(*bid);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut frontiers = HashMap::new();
|
|
||||||
for (bid, preds) in reverse_cfg.iter().filter(|(_, preds)| preds.len() > 1) {
|
|
||||||
let idom = if let Some(idom) = idoms.get(bid) {
|
|
||||||
idom
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
for (bid_pred, _) in preds {
|
|
||||||
let mut runner = *bid_pred;
|
|
||||||
while !Self::dominates(&idoms, runner, *bid) {
|
|
||||||
frontiers.entry(runner).or_insert_with(Vec::new).push(*bid);
|
|
||||||
runner = idoms[&runner];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
|
||||||
idoms,
|
|
||||||
inverse_idoms,
|
|
||||||
frontiers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dominates(idoms: &HashMap<BlockId, BlockId>, bid1: BlockId, mut bid2: BlockId) -> bool {
|
|
||||||
loop {
|
|
||||||
bid2 = if let Some(idom2) = idoms.get(&bid2) {
|
|
||||||
*idom2
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
if bid1 == bid2 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frontiers(&self, bid: &BlockId) -> Option<&Vec<BlockId>> {
|
|
||||||
self.frontiers.get(bid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn intersect_idom(
|
|
||||||
lhs: Option<BlockId>,
|
|
||||||
mut rhs: BlockId,
|
|
||||||
irpo: &HashMap<BlockId, usize>,
|
|
||||||
idoms: &HashMap<BlockId, BlockId>,
|
|
||||||
) -> BlockId {
|
|
||||||
let mut lhs = if let Some(lhs) = lhs { lhs } else { return rhs };
|
|
||||||
loop {
|
|
||||||
if lhs == rhs {
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
match irpo[&lhs].cmp(&irpo[&rhs]) {
|
|
||||||
Ordering::Less => rhs = idoms[&rhs],
|
|
||||||
Ordering::Greater => lhs = idoms[&lhs],
|
|
||||||
Ordering::Equal => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PhinodeInfo<'a> = (
|
type PhinodeInfo<'a> = (
|
||||||
&'a HashMap<(usize, BlockId), usize>,
|
&'a HashMap<(usize, BlockId), usize>,
|
||||||
&'a HashMap<BlockId, Vec<(usize, Dtype)>>,
|
&'a HashMap<BlockId, Vec<(usize, Dtype)>>,
|
||||||
@@ -405,7 +222,7 @@ fn traverse_po(
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(bids_successors) = domtree.inverse_idoms.get(&bid) {
|
if let Some(bids_successors) = domtree.successors(&bid) {
|
||||||
for bid_successor in bids_successors {
|
for bid_successor in bids_successors {
|
||||||
traverse_po(
|
traverse_po(
|
||||||
*bid_successor,
|
*bid_successor,
|
||||||
@@ -436,7 +253,7 @@ fn find_end_value(
|
|||||||
|
|
||||||
if let Some(phinode_index) = phinode_indexes.get(&(aid, bid)) {
|
if let Some(phinode_index) = phinode_indexes.get(&(aid, bid)) {
|
||||||
Operand::register(RegisterId::arg(bid, *phinode_index), dtype)
|
Operand::register(RegisterId::arg(bid, *phinode_index), dtype)
|
||||||
} else if let Some(bid_idom) = domtree.idoms.get(&bid) {
|
} else if let Some(bid_idom) = domtree.idom(&bid) {
|
||||||
find_end_value(
|
find_end_value(
|
||||||
aid,
|
aid,
|
||||||
dtype,
|
dtype,
|
||||||
@@ -461,91 +278,3 @@ fn fill_jump_args(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_instruction_operands(
|
|
||||||
inst: &mut Instruction,
|
|
||||||
replaces: &HashMap<RegisterId, Operand>,
|
|
||||||
) -> bool {
|
|
||||||
match inst {
|
|
||||||
Instruction::BinOp { lhs, rhs, .. } => {
|
|
||||||
let a = replace_operand(lhs, replaces);
|
|
||||||
let b = replace_operand(rhs, replaces);
|
|
||||||
a || b
|
|
||||||
}
|
|
||||||
Instruction::UnaryOp { operand, .. } => replace_operand(operand, replaces),
|
|
||||||
Instruction::Store { ptr, value } => {
|
|
||||||
let a = replace_operand(ptr, replaces);
|
|
||||||
let b = replace_operand(value, replaces);
|
|
||||||
a || b
|
|
||||||
}
|
|
||||||
Instruction::Load { ptr } => replace_operand(ptr, replaces),
|
|
||||||
Instruction::Call { callee, args, .. } => {
|
|
||||||
let mut changed = replace_operand(callee, replaces);
|
|
||||||
for arg in args.iter_mut() {
|
|
||||||
changed = replace_operand(arg, replaces) || changed;
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
Instruction::TypeCast { value, .. } => replace_operand(value, replaces),
|
|
||||||
Instruction::GetElementPtr { ptr, offset, .. } => {
|
|
||||||
let a = replace_operand(ptr, replaces);
|
|
||||||
let b = replace_operand(offset, replaces);
|
|
||||||
a || b
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_exit_operands(exit: &mut BlockExit, replaces: &HashMap<RegisterId, Operand>) -> bool {
|
|
||||||
match exit {
|
|
||||||
BlockExit::Jump { arg } => {
|
|
||||||
let mut changed = false;
|
|
||||||
for arg in arg.args.iter_mut() {
|
|
||||||
changed = replace_operand(arg, replaces) || changed;
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
BlockExit::ConditionalJump {
|
|
||||||
condition,
|
|
||||||
arg_then,
|
|
||||||
arg_else,
|
|
||||||
} => {
|
|
||||||
let mut changed = replace_operand(condition, replaces);
|
|
||||||
for arg in arg_then.args.iter_mut() {
|
|
||||||
changed = replace_operand(arg, replaces) || changed;
|
|
||||||
}
|
|
||||||
for arg in arg_else.args.iter_mut() {
|
|
||||||
changed = replace_operand(arg, replaces) || changed;
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
BlockExit::Switch {
|
|
||||||
value,
|
|
||||||
default,
|
|
||||||
cases,
|
|
||||||
} => {
|
|
||||||
let mut changed = replace_operand(value, replaces);
|
|
||||||
for arg in default.args.iter_mut() {
|
|
||||||
changed = replace_operand(arg, replaces) || changed;
|
|
||||||
}
|
|
||||||
for (_, arg) in cases {
|
|
||||||
for arg in arg.args.iter_mut() {
|
|
||||||
changed = replace_operand(arg, replaces) || changed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
BlockExit::Return { value } => replace_operand(value, replaces),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_operand(operand: &mut Operand, replaces: &HashMap<RegisterId, Operand>) -> bool {
|
|
||||||
if let Operand::Register { rid, .. } = operand {
|
|
||||||
if let Some(new_operand) = replaces.get(rid) {
|
|
||||||
*operand = new_operand.clone();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,3 +3,296 @@
|
|||||||
//! You can freely add utilities commonly used in the implementation of multiple optimizations here.
|
//! You can freely add utilities commonly used in the implementation of multiple optimizations here.
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::ir::*;
|
||||||
|
|
||||||
|
pub(crate) fn make_cfg(fdef: &FunctionDefinition) -> HashMap<BlockId, Vec<JumpArg>> {
|
||||||
|
fdef.blocks
|
||||||
|
.iter()
|
||||||
|
.map(|(bid, block)| {
|
||||||
|
let mut args = Vec::new();
|
||||||
|
match &block.exit {
|
||||||
|
BlockExit::Jump { arg } => args.push(arg.clone()),
|
||||||
|
BlockExit::ConditionalJump {
|
||||||
|
arg_then, arg_else, ..
|
||||||
|
} => {
|
||||||
|
args.push(arg_then.clone());
|
||||||
|
args.push(arg_else.clone());
|
||||||
|
}
|
||||||
|
BlockExit::Switch { default, cases, .. } => {
|
||||||
|
args.push(default.clone());
|
||||||
|
for (_, arg) in cases {
|
||||||
|
args.push(arg.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
(*bid, args)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn reverse_cfg(
|
||||||
|
cfg: &HashMap<BlockId, Vec<JumpArg>>,
|
||||||
|
) -> HashMap<BlockId, Vec<(BlockId, JumpArg)>> {
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
for (bid, jumps) in cfg {
|
||||||
|
for jump in jumps {
|
||||||
|
result
|
||||||
|
.entry(jump.bid)
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push((*bid, jump.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
fn traverse_rpo(bid_init: BlockId, cfg: &HashMap<BlockId, Vec<JumpArg>>) -> Vec<BlockId> {
|
||||||
|
fn traverse_po(
|
||||||
|
bid: BlockId,
|
||||||
|
cfg: &HashMap<BlockId, Vec<JumpArg>>,
|
||||||
|
visited: &mut HashSet<BlockId>,
|
||||||
|
post_order: &mut Vec<BlockId>,
|
||||||
|
) {
|
||||||
|
for jump in &cfg[&bid] {
|
||||||
|
if visited.insert(jump.bid) {
|
||||||
|
traverse_po(jump.bid, cfg, visited, post_order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post_order.push(bid);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
let _ = visited.insert(bid_init);
|
||||||
|
let mut order = Vec::new();
|
||||||
|
|
||||||
|
traverse_po(bid_init, cfg, &mut visited, &mut order);
|
||||||
|
order.reverse();
|
||||||
|
order
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Domtree {
|
||||||
|
idoms: HashMap<BlockId, BlockId>,
|
||||||
|
inverse_idoms: HashMap<BlockId, HashSet<BlockId>>,
|
||||||
|
frontiers: HashMap<BlockId, Vec<BlockId>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Domtree {
|
||||||
|
pub(crate) fn new(
|
||||||
|
bid_init: BlockId,
|
||||||
|
cfg: &HashMap<BlockId, Vec<JumpArg>>,
|
||||||
|
reverse_cfg: &HashMap<BlockId, Vec<(BlockId, JumpArg)>>,
|
||||||
|
) -> Self {
|
||||||
|
let rpo = traverse_rpo(bid_init, cfg);
|
||||||
|
let irpo = rpo.iter().enumerate().map(|(i, bid)| (*bid, i)).collect();
|
||||||
|
let mut idoms: HashMap<BlockId, BlockId> = HashMap::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut changed = false;
|
||||||
|
|
||||||
|
for bid in &rpo {
|
||||||
|
if *bid == bid_init {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut idom = None;
|
||||||
|
for (bid_pred, _) in &reverse_cfg[bid] {
|
||||||
|
if *bid_pred == bid_init || idoms.contains_key(bid_pred) {
|
||||||
|
idom = Some(intersect_idom(idom, *bid_pred, &irpo, &idoms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(idom) = idom {
|
||||||
|
let _ = idoms
|
||||||
|
.entry(*bid)
|
||||||
|
.and_modify(|v| {
|
||||||
|
if *v != idom {
|
||||||
|
changed = true;
|
||||||
|
*v = idom;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_insert_with(|| {
|
||||||
|
changed = true;
|
||||||
|
idom
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !changed {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut inverse_idoms = HashMap::new();
|
||||||
|
for (bid, idom) in &idoms {
|
||||||
|
let _ = inverse_idoms
|
||||||
|
.entry(*idom)
|
||||||
|
.or_insert_with(HashSet::new)
|
||||||
|
.insert(*bid);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut frontiers = HashMap::new();
|
||||||
|
for (bid, preds) in reverse_cfg.iter().filter(|(_, preds)| preds.len() > 1) {
|
||||||
|
let idom = if let Some(idom) = idoms.get(bid) {
|
||||||
|
idom
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
for (bid_pred, _) in preds {
|
||||||
|
let mut runner = *bid_pred;
|
||||||
|
while !Self::dominates(&idoms, runner, *bid) {
|
||||||
|
frontiers.entry(runner).or_insert_with(Vec::new).push(*bid);
|
||||||
|
runner = idoms[&runner];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
idoms,
|
||||||
|
inverse_idoms,
|
||||||
|
frontiers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dominates(idoms: &HashMap<BlockId, BlockId>, bid1: BlockId, mut bid2: BlockId) -> bool {
|
||||||
|
loop {
|
||||||
|
bid2 = if let Some(idom2) = idoms.get(&bid2) {
|
||||||
|
*idom2
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if bid1 == bid2 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn idom(&self, bid: &BlockId) -> Option<&BlockId> {
|
||||||
|
self.idoms.get(bid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn successors(&self, bid: &BlockId) -> Option<&HashSet<BlockId>> {
|
||||||
|
self.inverse_idoms.get(bid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn frontiers(&self, bid: &BlockId) -> Option<&Vec<BlockId>> {
|
||||||
|
self.frontiers.get(bid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect_idom(
|
||||||
|
lhs: Option<BlockId>,
|
||||||
|
mut rhs: BlockId,
|
||||||
|
irpo: &HashMap<BlockId, usize>,
|
||||||
|
idoms: &HashMap<BlockId, BlockId>,
|
||||||
|
) -> BlockId {
|
||||||
|
let mut lhs = if let Some(lhs) = lhs { lhs } else { return rhs };
|
||||||
|
loop {
|
||||||
|
if lhs == rhs {
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
match irpo[&lhs].cmp(&irpo[&rhs]) {
|
||||||
|
Ordering::Less => rhs = idoms[&rhs],
|
||||||
|
Ordering::Greater => lhs = idoms[&lhs],
|
||||||
|
Ordering::Equal => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn replace_instruction_operands(
|
||||||
|
inst: &mut Instruction,
|
||||||
|
replaces: &HashMap<RegisterId, Operand>,
|
||||||
|
) -> bool {
|
||||||
|
match inst {
|
||||||
|
Instruction::BinOp { lhs, rhs, .. } => {
|
||||||
|
let a = replace_operand(lhs, replaces);
|
||||||
|
let b = replace_operand(rhs, replaces);
|
||||||
|
a || b
|
||||||
|
}
|
||||||
|
Instruction::UnaryOp { operand, .. } => replace_operand(operand, replaces),
|
||||||
|
Instruction::Store { ptr, value } => {
|
||||||
|
let a = replace_operand(ptr, replaces);
|
||||||
|
let b = replace_operand(value, replaces);
|
||||||
|
a || b
|
||||||
|
}
|
||||||
|
Instruction::Load { ptr } => replace_operand(ptr, replaces),
|
||||||
|
Instruction::Call { callee, args, .. } => {
|
||||||
|
let mut changed = replace_operand(callee, replaces);
|
||||||
|
for arg in args.iter_mut() {
|
||||||
|
changed = replace_operand(arg, replaces) || changed;
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
Instruction::TypeCast { value, .. } => replace_operand(value, replaces),
|
||||||
|
Instruction::GetElementPtr { ptr, offset, .. } => {
|
||||||
|
let a = replace_operand(ptr, replaces);
|
||||||
|
let b = replace_operand(offset, replaces);
|
||||||
|
a || b
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn replace_exit_operands(
|
||||||
|
exit: &mut BlockExit,
|
||||||
|
replaces: &HashMap<RegisterId, Operand>,
|
||||||
|
) -> bool {
|
||||||
|
match exit {
|
||||||
|
BlockExit::Jump { arg } => {
|
||||||
|
let mut changed = false;
|
||||||
|
for arg in arg.args.iter_mut() {
|
||||||
|
changed = replace_operand(arg, replaces) || changed;
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
BlockExit::ConditionalJump {
|
||||||
|
condition,
|
||||||
|
arg_then,
|
||||||
|
arg_else,
|
||||||
|
} => {
|
||||||
|
let mut changed = replace_operand(condition, replaces);
|
||||||
|
for arg in arg_then.args.iter_mut() {
|
||||||
|
changed = replace_operand(arg, replaces) || changed;
|
||||||
|
}
|
||||||
|
for arg in arg_else.args.iter_mut() {
|
||||||
|
changed = replace_operand(arg, replaces) || changed;
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
BlockExit::Switch {
|
||||||
|
value,
|
||||||
|
default,
|
||||||
|
cases,
|
||||||
|
} => {
|
||||||
|
let mut changed = replace_operand(value, replaces);
|
||||||
|
for arg in default.args.iter_mut() {
|
||||||
|
changed = replace_operand(arg, replaces) || changed;
|
||||||
|
}
|
||||||
|
for (_, arg) in cases {
|
||||||
|
for arg in arg.args.iter_mut() {
|
||||||
|
changed = replace_operand(arg, replaces) || changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
BlockExit::Return { value } => replace_operand(value, replaces),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn replace_operand(
|
||||||
|
operand: &mut Operand,
|
||||||
|
replaces: &HashMap<RegisterId, Operand>,
|
||||||
|
) -> bool {
|
||||||
|
if let Operand::Register { rid, .. } = operand {
|
||||||
|
if let Some(new_operand) = replaces.get(rid) {
|
||||||
|
*operand = new_operand.clone();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|||||||
@@ -117,9 +117,9 @@ impl Optimize<FunctionDefinition> for SimplifyCfgMerge {
|
|||||||
|
|
||||||
for (bid, block) in &mut code.blocks {
|
for (bid, block) in &mut code.blocks {
|
||||||
for inst in block.instructions.iter_mut() {
|
for inst in block.instructions.iter_mut() {
|
||||||
replace_instruction_operands(inst, &replaces);
|
let _ = replace_instruction_operands(inst, &replaces);
|
||||||
}
|
}
|
||||||
replace_exit_operands(&mut block.exit, &replaces);
|
let _ = replace_exit_operands(&mut block.exit, &replaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
!merged_to.is_empty()
|
!merged_to.is_empty()
|
||||||
@@ -235,73 +235,3 @@ impl SimplifyCfgEmpty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_cfg(fdef: &FunctionDefinition) -> HashMap<BlockId, Vec<JumpArg>> {
|
|
||||||
fdef.blocks
|
|
||||||
.iter()
|
|
||||||
.map(|(bid, block)| {
|
|
||||||
let mut args = Vec::new();
|
|
||||||
match &block.exit {
|
|
||||||
BlockExit::Jump { arg } => args.push(arg.clone()),
|
|
||||||
BlockExit::ConditionalJump {
|
|
||||||
arg_then, arg_else, ..
|
|
||||||
} => {
|
|
||||||
args.push(arg_then.clone());
|
|
||||||
args.push(arg_else.clone());
|
|
||||||
}
|
|
||||||
BlockExit::Switch { default, cases, .. } => {
|
|
||||||
args.push(default.clone());
|
|
||||||
for (_, arg) in cases {
|
|
||||||
args.push(arg.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
(*bid, args)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_instruction_operands(inst: &mut Instruction, replaces: &HashMap<RegisterId, Operand>) {
|
|
||||||
match inst {
|
|
||||||
Instruction::BinOp { lhs, rhs, .. } => {
|
|
||||||
replace_operand(lhs, replaces);
|
|
||||||
replace_operand(rhs, replaces);
|
|
||||||
}
|
|
||||||
Instruction::UnaryOp { operand, .. } => replace_operand(operand, replaces),
|
|
||||||
Instruction::Store { ptr, value } => {
|
|
||||||
replace_operand(ptr, replaces);
|
|
||||||
replace_operand(value, replaces);
|
|
||||||
}
|
|
||||||
Instruction::Load { ptr } => replace_operand(ptr, replaces),
|
|
||||||
Instruction::Call { callee, args, .. } => {
|
|
||||||
replace_operand(callee, replaces);
|
|
||||||
for arg in args.iter_mut() {
|
|
||||||
replace_operand(arg, replaces);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Instruction::TypeCast { value, .. } => replace_operand(value, replaces),
|
|
||||||
Instruction::GetElementPtr { ptr, offset, .. } => {
|
|
||||||
replace_operand(ptr, replaces);
|
|
||||||
replace_operand(offset, replaces);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_exit_operands(exit: &mut BlockExit, replaces: &HashMap<RegisterId, Operand>) {
|
|
||||||
match exit {
|
|
||||||
BlockExit::ConditionalJump { condition, .. } => replace_operand(condition, replaces),
|
|
||||||
BlockExit::Switch { value, .. } => replace_operand(value, replaces),
|
|
||||||
BlockExit::Return { value } => replace_operand(value, replaces),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_operand(operand: &mut Operand, replaces: &HashMap<RegisterId, Operand>) {
|
|
||||||
if let Operand::Register { rid, .. } = operand {
|
|
||||||
if let Some(new_operand) = replaces.get(rid) {
|
|
||||||
*operand = new_operand.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user