Commit eb657c64 authored by qinsoon's avatar qinsoon

[wip] mc domtree - dominators, idom

parent 5a40d427
Pipeline #1239 passed with stages
in 54 minutes and 55 seconds
// 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 compiler::CompilerPass;
use ast::ir::*;
use vm::VM;
use compiler::machine_code::*;
use compiler::backend;
use std::any::Any;
use utils::LinkedHashMap;
use utils::LinkedHashSet;
use utils::LinkedMultiMap;
const TRACE_DOMTREE: bool = true;
pub struct MCDomTree {
name: &'static str
}
impl CompilerPass for MCDomTree {
fn name(&self) -> &'static str {
self.name
}
fn as_any(&self) -> &Any {
self
}
fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
let compiled_funcs = vm.compiled_funcs().read().unwrap();
let mut cf = compiled_funcs.get(&func.id()).unwrap().write().unwrap();
let cfg = cf.mc().build_cfg();
let dominators = compute_dominators(&cf, &cfg);
trace!("dominators:");
trace!("{:?}", dominators);
let idoms = compute_immediate_dominators(&dominators);
trace!("immediate dominators:");
trace!("{:?}", idoms);
}
}
impl MCDomTree {
pub fn new() -> MCDomTree {
MCDomTree {
name: "Compute Machine Code Dom Tree"
}
}
}
fn compute_dominators(func: &CompiledFunction, cfg: &MachineCFG) -> LinkedMultiMap<MuName, MuName> {
let mc = func.mc();
// D[s0] = s0
// D[n] = {n} \/ ( /\ D[p] for all p in pred[n])
// use iterative algorithm to compute dominators
// init dominators:
let mut dominators = LinkedMultiMap::new();
// D[s0] = s0;
let entry = mc.get_prologue_block();
dominators.insert(entry.clone(), entry.clone());
// D[n] (n!=s0) = all the blocks
let all_blocks = LinkedHashSet::from_vec(mc.get_all_blocks());
for block in mc.get_all_blocks() {
if block != entry {
dominators.insert_set(block.clone(), all_blocks.clone());
}
}
// iteration - start with a work queue of all successors of entry block
let mut work_queue: LinkedHashSet<MuName> =
LinkedHashSet::from_vec(cfg.get_succs(&entry).clone());
while let Some(cur) = work_queue.pop_front() {
let preds = cfg.get_preds(&cur);
let new_set = {
// ( /\ D[p] for all p in pred[n])
let mut intersect: LinkedHashSet<MuName> = LinkedHashSet::new();
// add the first predecessor's dominators
for dp in dominators.get(&preds[0]).unwrap().iter() {
intersect.insert(dp.clone());
}
// retain the first predecessors's dominators with the rest
for p in preds.iter() {
let dp_set = dominators.get(p).unwrap();
intersect.retain(|x| dp_set.contains(x));
}
// union {n} with intersect
let mut union: LinkedHashSet<MuName> = LinkedHashSet::new();
union.insert(cur.clone());
union.add_all(intersect);
union
};
if new_set.equals(dominators.get(&cur).unwrap()) {
// no change, nothing
} else {
// otherwise set dominator as current set
dominators.replace_set(cur.clone(), new_set);
// add successors to work queue
work_queue.add_from_vec(cfg.get_succs(&cur).clone());
}
}
dominators
}
fn compute_immediate_dominators(dominators: &LinkedMultiMap<MuName, MuName>)
-> LinkedHashMap<MuName, MuName> {
let mut immediate_doms: LinkedHashMap<MuName, MuName> = LinkedHashMap::new();
for (n, doms) in dominators.iter() {
trace_if!(TRACE_DOMTREE, "compute idom(n={:?})", n);
// check which dominator idom from doms is the immediate dominator
// 1. idom is not n
// 2. idom dominates n (for sure if we find idom from n's dominators)
// 3. idom does not dominate any other dominator of n
for candidate in doms.iter() {
trace_if!(TRACE_DOMTREE, " check candidate {:?}", candidate);
// idom is not n
if candidate != n {
let mut candidate_is_idom = true;
// candidate does not dominate any other dominator of n
for d in doms.iter() {
trace_if!(TRACE_DOMTREE, " check if {:?} doms d={:?}", candidate, d);
if d != candidate && d != n {
if is_dom(candidate, d, &dominators) {
trace_if!(
TRACE_DOMTREE,
" failed, as {:?} dominates other dominator {:?}",
candidate,
d
);
candidate_is_idom = false;
}
} else {
trace_if!(TRACE_DOMTREE, " skip, as d==candidate or d==n");
}
}
if candidate_is_idom {
assert!(!immediate_doms.contains_key(n));
trace_if!(TRACE_DOMTREE, " add idom({:?}) = {:?}", n, candidate);
immediate_doms.insert(n.clone(), candidate.clone());
break;
}
} else {
trace_if!(TRACE_DOMTREE, " skip, candidate is n");
}
}
}
assert_eq!(immediate_doms.len(), dominators.len() - 1); // entry block does not have idom
immediate_doms
}
/// whether a dominates b (i.e. b is one of the dominators of a
fn is_dom(a: &MuName, b: &MuName, dominators: &LinkedMultiMap<MuName, MuName>) -> bool {
dominators.contains_key_val(b, a)
}
......@@ -14,6 +14,8 @@
/// A instruction selection pass. Uses simple tree pattern matching.
pub mod inst_sel;
/// A Dominator Tree pass for machine code.
pub mod mc_domtree;
/// A register allocation pass. Graph coloring.
pub mod reg_alloc;
/// A peephole optimization pass after register allocation.
......
......@@ -14,11 +14,13 @@
use ast::ir::*;
use ast::ptr::*;
use compiler;
use compiler::frame::*;
use runtime::ValueLocation;
use rodal;
use utils::Address;
use utils::LinkedHashMap;
use std::sync::Arc;
use runtime::resolve_symbol;
use std;
......@@ -215,6 +217,15 @@ pub trait MachineCode {
fn get_all_blocks(&self) -> Vec<MuName>;
/// gets the entry block
fn get_entry_block(&self) -> MuName;
/// gets the prologue block
fn get_prologue_block(&self) -> MuName {
for name in self.get_all_blocks() {
if name.contains(compiler::PROLOGUE_BLOCK_NAME) {
return name;
}
}
unreachable!()
}
/// gets the range of a given block, returns [start_inst, end_inst) (end_inst not included)
fn get_block_range(&self, block: &str) -> Option<ops::Range<usize>>;
/// gets the block for a given index, returns an Option for the block
......@@ -240,4 +251,123 @@ pub trait MachineCode {
fn patch_frame_size(&mut self, size: usize);
fn as_any(&self) -> &Any;
fn build_cfg(&self) -> MachineCFG {
let mut ret = MachineCFG::empty();
let all_blocks = self.get_all_blocks();
let (start_inst_map, end_inst_map) = {
let mut start_inst_map: LinkedHashMap<usize, MuName> = LinkedHashMap::new();
let mut end_inst_map: LinkedHashMap<usize, MuName> = LinkedHashMap::new();
for block in all_blocks.iter() {
let range = match self.get_block_range(block) {
Some(range) => range,
None => panic!("cannot find range for block {}", block)
};
// start inst
let first_inst = range.start;
// last inst (we need to skip symbols)
let last_inst = match self.get_last_inst(range.end) {
Some(last) => last,
None => {
panic!(
"cannot find last instruction in block {}, \
this block contains no instruction?",
block
)
}
};
trace!(
"Block {}: start_inst={}, end_inst(inclusive)={}",
block,
first_inst,
last_inst
);
start_inst_map.insert(first_inst, block.clone());
end_inst_map.insert(last_inst, block.clone());
}
(start_inst_map, end_inst_map)
};
// collect info for each basic block
for block in self.get_all_blocks().iter() {
let range = self.get_block_range(block).unwrap();
let start_inst = range.start;
let end = range.end;
let preds: Vec<MuName> = {
let mut ret = vec![];
// predecessors of the first instruction is the predecessors of this block
for pred in self.get_preds(start_inst).into_iter() {
match end_inst_map.get(pred) {
Some(block) => ret.push(block.clone()),
None => {}
}
}
ret
};
let succs: Vec<MuName> = {
let mut ret = vec![];
// successors of the last instruction is the successors of this block
for succ in self.get_succs(self.get_last_inst(end).unwrap()).into_iter() {
match start_inst_map.get(succ) {
Some(block) => ret.push(block.clone()),
None => {}
}
}
ret
};
let node = MachineCFGNode {
block: block.clone(),
preds: preds,
succs: succs
};
trace!("CFGNode {:?}", node);
ret.inner.insert(block.clone(), node);
}
ret
}
}
pub struct MachineCFG {
inner: LinkedHashMap<MuName, MachineCFGNode>
}
impl MachineCFG {
fn empty() -> Self {
MachineCFG {
inner: LinkedHashMap::new()
}
}
pub fn get_blocks(&self) -> Vec<MuName> {
self.inner.keys().map(|x| x.clone()).collect()
}
pub fn get_preds(&self, block: &MuName) -> &Vec<MuName> {
&self.inner.get(block).unwrap().preds
}
pub fn get_succs(&self, block: &MuName) -> &Vec<MuName> {
&self.inner.get(block).unwrap().succs
}
}
/// MachineCFGNode represents a block in machine code control flow graph
#[derive(Clone, Debug)]
pub struct MachineCFGNode {
block: MuName,
preds: Vec<MuName>,
succs: Vec<MuName>
}
......@@ -111,6 +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::reg_alloc::RegisterAllocation::new()));
// machine code level passes
......
......@@ -60,11 +60,14 @@ pub const WORD_SIZE: ByteSize = 1 << LOG_POINTER_SIZE;
mod linked_hashmap;
/// linked hashset implementation based on LinkedHashMap
mod linked_hashset;
/// linked multi-key hashmap implementation
mod linked_multimap;
// re-export these data structures
pub use linked_hashmap::LinkedHashMap;
pub use linked_hashset::LinkedHashSet;
pub use linked_multimap::LinkedMultiMap;
pub use self::doubly::DoublyLinkedList;
/// mem module:
......
......@@ -91,6 +91,22 @@ impl<K: Hash + Eq, S: BuildHasher> LinkedHashSet<K, S> {
self.0.contains_key(k)
}
/// retains elements that matches the predicate
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K) -> bool
{
let mut retain = vec![];
while let Some(x) = self.0.pop_front() {
if f(&x.0) {
retain.push(x);
}
}
for x in retain {
self.0.insert(x.0, x.1);
}
}
/// removes an element from the set, do nothing if the set does not contain the element
pub fn remove<Q: ?Sized>(&mut self, k: &Q)
where
......
// 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 std::collections::hash_map;
use std::hash::Hash;
use std::fmt;
use std::fmt::Debug;
use linked_hashmap::LinkedHashMap;
use linked_hashmap::{Iter, Keys};
use linked_hashset::LinkedHashSet;
pub struct LinkedMultiMap<K, V, S = hash_map::RandomState> {
inner: LinkedHashMap<K, LinkedHashSet<V, S>>
}
impl<K: Hash + Eq, V: Hash + Eq> LinkedMultiMap<K, V> {
pub fn new() -> LinkedMultiMap<K, V> {
LinkedMultiMap {
inner: LinkedHashMap::new()
}
}
pub fn insert(&mut self, k: K, v: V) {
if self.inner.contains_key(&k) {
self.inner.get_mut(&k).unwrap().insert(v);
} else {
let mut set = LinkedHashSet::<V>::new();
set.insert(v);
self.inner.insert(k, set);
}
}
pub fn insert_set(&mut self, k: K, set: LinkedHashSet<V>) {
if self.inner.contains_key(&k) {
self.inner.get_mut(&k).unwrap().add_all(set);
} else {
self.inner.insert(k, set);
}
}
pub fn replace_set(&mut self, k: K, set: LinkedHashSet<V>) {
self.inner.insert(k, set);
}
pub fn get(&self, k: &K) -> Option<&LinkedHashSet<V>> {
self.inner.get(k)
}
pub fn contains_key(&self, k: &K) -> bool {
self.inner.contains_key(k)
}
pub fn contains_key_val(&self, k: &K, v: &V) -> bool {
self.inner.contains_key(k) && self.inner.get(&k).unwrap().contains(v)
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn iter(&self) -> Iter<K, LinkedHashSet<V>> {
self.inner.iter()
}
pub fn keys(&self) -> Keys<K, LinkedHashSet<V>> {
self.inner.keys()
}
}
impl<K: Hash + Eq + Debug, V: Hash + Eq + Debug> Debug for LinkedMultiMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (k, v) in self.iter() {
write!(f, "{:?} -> {:?}\n", k, v).unwrap();
}
Ok(())
}
}
\ 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