//Mike Maxim
//Main class for the full compilation

package edu.cmu.cs.l3.main;

import edu.cmu.cs.l3.general.*;
import edu.cmu.cs.l3.translate.*;
import edu.cmu.cs.l3.codegen.*;
import edu.cmu.cs.l3.x86.*;
import edu.cmu.cs.l3.temp.*;
import edu.cmu.cs.l3.assem.*;
import edu.cmu.cs.l3.regalloc.*;
import edu.cmu.cs.l3.flowgraph.*;
import java.io.*;
import java.util.*;

public class Compiler {
    public Compiler() {
    }

    public static void go(String filename, String outfile, boolean doregalloc,
                          RegisterAllocatorOptions regoptions) throws Exception {
        int i, j;
        StringBuffer code = new StringBuffer();
        RegisterAllocator.Stats regstats=null;

        Translator tr = new Translator(new FrameIntel());
        List irfrags = tr.translate(filename, true);

        CodeGenerator cg = new X86CodeGenerator(regoptions.m_genspills);
        TempMap regalloc;

        Globals.verbosePrintln("\n--- Initiating Code Generation Stage");
        Globals.verbosePrintln(" --- Generating Code");
        List cgfrags = cg.codegen(irfrags);
        Globals.verbosePrintln(" --- Optimizing");
        Globals.verbosePrintln("  --- Register Allocation");
        for (j = 0; j < cgfrags.size(); j++) {
            Fragment cfrag = (Fragment) cgfrags.get(j);
            List fragcode = cfrag.getAssemCode();

            if (cfrag instanceof FragmentCode) {
                if (doregalloc && !((FragmentCode)cfrag).getName().equals("____Global")) {
                    regalloc = new X86RegisterAllocator(
                        new LivenessIGConstructor(), new AssemFGConstructor(), regoptions);
                    fragcode = ( (RegisterAllocator) regalloc).allocate(cfrag.getFrame(),
                        fragcode, Arrays.asList(cfrag.getFrame().getRegisters()));
                    cfrag.getFrame().finalize(fragcode);
                    regstats = ((RegisterAllocator)regalloc).m_stats;
                }
                else {
                    regalloc = cfrag.getFrame();
                }
                for (i = 0; i < fragcode.size(); i++) {
                    Instruction ins = (Instruction) fragcode.get(i);
                    code.append(ins.format(regalloc));
                }
            }
        }

        if (regstats != null)
            Globals.verbosePrintln("   --- RA: Spills: " + regstats.m_spills
                                   + " Coalesced: " + regstats.m_cnodes
                                   + " DeadMoves: " + regstats.m_delete
                                   + " Loops: " + regstats.m_iterations);

        File ofile = new File(outfile); ofile.createNewFile();
        PrintStream targetfile = new PrintStream(new FileOutputStream(ofile));
        targetfile.print(code);

        Globals.verbosePrintln("--- Done.");

    }
}