fn control_flow_analysis(&mut self) {
        const TRACE_CFA: bool = true;

        // control flow analysis
        let n_insts = self.number_of_insts();
        let ref mut asm = self.code;

        for i in 0..n_insts {
            trace_if!(TRACE_CFA, "---inst {}---", i);

            // skip symbol
            if asm[i].is_symbol {
                continue;
            }

            // determine predecessor:
            // * if last instruction falls through to current instruction,
            //   the predecessor is last instruction
            // * otherwise, we set predecessor when we deal with the instruction
            //   that branches to current instruction
            if i != 0 {
                let last_inst = ASMCode::find_prev_inst(i, asm);
                match last_inst {
                    Some(last_inst) => {
                        let last_inst_branch = asm[last_inst].branch.clone();
                        match last_inst_branch {
                            // if it is a fallthrough, we set its preds as last inst
                            ASMBranchTarget::None => {
                                if !asm[i].preds.contains(&last_inst) {
                                    asm[i].preds.push(last_inst);
                                    trace_if!(
                                        TRACE_CFA,
                                        "inst {}: set PREDS as previous inst - fallthrough {}",
                                        i,
                                        last_inst
                                    );
                                }
                            }
                            // otherwise do nothing
                            _ => {}
                        }
                    }
                    None => {}
                }
            }

            // determine successor
            // make a clone so that we are not borrowing anything
            let branch = asm[i].branch.clone();
            match branch {
                ASMBranchTarget::Unconditional(ref target) => {
                    // branch-to target
                    let target_n = self.blocks.get(target).unwrap().start_inst;

                    // cur inst's succ is target
                    asm[i].succs.push(target_n);

                    // target's pred is cur
                    asm[target_n].preds.push(i);

                    trace_if!(TRACE_CFA, "inst {}: is a branch to {}", i, target);
                    trace_if!(TRACE_CFA, "inst {}: branch target index is {}", i, target_n);
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set SUCCS as branch target {}",
                        i,
                        target_n
                    );
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set PREDS as branch source {}",
                        target_n,
                        i
                    );
                }
                ASMBranchTarget::Conditional(ref target) => {
                    // branch-to target
                    let target_n = self.blocks.get(target).unwrap().start_inst;

                    // cur insts' succ is target
                    asm[i].succs.push(target_n);

                    trace_if!(TRACE_CFA, "inst {}: is a cond branch to {}", i, target);
                    trace_if!(TRACE_CFA, "inst {}: branch target index is {}", i, target_n);
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set SUCCS as branch target {}",
                        i,
                        target_n
                    );

                    // target's pred is cur
                    asm[target_n].preds.push(i);
                    trace_if!(TRACE_CFA, "inst {}: set PREDS as {}", target_n, i);

                    if let Some(next_inst) = ASMCode::find_next_inst(i, asm) {
                        // cur succ is next inst
                        asm[i].succs.push(next_inst);

                        // next inst's pred is cur
                        asm[next_inst].preds.push(i);

                        trace_if!(
                            TRACE_CFA,
                            "inst {}: SET SUCCS as c-branch fallthrough target {}",
                            i,
                            next_inst
                        );
                    } else {
                        panic!("conditional branch does not have a fallthrough target");
                    }
                }
                ASMBranchTarget::PotentiallyExcepting(ref target) => {
                    // may trigger exception and jump to target - similar as conditional branch
                    let target_n = self.blocks.get(target).unwrap().start_inst;

                    // cur inst's succ is target
                    asm[i].succs.push(target_n);

                    trace_if!(
                        TRACE_CFA,
                        "inst {}: is potentially excepting to {}",
                        i,
                        target
                    );
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: excepting target index is {}",
                        i,
                        target_n
                    );
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set SUCCS as excepting target {}",
                        i,
                        target_n
                    );

                    asm[target_n].preds.push(i);

                    if let Some(next_inst) = ASMCode::find_next_inst(i, asm) {
                        // cur succ is next inst
                        asm[i].succs.push(next_inst);

                        // next inst's pred is cur
                        asm[next_inst].preds.push(i);

                        trace_if!(
                            TRACE_CFA,
                            "inst {}: SET SUCCS as PEI fallthrough target {}",
                            i,
                            next_inst
                        );
                    } else {
                        panic!("PEI does not have a fallthrough target");
                    }
                }
                ASMBranchTarget::Return => {
                    trace_if!(TRACE_CFA, "inst {}: is a return", i);
                    trace_if!(TRACE_CFA, "inst {}: has no successor", i);
                }
                ASMBranchTarget::None => {
                    // not branch nor cond branch, succ is next inst
                    trace_if!(TRACE_CFA, "inst {}: not a branch inst", i);
                    if let Some(next_inst) = ASMCode::find_next_inst(i, asm) {
                        trace_if!(
                            TRACE_CFA,
                            "inst {}: set SUCCS as next inst {}",
                            i,
                            next_inst
                        );
                        asm[i].succs.push(next_inst);
                    }
                }
            }
        }
    }
/// control flow analysis on current code
/// calculating branch targets, preds/succs for each instruction
control flow analysis on current code
calculating branch targets, preds/succs for each instruction
control flow analysis on current code calculating branch targets preds / succs for each instruction
fn control_flow_analysis(&mut self) {
        const TRACE_CFA: bool = true;
        // control flow analysis
        let n_insts = self.number_of_insts();
        let ref mut asm = self.code;
        for i in 0..n_insts {
            trace_if!(TRACE_CFA, "---inst {}---", i);
            // skip symbol
            if asm[i].is_symbol {
                continue;
            }
            // determine predecessor:
            // * if last instruction falls through to current instruction,
            //   the predecessor is last instruction
            // * otherwise, we set predecessor when we deal with the instruction
            //   that branches to current instruction
            if i != 0 {
                let last_inst = ASMCode::find_prev_inst(i, asm);
                match last_inst {
                    Some(last_inst) => {
                        let last_inst_branch = asm[last_inst].branch.clone();
                        match last_inst_branch {
                            // if it is a fallthrough, we set its preds as last inst
                            ASMBranchTarget::None => {
                                if !asm[i].preds.contains(&last_inst) {
                                    asm[i].preds.push(last_inst);
                                    trace_if!(
                                        TRACE_CFA,
                                        "inst {}: set PREDS as previous inst - fallthrough {}",
                                        i,
                                        last_inst
                                    );
                                }
                            }
                            // otherwise do nothing
                            _ => {}
                        }
                    }
                    None => {}
                }
            }
            // determine successor
            // make a clone so that we are not borrowing anything
            let branch = asm[i].branch.clone();
            match branch {
                ASMBranchTarget::Unconditional(ref target) => {
                    // branch-to target
                    let target_n = self.blocks.get(target).unwrap().start_inst;
                    // cur inst's succ is target
                    asm[i].succs.push(target_n);
                    // target's pred is cur
                    asm[target_n].preds.push(i);
                    trace_if!(TRACE_CFA, "inst {}: is a branch to {}", i, target);
                    trace_if!(TRACE_CFA, "inst {}: branch target index is {}", i, target_n);
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set SUCCS as branch target {}",
                        i,
                        target_n
                    );
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set PREDS as branch source {}",
                        target_n,
                        i
                    );
                }
                ASMBranchTarget::Conditional(ref target) => {
                    // branch-to target
                    let target_n = self.blocks.get(target).unwrap().start_inst;
                    // cur insts' succ is target
                    asm[i].succs.push(target_n);
                    trace_if!(TRACE_CFA, "inst {}: is a cond branch to {}", i, target);
                    trace_if!(TRACE_CFA, "inst {}: branch target index is {}", i, target_n);
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set SUCCS as branch target {}",
                        i,
                        target_n
                    );
                    // target's pred is cur
                    asm[target_n].preds.push(i);
                    trace_if!(TRACE_CFA, "inst {}: set PREDS as {}", target_n, i);
                    if let Some(next_inst) = ASMCode::find_next_inst(i, asm) {
                        // cur succ is next inst
                        asm[i].succs.push(next_inst);
                        // next inst's pred is cur
                        asm[next_inst].preds.push(i);
                        trace_if!(
                            TRACE_CFA,
                            "inst {}: SET SUCCS as c-branch fallthrough target {}",
                            i,
                            next_inst
                        );
                    } else {
                        panic!("conditional branch does not have a fallthrough target");
                    }
                }
                ASMBranchTarget::PotentiallyExcepting(ref target) => {
                    // may trigger exception and jump to target - similar as conditional branch
                    let target_n = self.blocks.get(target).unwrap().start_inst;
                    // cur inst's succ is target
                    asm[i].succs.push(target_n);
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: is potentially excepting to {}",
                        i,
                        target
                    );
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: excepting target index is {}",
                        i,
                        target_n
                    );
                    trace_if!(
                        TRACE_CFA,
                        "inst {}: set SUCCS as excepting target {}",
                        i,
                        target_n
                    );
                    asm[target_n].preds.push(i);
                    if let Some(next_inst) = ASMCode::find_next_inst(i, asm) {
                        // cur succ is next inst
                        asm[i].succs.push(next_inst);
                        // next inst's pred is cur
                        asm[next_inst].preds.push(i);
                        trace_if!(
                            TRACE_CFA,
                            "inst {}: SET SUCCS as PEI fallthrough target {}",
                            i,
                            next_inst
                        );
                    } else {
                        panic!("PEI does not have a fallthrough target");
                    }
                }
                ASMBranchTarget::Return => {
                    trace_if!(TRACE_CFA, "inst {}: is a return", i);
                    trace_if!(TRACE_CFA, "inst {}: has no successor", i);
                }
                ASMBranchTarget::None => {
                    // not branch nor cond branch, succ is next inst
                    trace_if!(TRACE_CFA, "inst {}: not a branch inst", i);
                    if let Some(next_inst) = ASMCode::find_next_inst(i, asm) {
                        trace_if!(
                            TRACE_CFA,
                            "inst {}: set SUCCS as next inst {}",
                            i,
                            next_inst
                        );
                        asm[i].succs.push(next_inst);
                    }
                }
            }
        }
    }
fn control_flow_analysis ( & mut self ) { const TRACE_CFA : bool = true ; // control flow analysis let n_insts = self . number_of_insts ( ) ; let ref mut asm = self . code ; for i in 0 .. n_insts { trace_if ! ( TRACE_CFA " " i ) ; // skip symbol if asm [ i ] . is_symbol { continue ; } // determine predecessor: // * if last instruction falls through to current instruction, //   the predecessor is last instruction // * otherwise, we set predecessor when we deal with the instruction //   that branches to current instruction if i != 0 { let last_inst = ASMCode :: find_prev_inst ( i , asm ) ; match last_inst { Some ( last_inst ) => { let last_inst_branch = asm [ last_inst ] . branch . clone ( ) ; match last_inst_branch { // if it is a fallthrough, we set its preds as last inst ASMBranchTarget :: None => { if ! asm [ i ] . preds . contains ( & last_inst ) { asm [ i ] . preds . push ( last_inst ) ; trace_if ! ( TRACE_CFA " " i last_inst ) ; } } // otherwise do nothing _ => { } } } None => { } } } // determine successor // make a clone so that we are not borrowing anything let branch = asm [ i ] . branch . clone ( ) ; match branch { ASMBranchTarget :: Unconditional ( ref target ) => { // branch-to target let target_n = self . blocks . get ( target ) . unwrap ( ) . start_inst ; // cur inst's succ is target asm [ i ] . succs . push ( target_n ) ; // target's pred is cur asm [ target_n ] . preds . push ( i ) ; trace_if ! ( TRACE_CFA " " i target ) ; trace_if ! ( TRACE_CFA " " i target_n ) ; trace_if ! ( TRACE_CFA " " i target_n ) ; trace_if ! ( TRACE_CFA " " target_n i ) ; } ASMBranchTarget :: Conditional ( ref target ) => { // branch-to target let target_n = self . blocks . get ( target ) . unwrap ( ) . start_inst ; // cur insts' succ is target asm [ i ] . succs . push ( target_n ) ; trace_if ! ( TRACE_CFA " " i target ) ; trace_if ! ( TRACE_CFA " " i target_n ) ; trace_if ! ( TRACE_CFA " " i target_n ) ; // target's pred is cur asm [ target_n ] . preds . push ( i ) ; trace_if ! ( TRACE_CFA " " target_n i ) ; if let Some ( next_inst ) = ASMCode :: find_next_inst ( i , asm ) { // cur succ is next inst asm [ i ] . succs . push ( next_inst ) ; // next inst's pred is cur asm [ next_inst ] . preds . push ( i ) ; trace_if ! ( TRACE_CFA " " i next_inst ) ; } else { panic ! ( " " ) ; } } ASMBranchTarget :: PotentiallyExcepting ( ref target ) => { // may trigger exception and jump to target - similar as conditional branch let target_n = self . blocks . get ( target ) . unwrap ( ) . start_inst ; // cur inst's succ is target asm [ i ] . succs . push ( target_n ) ; trace_if ! ( TRACE_CFA " " i target ) ; trace_if ! ( TRACE_CFA " " i target_n ) ; trace_if ! ( TRACE_CFA " " i target_n ) ; asm [ target_n ] . preds . push ( i ) ; if let Some ( next_inst ) = ASMCode :: find_next_inst ( i , asm ) { // cur succ is next inst asm [ i ] . succs . push ( next_inst ) ; // next inst's pred is cur asm [ next_inst ] . preds . push ( i ) ; trace_if ! ( TRACE_CFA " " i next_inst ) ; } else { panic ! ( " " ) ; } } ASMBranchTarget :: Return => { trace_if ! ( TRACE_CFA " " i ) ; trace_if ! ( TRACE_CFA " " i ) ; } ASMBranchTarget :: None => { // not branch nor cond branch, succ is next inst trace_if ! ( TRACE_CFA " " i ) ; if let Some ( next_inst ) = ASMCode :: find_next_inst ( i , asm ) { trace_if ! ( TRACE_CFA " " i next_inst ) ; asm [ i ] . succs . push ( next_inst ) ; } } } } }
control flow analysis on current code
calculating branch targets, preds/succs for each instruction
control flow analysis on current code calculating branch targets preds / succs for each instruction
&mut self
&mut self