From f4dc5e426c200f6415858a113e2628ef0dd7ee95 Mon Sep 17 00:00:00 2001 From: Jeehoon Kang Date: Sat, 2 May 2020 07:52:40 +0000 Subject: [PATCH] Update skeleton --- examples/c/shift.c | 2 +- examples/gvn/gvn.input.ir | 44 ++++++++++++++++++++++++++++ examples/gvn/gvn.output.ir | 46 ++++++++++++++++++++++++++++++ examples/mem2reg/mem2reg.output.ir | 6 ++-- src/ir/mod.rs | 6 ++-- src/ir/parse.rs | 2 +- src/opt/gvn.rs | 2 +- src/opt/opt_utils.rs | 3 ++ src/tests.rs | 24 ++++++++++++++-- tests/reduce-criteria-template.sh | 13 +++++++-- tests/test_examples.rs | 9 ++++++ 11 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 examples/gvn/gvn.input.ir create mode 100644 examples/gvn/gvn.output.ir diff --git a/examples/c/shift.c b/examples/c/shift.c index fc99bad..6fb982a 100644 --- a/examples/c/shift.c +++ b/examples/c/shift.c @@ -1,5 +1,5 @@ int main() { - char a = -1; + char a = 127; char b = a << 1; unsigned char c = (unsigned char)b >> 1; diff --git a/examples/gvn/gvn.input.ir b/examples/gvn/gvn.input.ir new file mode 100644 index 0000000..9250748 --- /dev/null +++ b/examples/gvn/gvn.input.ir @@ -0,0 +1,44 @@ +fun unit @sink { +init: + bid: b0 + allocations: + +block b0: + %b0:p0:i32 + ret unit:unit +} + +fun i32 @gvn { +init: + bid: b0 + allocations: + +block b0: + %b0:p0:i32:a + %b0:i0:i32:b = add %b0:p0:i32 1:i32 + br undef:i1 b1() b2() + +block b1: + %b1:i0:i32:b = add %b0:p0:i32 1:i32 + %b1:i1:i32:c = add %b1:i0:i32 2:i32 + + %b1:i2:unit = call @sink(%b1:i0:i32) + + j b3() + +block b2: + %b2:i0:i32:c = add %b0:i0:i32 2:i32 + + %b2:i1:unit = call @sink(%b2:i0:i32) + + j b3() + +block b3: + %b3:i0:i32:b = add %b0:p0:i32 1:i32 + %b3:i1:i32:c = add %b3:i0:i32 2:i32 + + %b3:i2:unit = call @sink(%b3:i0:i32) + %b3:i3:unit = call @sink(%b3:i1:i32) + + ret 0:i32 +} diff --git a/examples/gvn/gvn.output.ir b/examples/gvn/gvn.output.ir new file mode 100644 index 0000000..305af0b --- /dev/null +++ b/examples/gvn/gvn.output.ir @@ -0,0 +1,46 @@ +fun unit @sink { +init: + bid: b0 + allocations: + +block b0: + %b0:p0:i32 + ret unit:unit +} + +fun i32 @gvn { +init: + bid: b0 + allocations: + +block b0: + %b0:p0:i32:a + %b0:i0:i32:b = add %b0:p0:i32 1:i32 + br undef:i1 b1() b2() + +block b1: + %b1:i0:i32:b = add %b0:p0:i32 1:i32 + %b1:i1:i32:c = add %b0:i0:i32 2:i32 + + %b1:i2:unit = call @sink(%b0:i0:i32) + + j b3(%b1:i1:i32) + +block b2: + %b2:i0:i32:c = add %b0:i0:i32 2:i32 + + %b2:i1:unit = call @sink(%b2:i0:i32) + + j b3(%b2:i0:i32) + +block b3: + %b3:p0:i32 + + %b3:i0:i32:b = add %b0:p0:i32 1:i32 + %b3:i1:i32:c = add %b0:i0:i32 2:i32 + + %b3:i2:unit = call @sink(%b0:i0:i32) + %b3:i3:unit = call @sink(%b3:p0:i32) + + ret 0:i32 +} diff --git a/examples/mem2reg/mem2reg.output.ir b/examples/mem2reg/mem2reg.output.ir index 742aa13..97b33e1 100644 --- a/examples/mem2reg/mem2reg.output.ir +++ b/examples/mem2reg/mem2reg.output.ir @@ -45,17 +45,15 @@ block b0: %b0:i3:unit = nop %b0:i4:i32 = load %l0:*i32 - j b1(37:i32) + j b1() block b1: - %b1:p0:i32:x - %b1:i0:i32 = load %l0:*i32 %b1:i1:unit = call @sink(undef:i32) %b1:i2:unit = call @sink(42:i32) %b1:i3:unit = call @sink(37:i32) - %b1:i4:unit = call @sink(%b1:p0:i32) + %b1:i4:unit = call @sink(37:i32) ret 0:i32 } diff --git a/src/ir/mod.rs b/src/ir/mod.rs index fe30ae5..959b461 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -9,7 +9,7 @@ use core::ops::{Deref, DerefMut}; use hexf::{parse_hexf32, parse_hexf64}; use lang_c::ast; use ordered_float::OrderedFloat; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::hash::{Hash, Hasher}; pub use dtype::{Dtype, DtypeError, HasDtype}; @@ -18,7 +18,7 @@ pub use parse::Parse; #[derive(Debug, Clone, PartialEq)] pub struct TranslationUnit { - pub decls: HashMap, + pub decls: BTreeMap, pub structs: HashMap>, } @@ -161,7 +161,7 @@ pub struct FunctionDefinition { pub allocations: Vec>, /// Basic blocks. - pub blocks: HashMap, + pub blocks: BTreeMap, /// The initial block id. pub bid_init: BlockId, diff --git a/src/ir/parse.rs b/src/ir/parse.rs index bbe415c..6bedc45 100644 --- a/src/ir/parse.rs +++ b/src/ir/parse.rs @@ -16,7 +16,7 @@ peg::parser! { pub rule translation_unit() -> TranslationUnit = _ ds:(named_decl() ** __) _ { - let mut decls = HashMap::new(); + let mut decls = BTreeMap::new(); for decl in ds { let result = decls.insert(decl.name.unwrap(), decl.inner); assert!(result.is_none()); diff --git a/src/opt/gvn.rs b/src/opt/gvn.rs index ac50254..8e6a942 100644 --- a/src/opt/gvn.rs +++ b/src/opt/gvn.rs @@ -1,7 +1,7 @@ use crate::opt::FunctionPass; use crate::*; -pub type Gvn = FunctionPass>; +pub type Gvn = FunctionPass; #[derive(Default)] pub struct GvnInner {} diff --git a/src/opt/opt_utils.rs b/src/opt/opt_utils.rs index e69de29..9199548 100644 --- a/src/opt/opt_utils.rs +++ b/src/opt/opt_utils.rs @@ -0,0 +1,3 @@ +//! Utilities for implementing optimizations. +//! +//! You can add here utilities commonly used in the implementation of multiple optimizations. diff --git a/src/tests.rs b/src/tests.rs index 2b0451d..51cc52f 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,6 +1,6 @@ use lang_c::ast::*; use std::fs::{self, File}; -use std::io::{stderr, Write}; +use std::io::{stderr, Read, Write}; use std::path::Path; use std::process::{Command, Stdio}; use tempfile::tempdir; @@ -41,7 +41,14 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) { // Compile c file: If fails, test is vacuously success if !Command::new("gcc") - .args(&["-O1", &file_path, "-o", &bin_path]) + .args(&[ + "-fsanitize=undefined", + "-fno-sanitize-recover=all", + "-O1", + &file_path, + "-o", + &bin_path, + ]) .stderr(Stdio::null()) .status() .unwrap() @@ -52,6 +59,7 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) { // Execute compiled executable let mut child = Command::new(fs::canonicalize(bin_path.clone()).unwrap()) + .stderr(Stdio::piped()) .spawn() .expect("failed to execute the compiled executable"); @@ -71,6 +79,18 @@ pub fn test_irgen(unit: &TranslationUnit, path: &Path) { ::std::process::exit(SKIP_TEST); } ); + + if child + .stderr + .expect("`stderr` of `child` must be `Some`") + .bytes() + .next() + .is_some() + { + println!("error occurs"); + ::std::process::exit(SKIP_TEST); + } + let status = some_or_exit!(status.code(), SKIP_TEST); let ir = match Irgen::default().translate(unit) { diff --git a/tests/reduce-criteria-template.sh b/tests/reduce-criteria-template.sh index d43a352..e567894 100644 --- a/tests/reduce-criteria-template.sh +++ b/tests/reduce-criteria-template.sh @@ -30,6 +30,7 @@ if grep 'too many arguments in call' out.txt ||\ grep 'declaration does not declare anything' out.txt ||\ grep 'not equal to a null pointer is always true' out.txt ||\ + grep 'empty struct is a GNU extension' out.txt ||\ ! gcc -Wall -Wextra -O2 test_reduced.c > outa.txt 2>&1 ||\ grep 'uninitialized' outa.txt ||\ grep 'without a cast' outa.txt ||\ @@ -49,10 +50,16 @@ if grep 'excess elements in struct initializer' outa.txt ||\ grep 'comparison between pointer and integer' outa.txt ||\ ! gcc -O1 test_reduced.c > cc_out1.txt 2>&1 ||\ - ! gcc -O2 test_reduced.c > cc_out2.txt 2>&1) + ! gcc -O2 test_reduced.c > cc_out2.txt 2>&1 ||\ + ! cargo run --manifest-path $PROJECT_DIR/Cargo.toml --release -- --parse test_reduced.c >/dev/null 2>&1) then exit 1 fi -cargo run --manifest-path $PROJECT_DIR/Cargo.toml --release -- --parse test_reduced.c >/dev/null 2>&1 &&\ -! cargo run --manifest-path $PROJECT_DIR/Cargo.toml --release --bin fuzz -- $FUZZ_ARG test_reduced.c +cargo run --manifest-path $PROJECT_DIR/Cargo.toml --release --bin fuzz -- $FUZZ_ARG test_reduced.c +if [ "$?" = 101 ] +then + exit 0 +else + exit 1 +fi diff --git a/tests/test_examples.rs b/tests/test_examples.rs index b4830be..0ee2a34 100644 --- a/tests/test_examples.rs +++ b/tests/test_examples.rs @@ -83,3 +83,12 @@ fn test_examples_mem2reg() { &mut Mem2reg::default(), ); } + +#[test] +fn test_examples_gvn() { + test_opt( + &Path::new("examples/gvn/gvn.input.ir"), + &Path::new("examples/gvn/gvn.output.ir"), + &mut Gvn::default(), + ); +}