/*
 *	Note, to_branch is included in the collapse!!
 */
void El_collapse_compare_chain(Hyperblock *hb, Dlist< Pair<Op*, Op*> > &cpr_block,
				Op *target_branch, Op *to_branch)
{
    Pair<Op*,Op*> cur_pair;
    Op *target_cmpp, *to_cmpp, *cur_branch, *cur_cmpp;
    Operand incoming_pred, br_pred, ft_pred;
    bool flag, last_br;

    target_cmpp = to_cmpp = NULL;
    for (Dlist_iterator<Pair<Op*, Op*> > dl_i(cpr_block); dl_i!=0; dl_i++) {
	cur_pair = *dl_i;
	cur_branch = cur_pair.first;
	cur_cmpp = cur_pair.second;
	if (cur_branch == target_branch)
	    target_cmpp = cur_cmpp;
	if (cur_branch == to_branch)
	    to_cmpp = cur_cmpp;
    }
    
    /* Figure out the value of incoming predicate */
    if (to_cmpp != NULL)
	incoming_pred = to_cmpp->src(PRED1);
    else {
	Pred_lit* new_pred_lit = new Pred_lit(true);
        Operand pred_true(new_pred_lit);
	incoming_pred = pred_true;
    }

    /* Create the collapsed pred and initialize it */
    El_create_collapsed_predicates(br_pred, ft_pred);
    El_insert_initializer_for_collapsed_predicate(hb, br_pred, ft_pred,
							incoming_pred, to_cmpp);

    /* Walk the chain in reverse order, insert collapsed cmpp ops */
    flag = false;
    for (Dlist_iterator<Pair<Op*, Op*> > dl_i2(cpr_block, true); dl_i2!=0; dl_i2--) {
	cur_pair = *dl_i2;
	cur_branch = cur_pair.first;
        cur_cmpp = cur_pair.second;
	last_br = false;
	if (cur_branch == target_branch) {
	    flag = true;
	    last_br = true;
	}
	if (flag == false)
	    continue;
	El_insert_collapsed_cmpp_op(hb, cur_cmpp, br_pred, ft_pred, incoming_pred,
					last_br);
	if (cur_branch == to_branch)
	    break;
    }

    El_reassociate_branch_pred(target_branch, br_pred);
    if (target_cmpp != NULL) {
        El_reassociate_input_operand(hb, target_cmpp->dest(DEST1), br_pred);
        El_reassociate_input_operand(hb, target_cmpp->dest(DEST2), ft_pred);
    }
    hb_br_preds.push_tail(br_pred);
    hb_ft_preds.push_tail(ft_pred);
}
void El_max_reduce_cpr_blocks(Hyperblock *hb, Cont_cpr_match_result &match_result)
{
    Dlist<Dlist< Pair<Op*, Op*> > > hb_cprblocks;
    Dlist< Pair<Op*, Op*> > cur_cprblock;
    Pair<Op*, Op*> cur_tuple;
    Op *first_branch, *cur_branch, *cur_cmpp;

    hb_cprblocks = match_result.cpr_blk_list;

    if (hb_cprblocks.size() == 0) {
        if (dbg(cpr, 2))
            cdbg << "HB " << hb->id() << " has no cpr blocks" << endl;
        return;
    }

    hb_br_preds.clear();
    hb_ft_preds.clear();

    for (Dlist_iterator<Dlist< Pair<Op*, Op*> > > d_iter(hb_cprblocks);
			d_iter!=0; d_iter++) {
	cur_cprblock = *d_iter;
	El_normalize_cprblock(cur_cprblock);

	first_branch = NULL;
	for (Dlist_iterator<Pair<Op*, Op*> > d2_iter(cur_cprblock);
			d2_iter!=0; d2_iter++) {
	    cur_tuple = *d2_iter;
	    cur_branch = cur_tuple.first;
	    cur_cmpp = cur_tuple.second;
	    if (first_branch == NULL) {
		first_branch = cur_branch;
		hb_br_preds.push_tail(cur_cmpp->dest(DEST1));
		hb_ft_preds.push_tail(cur_cmpp->dest(DEST2));
		continue;
	    }
	    El_collapse_compare_chain(hb, cur_cprblock, cur_branch, first_branch);
	}
    }

    El_record_maxreduce_info_in_attr(hb);
}