GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

tree_gen.rs 5.1 KB
Newer Older
1
use ast::ir::*;
2
use ast::inst::*;
3
use ast::ir_semantics::*;
4

5
use vm::context::VMContext;
6 7
use compiler::CompilerPass;

qinsoon's avatar
qinsoon committed
8
pub struct TreeGen {
9
    name: &'static str
qinsoon's avatar
qinsoon committed
10
} 
11

qinsoon's avatar
qinsoon committed
12 13 14
impl TreeGen {
    pub fn new() -> TreeGen {
        TreeGen{name: "Tree Geenration"}
15 16 17
    }
}

18 19 20 21
fn is_movable(expr: &Instruction_) -> bool {
    !has_side_effect(expr)
}

qinsoon's avatar
qinsoon committed
22
impl CompilerPass for TreeGen {
qinsoon's avatar
qinsoon committed
23 24
    fn name(&self) -> &'static str {
        self.name
25
    }
26 27 28 29
    
    fn execute(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
        debug!("---CompilerPass {} for {}---", self.name(), func.fn_name);
        
30
        for (label, ref mut block) in func.content.as_mut().unwrap().blocks.iter_mut() {
31 32 33 34 35 36 37 38 39 40
            // take its content, we will need to put it back
            let mut content = block.content.take().unwrap();
            let body = content.body;
            
            let mut new_body = vec![];
            
            trace!("check block {}", label);
            trace!("");
            
            for node in body.into_iter() {
41
                trace!("check inst: {}", node);
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
                match &node.v {
                    &TreeNode_::Instruction(ref inst) => {
                        // check if any operands can be replaced by expression
                        {
                            trace!("check if we can replace any operand with inst");
                            
                            let mut ops = inst.ops.borrow_mut();
                            for index in 0..ops.len() {
                                let possible_ssa_id = ops[index].extract_ssa_id();
                                if possible_ssa_id.is_some() {
                                    let entry_value = func.context.get_value_mut(possible_ssa_id.unwrap()).unwrap();
                                    
                                    if entry_value.expr.is_some() {
                                        // replace the node with its expr
                                        let expr = entry_value.expr.take().unwrap();
                                        
58
                                        trace!("{} replaced by {}", ops[index], expr);
59 60 61
                                        ops[index] = TreeNode::new_inst(expr);
                                    }
                                } else {
62
                                    trace!("{} cant be replaced", ops[index]);
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
                                }
                            }
                        }
                        
                        // check if left hand side of an assignment has a single use
                        trace!("check if we should fold the inst");
                        if inst.value.is_some() {
                            let left = inst.value.as_ref().unwrap();
                            
                            // if left is _one_ variable that is used once
                            // we can put the expression as a child node to its use
                            if left.len() == 1 {
                                let lhs = func.context.get_value_mut(left[0].extract_ssa_id().unwrap()).unwrap(); 
                                if lhs.use_count.get() == 1{
                                    if is_movable(&inst.v) {
                                        lhs.expr = Some(inst.clone()); // FIXME: should be able to move the inst here 
                                        
                                        trace!("yes");
                                        trace!("");
                                        continue;
                                    } else {
                                        trace!("no, not movable");
                                    }
                                } else {
                                    trace!("no, use count more than 1");
                                }
                            } else {
                                trace!("no, yields more than 1 SSA var");
                            }
                        } else {
                            trace!("no, no value yielded");
                        }
                    },
                    _ => panic!("expected an instruction node here")
                }
                
99
                trace!("add {} back to block {}", node, label);
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
                trace!("");
                new_body.push(node);
            }
            
            content.body = new_body;
            trace!("block {} has {} insts", label, content.body.len());
            trace!("");
                        
            // put the content back
            block.content = Some(content);
        }
        
        self.finish_function(vm_context, func);
        
        debug!("---finish---");
    }
    
    #[allow(unused_variables)]
    fn finish_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
        debug!("check depth tree for {}", func.fn_name);
        
        for entry in func.content.as_ref().unwrap().blocks.iter() {
            debug!("block {}", entry.0);
            
            for inst in entry.1.content.as_ref().unwrap().body.iter() {
125
                debug!("{}", inst);
126 127 128
            }
        }
    }
129
}