package edu.cmu.cs.l3.x86;

import edu.cmu.cs.l3.regalloc.*;
import edu.cmu.cs.l3.temp.*;
import edu.cmu.cs.l3.assem.*;
import edu.cmu.cs.l3.frame.*;
import edu.cmu.cs.l3.flowgraph.*;
import java.util.*;

public class X86RegisterAllocator
    extends RegisterAllocator {

    public X86RegisterAllocator(IGConstructor cons, FGConstructor fgcons,
                                RegisterAllocatorOptions options) {
        super(cons, fgcons, options);
    }

    public String tempMap(Temp t) {

        if (t.isSpilled()) {
            return t.getSpillOffset() + "(%ebp)";
        }
        if (t.isGlobal()) {
            if (t.isGlobalPointer())
                return "$"+t.getGlobalName();
            else
                return t.getGlobalName();
        }
        if (t.hasValue()) {
            return "$" + t.getValue();
        }

        String reg = (String) m_tempmap.get(t);
        if (reg == null) {
            return t.toString();
        }
        return reg;
    }

    protected boolean rewrite(Frame frame, List newcode, List code, List spills) {

        int i, j, k;
        boolean changed = false;
        Dictionary spillmap = new Hashtable();

        for (i = 0; i < spills.size(); i++) {
            Temp curspill = ( (InterferenceVertex) spills.get(i)).getTemp();
            spillmap.put(curspill, frame.allocLocal(Frame.STACK, 1));
        }

        for (i = 0; i < code.size(); i++) {
            Instruction instr = (Instruction) code.get(i);
            FrameStack mem;
            List uses = instr.sourceTemps();
            List defs = instr.destTemps();
            Dictionary usesreplaced = new Hashtable();

            for (j = 0; uses != null && j < uses.size(); j++) {
                if (null != (mem = (FrameStack) spillmap.get((Temp)uses.get(j)))) {
                    Temp spilltemp = new Temp();
                    spilltemp.setSpilled(mem.getOffset());
                    if (m_options.m_genspills) {
                        Temp usetemp = frame.allocLocalTemp();
                        usetemp.setAsMemHelper();
                        newcode.add(new MoveInstruction("\tmovl\t`s0, `d0\t\t/* Spill Fetch */\n",
                            usetemp, spilltemp));
                        usesreplaced.put((Temp)uses.get(j), usetemp);
                        uses.set(j, usetemp);
                    }
                    else
                        uses.set(j, spilltemp);

                    changed = true;
                }
            }
            newcode.add(instr);
            for (j = 0; defs != null && j < defs.size(); j++) {
                if (null != (mem = (FrameStack) spillmap.get((Temp)defs.get(j)))) {
                    Temp spilltemp = new Temp();
                    spilltemp.setSpilled(mem.getOffset());
                    if (m_options.m_genspills) {
                        Temp spilledtemp = (Temp) defs.get(j);
                        Temp deftemp;
                        if (null == (deftemp = (Temp) usesreplaced.get(spilledtemp))) {
                            deftemp = frame.allocLocalTemp();
                            deftemp.setAsMemHelper();
                        }
                        newcode.add(new MoveInstruction("\tmovl\t`s0, `d0\t\t/* Spill Store */\n",
                            spilltemp, deftemp));
                        defs.set(j, deftemp);
                    }
                    else
                        defs.set(j, spilltemp);
                    changed = true;
                }
            }
        }

        return changed;
    }
}