Fix hw1 fuzzer again

This commit is contained in:
Jeehoon Kang
2020-03-28 18:29:04 +09:00
parent 938390821f
commit 2a5a5e71ed
21 changed files with 500 additions and 110 deletions

14
src/opt/deadcode.rs Normal file
View 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")
}
}

View File

@@ -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")
}
}

View File

@@ -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")
}
}

View File

@@ -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
View 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!()
}

View File

@@ -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)]