mirror of
https://github.com/kmc7468/cs420.git
synced 2025-12-16 15:38:48 +00:00
Fix hw1 fuzzer again
This commit is contained in:
14
src/opt/deadcode.rs
Normal file
14
src/opt/deadcode.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use crate::ir::*;
|
||||
use crate::opt::FunctionPass;
|
||||
use crate::*;
|
||||
|
||||
pub type Deadcode = FunctionPass<DeadcodeInner>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DeadcodeInner {}
|
||||
|
||||
impl Optimize<FunctionDefinition> for DeadcodeInner {
|
||||
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
|
||||
todo!("homework 6")
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
use crate::ir;
|
||||
use crate::opt::FunctionPass;
|
||||
use crate::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Gvn {}
|
||||
pub type Gvn = FunctionPass<Repeat<GvnInner>>;
|
||||
|
||||
impl Optimize<ir::TranslationUnit> for Gvn {
|
||||
fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool {
|
||||
todo!()
|
||||
#[derive(Default)]
|
||||
pub struct GvnInner {}
|
||||
|
||||
impl Optimize<ir::FunctionDefinition> for GvnInner {
|
||||
fn optimize(&mut self, _code: &mut ir::FunctionDefinition) -> bool {
|
||||
todo!("homework 5")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
use crate::ir;
|
||||
use crate::ir::*;
|
||||
use crate::opt::FunctionPass;
|
||||
use crate::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Mem2reg {}
|
||||
pub type Mem2reg = FunctionPass<Mem2regInner>;
|
||||
|
||||
impl Optimize<ir::TranslationUnit> for Mem2reg {
|
||||
fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool {
|
||||
todo!()
|
||||
#[derive(Default)]
|
||||
pub struct Mem2regInner {}
|
||||
|
||||
impl Optimize<FunctionDefinition> for Mem2regInner {
|
||||
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool {
|
||||
todo!("homework 4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,42 @@
|
||||
use crate::*;
|
||||
|
||||
mod deadcode;
|
||||
mod gvn;
|
||||
mod mem2reg;
|
||||
mod opt_utils;
|
||||
mod simplify_cfg;
|
||||
|
||||
pub use deadcode::Deadcode;
|
||||
pub use gvn::Gvn;
|
||||
pub use mem2reg::Mem2reg;
|
||||
pub use opt_utils::{
|
||||
make_cfg, make_domtree, replace_operand, replace_operands, reverse_cfg, Domtree, Walk,
|
||||
};
|
||||
pub use simplify_cfg::SimplifyCfg;
|
||||
|
||||
use crate::ir;
|
||||
|
||||
pub trait Translate<S> {
|
||||
type Target;
|
||||
type Error;
|
||||
|
||||
fn translate(&mut self, source: &S) -> Result<Self::Target, Self::Error>;
|
||||
}
|
||||
|
||||
pub trait Optimize<T> {
|
||||
fn optimize(&mut self, code: &mut T) -> bool;
|
||||
}
|
||||
|
||||
pub type O0 = Null;
|
||||
pub type O1 = Repeat<(SimplifyCfg, (Mem2reg, (Deadcode, Gvn)))>;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Null {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Repeat<O> {
|
||||
inner: O,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct O0 {}
|
||||
pub struct FunctionPass<T: Optimize<ir::FunctionDefinition>> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
pub type O1 = Repeat<(SimplifyCfg, (Mem2reg, Gvn))>;
|
||||
|
||||
impl Optimize<ir::TranslationUnit> for O0 {
|
||||
impl Optimize<ir::TranslationUnit> for Null {
|
||||
fn optimize(&mut self, _code: &mut ir::TranslationUnit) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -53,3 +60,23 @@ impl<T, O: Optimize<T>> Optimize<T> for Repeat<O> {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Optimize<ir::TranslationUnit> for FunctionPass<T>
|
||||
where
|
||||
T: Optimize<ir::FunctionDefinition>,
|
||||
{
|
||||
fn optimize(&mut self, code: &mut ir::TranslationUnit) -> bool {
|
||||
code.decls.iter_mut().any(|(_, decl)| self.optimize(decl))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Optimize<ir::Declaration> for FunctionPass<T>
|
||||
where
|
||||
T: Optimize<ir::FunctionDefinition>,
|
||||
{
|
||||
fn optimize(&mut self, code: &mut ir::Declaration) -> bool {
|
||||
let (_fsig, fdef) = some_or!(code.get_function_mut(), return false);
|
||||
let fdef = some_or!(fdef, return false);
|
||||
self.inner.optimize(fdef)
|
||||
}
|
||||
}
|
||||
|
||||
171
src/opt/opt_utils.rs
Normal file
171
src/opt/opt_utils.rs
Normal file
@@ -0,0 +1,171 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ir::*;
|
||||
|
||||
/// "Replace-all-uses-with".
|
||||
pub trait Walk {
|
||||
fn walk<F>(&mut self, f: F) -> bool
|
||||
where
|
||||
F: FnMut(&mut Operand) -> bool;
|
||||
}
|
||||
|
||||
impl Walk for FunctionDefinition {
|
||||
fn walk<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
F: FnMut(&mut Operand) -> bool,
|
||||
{
|
||||
self.blocks.iter_mut().any(|(_, block)| block.walk(&mut f))
|
||||
}
|
||||
}
|
||||
|
||||
impl Walk for Block {
|
||||
fn walk<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
F: FnMut(&mut Operand) -> bool,
|
||||
{
|
||||
self.instructions.iter_mut().any(|i| i.walk(&mut f)) || self.exit.walk(&mut f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Walk for Instruction {
|
||||
fn walk<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
F: FnMut(&mut Operand) -> bool,
|
||||
{
|
||||
match self {
|
||||
Self::Nop => false,
|
||||
Self::BinOp { lhs, rhs, .. } => lhs.walk(&mut f) || rhs.walk(&mut f),
|
||||
Self::UnaryOp { operand, .. } => operand.walk(&mut f),
|
||||
Self::Store { ptr, value } => ptr.walk(&mut f) || value.walk(&mut f),
|
||||
Self::Load { ptr } => ptr.walk(&mut f),
|
||||
Self::Call { callee, args, .. } => {
|
||||
callee.walk(&mut f) || args.iter_mut().any(|a| a.walk(&mut f))
|
||||
}
|
||||
Self::TypeCast { value, .. } => value.walk(&mut f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Walk for BlockExit {
|
||||
fn walk<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
F: FnMut(&mut Operand) -> bool,
|
||||
{
|
||||
match self {
|
||||
Self::Jump { arg } => arg.walk(&mut f),
|
||||
Self::ConditionalJump {
|
||||
condition,
|
||||
arg_then,
|
||||
arg_else,
|
||||
} => condition.walk(&mut f) || arg_then.walk(&mut f) || arg_else.walk(&mut f),
|
||||
Self::Switch {
|
||||
value,
|
||||
default,
|
||||
cases,
|
||||
} => {
|
||||
value.walk(&mut f)
|
||||
|| default.walk(&mut f)
|
||||
|| cases.iter_mut().any(|(_, a)| a.walk(&mut f))
|
||||
}
|
||||
Self::Return { value } => value.walk(&mut f),
|
||||
Self::Unreachable => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Walk for JumpArg {
|
||||
fn walk<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
F: FnMut(&mut Operand) -> bool,
|
||||
{
|
||||
self.args.iter_mut().any(|a| a.walk(&mut f))
|
||||
}
|
||||
}
|
||||
|
||||
impl Walk for Operand {
|
||||
fn walk<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
F: FnMut(&mut Operand) -> bool,
|
||||
{
|
||||
f(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_operand(operand: &mut Operand, from: &Operand, to: &Operand) -> bool {
|
||||
if operand == from {
|
||||
*operand = to.clone();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_operands(operand: &mut Operand, dict: &HashMap<RegisterId, Operand>) -> bool {
|
||||
if let Some((rid, dtype)) = operand.get_register_mut() {
|
||||
if let Some(val) = dict.get(rid) {
|
||||
assert_eq!(*dtype, val.dtype());
|
||||
*operand = val.clone();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn make_cfg(fdef: &FunctionDefinition) -> HashMap<BlockId, Vec<JumpArg>> {
|
||||
let mut result = HashMap::new();
|
||||
|
||||
for (bid, block) in &fdef.blocks {
|
||||
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());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
result.insert(*bid, args);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub 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
|
||||
}
|
||||
|
||||
pub struct Domtree {}
|
||||
|
||||
impl Domtree {
|
||||
pub fn walk<F>(&self, _f: F)
|
||||
where
|
||||
F: FnMut(BlockId, BlockId),
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_domtree(_cfg: &HashMap<BlockId, Vec<JumpArg>>) -> Domtree {
|
||||
todo!()
|
||||
}
|
||||
@@ -1,21 +1,9 @@
|
||||
use crate::ir::*;
|
||||
use crate::opt::FunctionPass;
|
||||
use crate::*;
|
||||
|
||||
pub type SimplifyCfg = Repeat<(SimplifyCfgConstProp, (SimplifyCfgReach, SimplifyCfgMerge))>;
|
||||
|
||||
impl Optimize<TranslationUnit> for SimplifyCfg {
|
||||
fn optimize(&mut self, code: &mut TranslationUnit) -> bool {
|
||||
code.decls.iter_mut().any(|(_, decl)| self.optimize(decl))
|
||||
}
|
||||
}
|
||||
|
||||
impl Optimize<Declaration> for SimplifyCfg {
|
||||
fn optimize(&mut self, code: &mut Declaration) -> bool {
|
||||
let (_fsig, fdef) = some_or!(code.get_function_mut(), return false);
|
||||
let fdef = some_or!(fdef, return false);
|
||||
self.optimize(fdef)
|
||||
}
|
||||
}
|
||||
pub type SimplifyCfg =
|
||||
FunctionPass<Repeat<(SimplifyCfgConstProp, (SimplifyCfgReach, SimplifyCfgMerge))>>;
|
||||
|
||||
/// Simplifies block exits by propagating constants.
|
||||
#[derive(Default)]
|
||||
|
||||
Reference in New Issue
Block a user