[bugpoint] Cosmetic improvements;

- Mostly Rust improvements to make code look more idiomatic.
- Also reuses the code memory accross compilation, to avoid many
memory allocations.
This commit is contained in:
Benjamin Bouvier
2019-10-11 16:44:40 +02:00
parent 48ccb3e051
commit a5efd2a625
2 changed files with 56 additions and 73 deletions

View File

@@ -48,9 +48,7 @@ pub fn run(
match reduce(isa, func, verbose) { match reduce(isa, func, verbose) {
Ok((func, crash_msg)) => { Ok((func, crash_msg)) => {
println!("Crash message: {}", crash_msg); println!("Crash message: {}", crash_msg);
println!("\n{}", func); println!("\n{}", func);
println!( println!(
"{} ebbs {} insts -> {} ebbs {} insts", "{} ebbs {} insts -> {} ebbs {} insts",
orig_ebb_count, orig_ebb_count,
@@ -69,6 +67,7 @@ pub fn run(
enum MutationKind { enum MutationKind {
/// The mutation reduced the amount of instructions or ebbs. /// The mutation reduced the amount of instructions or ebbs.
Shrinked, Shrinked,
/// The mutation only changed an instruction. Performing another round of mutations may only /// The mutation only changed an instruction. Performing another round of mutations may only
/// reduce the test case if another mutation shrank the test case. /// reduce the test case if another mutation shrank the test case.
Changed, Changed,
@@ -83,7 +82,7 @@ trait Mutator {
fn reduce( fn reduce(
&mut self, &mut self,
ccc: &mut CrashCheckContext, context: &mut CrashCheckContext,
mut func: Function, mut func: Function,
progress_bar_prefix: String, progress_bar_prefix: String,
verbose: bool, verbose: bool,
@@ -111,7 +110,7 @@ trait Mutator {
progress.set_message(&msg); progress.set_message(&msg);
match ccc.check_for_crash(&mutated_func) { match context.check_for_crash(&mutated_func) {
CheckResult::Succeed => { CheckResult::Succeed => {
// Shrinking didn't hit the problem anymore, discard changes. // Shrinking didn't hit the problem anymore, discard changes.
continue; continue;
@@ -170,28 +169,17 @@ impl Mutator for RemoveInst {
} }
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> { fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> {
if let Some((prev_ebb, prev_inst)) = next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst).map(|(prev_ebb, prev_inst)| {
next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst)
{
func.layout.remove_inst(prev_inst); func.layout.remove_inst(prev_inst);
if func.layout.ebb_insts(prev_ebb).next().is_none() { let msg = if func.layout.ebb_insts(prev_ebb).next().is_none() {
// Make sure empty ebbs are removed, as `next_inst_ret_prev` depends on non empty ebbs // Make sure empty ebbs are removed, as `next_inst_ret_prev` depends on non empty ebbs
func.layout.remove_ebb(prev_ebb); func.layout.remove_ebb(prev_ebb);
Some(( format!("Remove inst {} and empty ebb {}", prev_inst, prev_ebb)
func,
format!("Remove inst {} and empty ebb {}", prev_inst, prev_ebb),
MutationKind::Shrinked,
))
} else { } else {
Some(( format!("Remove inst {}", prev_inst)
func, };
format!("Remove inst {}", prev_inst), (func, msg, MutationKind::Shrinked)
MutationKind::Shrinked, })
))
}
} else {
None
}
} }
} }
@@ -222,24 +210,18 @@ impl Mutator for ReplaceInstWithIconst {
} }
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> { fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> {
if let Some((_prev_ebb, prev_inst)) = next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst).map(|(_prev_ebb, prev_inst)| {
next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst)
{
let results = func.dfg.inst_results(prev_inst); let results = func.dfg.inst_results(prev_inst);
if results.len() == 1 { let msg = if results.len() == 1 {
let ty = func.dfg.value_type(results[0]); let ty = func.dfg.value_type(results[0]);
func.dfg.replace(prev_inst).iconst(ty, 0); func.dfg.replace(prev_inst).iconst(ty, 0);
Some(( format!("Replace inst {} with iconst.{}", prev_inst, ty)
func,
format!("Replace inst {} with iconst.{}", prev_inst, ty),
MutationKind::Changed,
))
} else { } else {
Some((func, format!(""), MutationKind::Changed)) // Returns something so the harness tries replacement on following instructions.
} format!("")
} else { };
None (func, msg, MutationKind::Changed)
} })
} }
} }
@@ -270,18 +252,14 @@ impl Mutator for ReplaceInstWithTrap {
} }
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> { fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> {
if let Some((_prev_ebb, prev_inst)) = next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst).map(|(_prev_ebb, prev_inst)| {
next_inst_ret_prev(&func, &mut self.ebb, &mut self.inst)
{
func.dfg.replace(prev_inst).trap(TrapCode::User(0)); func.dfg.replace(prev_inst).trap(TrapCode::User(0));
Some(( (
func, func,
format!("Replace inst {} with trap", prev_inst), format!("Replace inst {} with trap", prev_inst),
MutationKind::Changed, MutationKind::Changed,
)) )
} else { })
None
}
} }
} }
@@ -308,20 +286,18 @@ impl Mutator for RemoveEbb {
} }
fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> { fn mutate(&mut self, mut func: Function) -> Option<(Function, String, MutationKind)> {
if let Some(next_ebb) = func.layout.next_ebb(self.ebb) { func.layout.next_ebb(self.ebb).map(|next_ebb| {
self.ebb = next_ebb; self.ebb = next_ebb;
while let Some(inst) = func.layout.last_inst(self.ebb) { while let Some(inst) = func.layout.last_inst(self.ebb) {
func.layout.remove_inst(inst); func.layout.remove_inst(inst);
} }
func.layout.remove_ebb(self.ebb); func.layout.remove_ebb(self.ebb);
Some(( (
func, func,
format!("Remove ebb {}", next_ebb), format!("Remove ebb {}", next_ebb),
MutationKind::Shrinked, MutationKind::Shrinked,
)) )
} else { })
None
}
} }
} }
@@ -568,13 +544,13 @@ fn next_inst_ret_prev(func: &Function, ebb: &mut Ebb, inst: &mut Inst) -> Option
if let Some(next_inst) = func.layout.next_inst(*inst) { if let Some(next_inst) = func.layout.next_inst(*inst) {
*inst = next_inst; *inst = next_inst;
return Some(prev); return Some(prev);
} else if let Some(next_ebb) = func.layout.next_ebb(*ebb) { }
if let Some(next_ebb) = func.layout.next_ebb(*ebb) {
*ebb = next_ebb; *ebb = next_ebb;
*inst = func.layout.first_inst(*ebb).expect("no inst"); *inst = func.layout.first_inst(*ebb).expect("no inst");
return Some(prev); return Some(prev);
} else {
return None;
} }
None
} }
fn ebb_count(func: &Function) -> usize { fn ebb_count(func: &Function) -> usize {
@@ -601,12 +577,12 @@ fn reduce(
mut func: Function, mut func: Function,
verbose: bool, verbose: bool,
) -> Result<(Function, String), String> { ) -> Result<(Function, String), String> {
let mut ccc = CrashCheckContext::new(isa); let mut context = CrashCheckContext::new(isa);
match ccc.check_for_crash(&func) { match context.check_for_crash(&func) {
CheckResult::Succeed => { CheckResult::Succeed => {
return Err(format!( return Err(format!(
"Given function compiled successfully or gave an verifier error." "Given function compiled successfully or gave a verifier error."
)); ));
} }
CheckResult::Crash(_) => {} CheckResult::Crash(_) => {}
@@ -619,17 +595,17 @@ fn reduce(
let mut phase = 0; let mut phase = 0;
loop { loop {
let mut mutator = match phase { let mut mutator: Box<dyn Mutator> = match phase {
0 => Box::new(RemoveInst::new(&func)) as Box<dyn Mutator>, 0 => Box::new(RemoveInst::new(&func)),
1 => Box::new(ReplaceInstWithIconst::new(&func)) as Box<dyn Mutator>, 1 => Box::new(ReplaceInstWithIconst::new(&func)),
2 => Box::new(ReplaceInstWithTrap::new(&func)) as Box<dyn Mutator>, 2 => Box::new(ReplaceInstWithTrap::new(&func)),
3 => Box::new(RemoveEbb::new(&func)) as Box<dyn Mutator>, 3 => Box::new(RemoveEbb::new(&func)),
4 => Box::new(RemoveUnusedEntities::new()) as Box<dyn Mutator>, 4 => Box::new(RemoveUnusedEntities::new()),
_ => break, _ => break,
}; };
func = mutator.reduce( func = mutator.reduce(
&mut ccc, &mut context,
func, func,
format!("pass {}", pass_idx), format!("pass {}", pass_idx),
verbose, verbose,
@@ -646,7 +622,7 @@ fn reduce(
} }
} }
let crash_msg = match ccc.check_for_crash(&func) { let crash_msg = match context.check_for_crash(&func) {
CheckResult::Succeed => unreachable!("Used to crash, but doesn't anymore???"), CheckResult::Succeed => unreachable!("Used to crash, but doesn't anymore???"),
CheckResult::Crash(crash_msg) => crash_msg, CheckResult::Crash(crash_msg) => crash_msg,
}; };
@@ -658,18 +634,23 @@ struct CrashCheckContext<'a> {
/// Cached `Context`, to prevent repeated allocation. /// Cached `Context`, to prevent repeated allocation.
context: Context, context: Context,
/// Cached code memory, to prevent repeated allocation.
code_memory: Vec<u8>,
/// The target isa to compile for. /// The target isa to compile for.
isa: &'a dyn TargetIsa, isa: &'a dyn TargetIsa,
} }
fn get_panic_string(panic: Box<dyn std::any::Any>) -> String { fn get_panic_string(panic: Box<dyn std::any::Any>) -> String {
let panic = match panic.downcast::<&'static str>() { let panic = match panic.downcast::<&'static str>() {
Ok(panic_msg) => panic_msg.to_owned(), Ok(panic_msg) => {
return panic_msg.to_string();
}
Err(panic) => panic, Err(panic) => panic,
}; };
match panic.downcast::<String>() { match panic.downcast::<String>() {
Ok(panic_msg) => *panic_msg, Ok(panic_msg) => *panic_msg,
Err(_) => "Box<Any>".to_owned(), Err(_) => "Box<Any>".to_string(),
} }
} }
@@ -685,6 +666,7 @@ impl<'a> CrashCheckContext<'a> {
fn new(isa: &'a dyn TargetIsa) -> Self { fn new(isa: &'a dyn TargetIsa) -> Self {
CrashCheckContext { CrashCheckContext {
context: Context::new(), context: Context::new(),
code_memory: Vec::new(),
isa, isa,
} }
} }
@@ -692,6 +674,8 @@ impl<'a> CrashCheckContext<'a> {
#[cfg_attr(test, allow(unreachable_code))] #[cfg_attr(test, allow(unreachable_code))]
fn check_for_crash(&mut self, func: &Function) -> CheckResult { fn check_for_crash(&mut self, func: &Function) -> CheckResult {
self.context.clear(); self.context.clear();
self.code_memory.clear();
self.context.func = func.clone(); self.context.func = func.clone();
use std::io::Write; use std::io::Write;
@@ -702,9 +686,9 @@ impl<'a> CrashCheckContext<'a> {
})) { })) {
Ok(Some(_)) => return CheckResult::Succeed, Ok(Some(_)) => return CheckResult::Succeed,
Ok(None) => {} Ok(None) => {}
// The verifier panicked. compiling it will probably give the same panic. // The verifier panicked. Compiling it will probably give the same panic.
// We treat it as succeeding to make it possible to reduce for the actual error. // We treat it as succeeding to make it possible to reduce for the actual error.
// FIXME prevent verifier panic on removing ebb1 // FIXME prevent verifier panic on removing ebb0.
Err(_) => return CheckResult::Succeed, Err(_) => return CheckResult::Succeed,
} }
@@ -732,11 +716,10 @@ impl<'a> CrashCheckContext<'a> {
let mut relocs = PrintRelocs::new(false); let mut relocs = PrintRelocs::new(false);
let mut traps = PrintTraps::new(false); let mut traps = PrintTraps::new(false);
let mut stackmaps = PrintStackmaps::new(false); let mut stackmaps = PrintStackmaps::new(false);
let mut mem = vec![];
let _ = self.context.compile_and_emit( let _ = self.context.compile_and_emit(
self.isa, self.isa,
&mut mem, &mut self.code_memory,
&mut relocs, &mut relocs,
&mut traps, &mut traps,
&mut stackmaps, &mut stackmaps,

View File

@@ -9,7 +9,7 @@ pub struct PrintRelocs {
} }
impl PrintRelocs { impl PrintRelocs {
pub fn new(flag_print: bool) -> PrintRelocs { pub fn new(flag_print: bool) -> Self {
Self { Self {
flag_print, flag_print,
text: String::new(), text: String::new(),
@@ -80,7 +80,7 @@ pub struct PrintTraps {
} }
impl PrintTraps { impl PrintTraps {
pub fn new(flag_print: bool) -> PrintTraps { pub fn new(flag_print: bool) -> Self {
Self { Self {
flag_print, flag_print,
text: String::new(), text: String::new(),
@@ -102,7 +102,7 @@ pub struct PrintStackmaps {
} }
impl PrintStackmaps { impl PrintStackmaps {
pub fn new(flag_print: bool) -> PrintStackmaps { pub fn new(flag_print: bool) -> Self {
Self { Self {
flag_print, flag_print,
text: String::new(), text: String::new(),