Commit 9be20de9 authored by qinsoon's avatar qinsoon

implemented loop analysis

parent eb657c64
......@@ -15,7 +15,7 @@
/// A instruction selection pass. Uses simple tree pattern matching.
pub mod inst_sel;
/// A Dominator Tree pass for machine code.
pub mod mc_domtree;
pub mod mc_loopanalysis;
/// A register allocation pass. Graph coloring.
pub mod reg_alloc;
/// A peephole optimization pass after register allocation.
......
......@@ -16,13 +16,13 @@ use ast::ir::*;
use ast::ptr::*;
use compiler;
use compiler::frame::*;
use compiler::backend::mc_loopanalysis::MCLoopAnalysisResult;
use runtime::ValueLocation;
use rodal;
use utils::Address;
use utils::LinkedHashMap;
use std::sync::Arc;
use utils::{LinkedHashMap, LinkedHashSet};
use runtime::resolve_symbol;
use rodal;
use std::sync::Arc;
use std;
use std::ops;
use std::collections::HashMap;
......@@ -54,7 +54,10 @@ pub struct CompiledFunction {
/// start location of this compiled function
pub start: ValueLocation,
/// end location of this compiled function
pub end: ValueLocation
pub end: ValueLocation,
/// results of machine code loop analysis
pub loop_analysis: Option<Box<MCLoopAnalysisResult>>
}
rodal_named!(CompiledFunction);
unsafe impl rodal::Dump for CompiledFunction {
......@@ -92,7 +95,8 @@ impl CompiledFunction {
mc: Some(mc),
frame: frame,
start: start_loc,
end: end_loc
end: end_loc,
loop_analysis: None
}
}
......@@ -332,7 +336,7 @@ pub trait MachineCode {
succs: succs
};
trace!("CFGNode {:?}", node);
trace!("{:?}", node);
ret.inner.insert(block.clone(), node);
}
......@@ -362,6 +366,66 @@ impl MachineCFG {
pub fn get_succs(&self, block: &MuName) -> &Vec<MuName> {
&self.inner.get(block).unwrap().succs
}
pub fn has_edge(&self, from: &MuName, to: &MuName) -> bool {
if self.inner.contains_key(from) {
let ref node = self.inner.get(from).unwrap();
for succ in node.succs.iter() {
if succ == to {
return true;
}
}
}
false
}
/// checks if there exists a path between from and to, without excluded node
pub fn has_path_with_node_excluded(
&self,
from: &MuName,
to: &MuName,
exclude_node: &MuName
) -> bool {
// we cannot exclude start and end of the path
assert!(exclude_node != from && exclude_node != to);
if from == to {
true
} else {
// we are doing BFS
// visited nodes
let mut visited: LinkedHashSet<&MuName> = LinkedHashSet::new();
// work queue
let mut work_list: Vec<&MuName> = vec![];
// initialize visited nodes, and work queue
visited.insert(from);
work_list.push(from);
while !work_list.is_empty() {
let n = work_list.pop().unwrap();
for succ in self.get_succs(n) {
if succ == exclude_node {
// we are not going to follow a path with the excluded node
continue;
} else {
// if we are reaching destination, return true
if succ == to {
return true;
}
// push succ to work list so we will traverse them later
if !visited.contains(succ) {
visited.insert(succ);
work_list.push(succ);
}
}
}
}
false
}
}
}
/// MachineCFGNode represents a block in machine code control flow graph
......
......@@ -111,7 +111,7 @@ impl Default for CompilerPolicy {
// compilation
passes.push(Box::new(backend::inst_sel::InstructionSelection::new()));
passes.push(Box::new(backend::mc_domtree::MCDomTree::new()));
passes.push(Box::new(backend::mc_loopanalysis::MCLoopAnalysis::new()));
passes.push(Box::new(backend::reg_alloc::RegisterAllocation::new()));
// machine code level passes
......
......@@ -62,12 +62,16 @@ mod linked_hashmap;
mod linked_hashset;
/// linked multi-key hashmap implementation
mod linked_multimap;
/// tree implementation
mod tree;
// re-export these data structures
pub use linked_hashmap::LinkedHashMap;
pub use linked_hashset::LinkedHashSet;
pub use linked_multimap::LinkedMultiMap;
pub use linked_multimap::LinkedRepeatableMultiMap;
pub use tree::Tree;
pub use self::doubly::DoublyLinkedList;
/// mem module:
......
......@@ -157,6 +157,25 @@ impl<K: Hash + Eq, S: BuildHasher> LinkedHashSet<K, S> {
}
}
impl<K: Hash + Eq> PartialEq for LinkedHashSet<K> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
for ele in self.iter() {
if !other.contains(ele) {
return false;
}
}
true
}
fn ne(&self, other: &Self) -> bool {
!self.eq(other)
}
}
impl<K: Hash + Eq> Eq for LinkedHashSet<K> {}
impl<K: Hash + Eq + Clone> Clone for LinkedHashSet<K> {
fn clone(&self) -> Self {
LinkedHashSet(self.0.clone())
......
......@@ -80,8 +80,71 @@ impl<K: Hash + Eq, V: Hash + Eq> LinkedMultiMap<K, V> {
impl<K: Hash + Eq + Debug, V: Hash + Eq + Debug> Debug for LinkedMultiMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "MultiMap").unwrap();
for (k, v) in self.iter() {
write!(f, "{:?} -> {:?}\n", k, v).unwrap();
writeln!(f, "{:?} -> {:?}", k, v).unwrap();
}
Ok(())
}
}
pub struct LinkedRepeatableMultiMap<K, V> {
inner: LinkedHashMap<K, Vec<V>>
}
impl<K: Hash + Eq, V> LinkedRepeatableMultiMap<K, V> {
pub fn new() -> LinkedRepeatableMultiMap<K, V> {
LinkedRepeatableMultiMap {
inner: LinkedHashMap::new()
}
}
pub fn insert(&mut self, k: K, v: V) {
if self.inner.contains_key(&k) {
self.inner.get_mut(&k).unwrap().push(v);
} else {
self.inner.insert(k, vec![v]);
}
}
pub fn insert_vec(&mut self, k: K, mut vec: Vec<V>) {
if self.inner.contains_key(&k) {
self.inner.get_mut(&k).unwrap().append(&mut vec);
} else {
self.inner.insert(k, vec);
}
}
pub fn replace_set(&mut self, k: K, vec: Vec<V>) {
self.inner.insert(k, vec);
}
pub fn get(&self, k: &K) -> Option<&Vec<V>> {
self.inner.get(k)
}
pub fn contains_key(&self, k: &K) -> bool {
self.inner.contains_key(k)
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn iter(&self) -> Iter<K, Vec<V>> {
self.inner.iter()
}
pub fn keys(&self) -> Keys<K, Vec<V>> {
self.inner.keys()
}
}
impl<K: Hash + Eq + Debug, V: Debug> Debug for LinkedRepeatableMultiMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "RepeatableMultiMap").unwrap();
for (k, v) in self.iter() {
writeln!(f, "{:?} -> {:?}", k, v).unwrap();
}
Ok(())
}
......
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use linked_multimap::LinkedMultiMap;
use linked_hashset::LinkedHashSet;
use std::fmt;
use std::hash::Hash;
pub struct Tree<T> {
edges: LinkedMultiMap<T, T>,
root: T
}
impl<T: Clone + Eq + Hash> Tree<T> {
pub fn new(root: T) -> Tree<T> {
Tree {
edges: LinkedMultiMap::new(),
root: root
}
}
pub fn root(&self) -> &T {
&self.root
}
pub fn insert(&mut self, parent: T, child: T) {
self.edges.insert(parent, child);
}
pub fn has_children(&self, n: &T) -> bool {
self.edges.contains_key(n)
}
pub fn get_children(&self, n: &T) -> &LinkedHashSet<T> {
assert!(self.edges.contains_key(n));
self.edges.get(n).unwrap()
}
pub fn get_all_descendants(&self, n: &T) -> LinkedHashSet<T> {
let mut set = LinkedHashSet::new();
self.add_descendant_node(n, &mut set);
set
}
fn add_descendant_node(&self, n: &T, set: &mut LinkedHashSet<T>) {
if self.edges.contains_key(n) {
for c in self.get_children(n).iter() {
self.add_descendant_node(c, set);
}
}
set.insert(n.clone());
}
}
impl<T: Clone + Eq + Hash + fmt::Debug> Tree<T> {
fn fmt_node(&self, f: &mut fmt::Formatter, indent: usize, node: &T) {
writeln!(
f,
"{}* {:?}",
(0..indent).map(|_| ' ').collect::<String>(),
node
).unwrap();
if self.edges.contains_key(node) {
for child in self.edges.get(node).unwrap().iter() {
self.fmt_node(f, indent + 1, child);
}
}
}
}
impl<T: Clone + Eq + Hash + fmt::Debug> fmt::Debug for Tree<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "\n").unwrap();
self.fmt_node(f, 0, &self.root);
Ok(())
}
}
......@@ -241,3 +241,39 @@ def test_exc_pass_values():
""", "test_exc_pass_values");
assert(execute("test_exc_pass_values") == 4);
def test_nest_loop():
lib = load_bundle(
"""
.funcdef nest_loop<(int<64>) -> (int<64>)>
{
entry(<int<64>> n):
BRANCH outer_header(n <int<64>> 0 <int<64>> 0)
outer_header(<int<64>> n <int<64>> i <int<64>> sum):
outer_cond = SLT <int<64>> i n
BRANCH2 outer_cond outer_body(n i sum) exit(sum)
outer_body(<int<64>> n <int<64>> i <int<64>> sum):
BRANCH inner_header(n i <int<64>> 0 sum)
outer_step(<int<64>> n <int<64>> i <int<64>> sum):
i2 = ADD <int<64>> i <int<64>> 1
BRANCH outer_header(n i2 sum)
inner_header(<int<64>> n <int<64>> i <int<64>> j <int<64>> sum):
inner_cond = SLT <int<64>> j i
BRANCH2 inner_cond inner_body(n i j sum) outer_step(n i sum)
inner_body(<int<64>> n <int<64>> i <int<64>> j <int<64>> sum):
sum2 = ADD <int<64>> sum j
j2 = ADD <int<64>> j <int<64>> 1
BRANCH inner_header(n i j2 sum2)
exit(<int<64>> sum):
RET sum
}
""", "nest_loop"
)
nest_loop = get_function(lib.nest_loop, [ctypes.c_int64], ctypes.c_int64)
assert(nest_loop(100) == 161700)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment