/* file "dce/dce.cpp" */

/*
    Copyright (c) 2000 The President and Fellows of Harvard College

    All rights reserved.

    This software is provided under the terms described in
    the "machine/copyright.h" include file.
*/

#include <machine/copyright.h>

#pragma implementation "dce/dce.h"

#include <machine/machine.h>
#include <cfg/cfg.h>
#include <cfa/cfa.h>
#include <bvd/bvd.h>

#include <dce/dce.h>

// Constants

NoteKey k_necessary_instr;			// for note marking needed instr

// Per-unit variables

int eliminated_instr_count;			// success statistic

void
Dce::initialize()
{
    debug(1, "Debug level is %d", debuglvl);

    k_necessary_instr = "necessary_instr";
}

void
Dce::do_opt_unit(OptUnit *unit)
{
    cur_unit = unit;

    IdString name = get_name(get_proc_sym(cur_unit));
    debug(2, "Processing procedure \"%s\"", name.chars());

    eliminated_instr_count = 0;				// success statistic

    // This pass requires a unit's body to be a CFG.  Be sure that a
    // preceding pass has left it in that form.

    claim(is_kind_of<Cfg>(get_body(cur_unit)), "Body is not in CFG form");
    unit_cfg = static_cast<Cfg*>(get_body(cur_unit));
    if (debuglvl >= 5)
	fprint(stderr, unit_cfg, false, true);		// no layout, just code

    // Find dominance frontier in reverse graph for control dependence info.
    // Find postdominators to use in control simplification.
    dominance_info = new DominanceInfo(unit_cfg);
    dominance_info->find_postdominators();
    dominance_info->find_reverse_dom_frontier();

    // Compute reaching_defs information for the current procedure's local
    // variables and registers.  Here
    //
    //   opnd_catalog	maps operands of interest to bit-vector slots,
    //   def_teller	identifies "interesting" definitions,
    //   reaching_defs	holds per-basic-block reaching_defs results.
    //
    // The argument to the catalog constructor means: save opnds for
    // printing only when debugging.

    opnd_catalog = new RegSymCatalog(debuglvl > 0);
    DefTeller *def_teller = new RegDefTeller(cur_unit, opnd_catalog);
    reaching_defs = new ReachingDefs(unit_cfg, def_teller);

    if (debuglvl >= 6) {
	fprintf(stderr, "Operand catalog:\n");
	opnd_catalog->print(stderr);
	fprintf(stderr, "\n");
    }

    // A DefUseAnalyzer identifies the defs/uses of interest in a single
    // instruction.  See the section on liveness in the BVD document for
    // the interface of this class.

    du_analyzer = new DefUseAnalyzer(opnd_catalog);

    /*
       ######
       #     #  #       ######    ##     ####   ######
       #     #  #       #        #  #   #       #
       ######   #       #####   #    #   ####   #####
       #        #       #       ######       #  #
       #        #       #       #    #  #    #  #
       #        ######  ######  #    #   ####   ######


	######     #    #    #     #     ####   #    #
	#          #    ##   #     #    #       #    #
	#####      #    # #  #     #     ####   ######
	#          #    #  # #     #         #  #    #
	#          #    #   ##     #    #    #  #    #
	#          #    #    #     #     ####   #    #

			 ###
	#    #  ######   ###
	##  ##  #        ###
	# ## #  #####     #
	#    #  #
	#    #  #        ###
	#    #  ######   ###
    */

    delete opnd_catalog;
    delete du_analyzer;
    delete reaching_defs;

    if (debuglvl >= 5) {
	fprintf(stderr, "\nFinal CFG:\n");
	fprint(stderr, unit_cfg, false, true);		// no layout, just code
    }
}

/* writes_volatile() -- Return true for an instruction with a
 * destination that's a non-local or address-taken symbol.
 */
bool
Dce::writes_volatile(Instr *instr)
{
    if (dsts_size(instr) == 0)
	return false;
    for (OpndHandle h = dsts_start(instr); h != dsts_end(instr); ++h)
	if (is_var(*h)) {
	    VarSym *v = get_var(*h);

	    if (!is_auto(v) || is_addr_taken(v))
		return true;
	}
    return false;
}
