package compiler.liveness;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import compiler.asmcode.AsmInstr;
import compiler.asmcode.AsmLABEL;
import compiler.asmcode.AsmMOVE;
import compiler.frames.Label;
import compiler.frames.Temp;
public class LivenessAnalyser
{
private static class Instruction
{
private AsmInstr instruction = null;
private LinkedList<Instruction> prev;
private LinkedList<Instruction> next;
private HashSet<Temp> in = null;
private HashSet<Temp> out = null;
private boolean changed = false;
public Instruction(AsmInstr instruction)
{
this.instruction = instruction;
in = new HashSet<Temp>();
out = new HashSet<Temp>();
prev = new LinkedList<Instruction>();
next = new LinkedList<Instruction>();
}
public void addIn(Temp var)
{
if (!in.contains(var))
{
in.add(var);
this.changed = true;
}
}
public void addOut(Temp var)
{
if (!out.contains(var))
{
out.add(var);
this.changed = true;
}
}
public void addNext(Instruction ins)
{
next.add(ins);
}
public void addPred(Instruction ins)
{
prev.add(ins);
}
public AsmInstr getInstruction()
{
return instruction;
}
public HashSet<Temp> getIn()
{
return in;
}
public HashSet<Temp> getOut()
{
return out;
}
public LinkedList<Instruction> getNexts()
{
return next;
}
public void reset()
{
this.changed = false;
}
public boolean hasChanged()
{
return this.changed;
}
}
public static LinkedList<LivenessEdge> analyze(LinkedList<AsmInstr> asmCode)
{
// Create instruction list table and populate it
LinkedList<Instruction> instructionList = new LinkedList<Instruction>();
// Build code execution graph
HashMap<Label, Instruction> labels = new HashMap<Label, Instruction>();
// Dummy first instruction
Instruction previousInstr = null;
// Find labels
for (AsmInstr instr : asmCode)
{
// Add labels to labels map
if (instr instanceof AsmLABEL)
{
labels.put(((AsmLABEL)instr).labels.get(0), new Instruction(instr));
}
}
for (AsmInstr instr : asmCode)
{
Instruction instruction = null;
// Grab previously created instruction object if the AsmInstr is a label
if (instr instanceof AsmLABEL)
{
instruction = labels.get(instr.labels.get(0));
}
else
{
instruction = new Instruction(instr);
}
// Add to flat instruction list
instructionList.add(instruction);
// Link instructions
if (previousInstr != null)
{
previousInstr.addNext(instruction);
instruction.addPred(previousInstr);
}
// Link labeled instructions
if (!(instr instanceof AsmLABEL) && !instr.labels.isEmpty())
{
for (Label lbl : instr.labels)
{
if (!labels.containsKey(lbl))
continue;
labels.get(lbl).addPred(instruction);
instruction.addNext(labels.get(lbl));
}
}
previousInstr = instruction;
}
// Repeat algorithm until there are changes made
do
{
// Reset changed counters for instructions
resetInstructionChangedStatus(instructionList);
for (Instruction instr : instructionList)
{
// Add all used to IN
for (Temp use : instr.getInstruction().uses)
{
instr.addIn(use);
}
// Add all "out but not defined" to IN
for (Temp out : instr.getOut())
{
if (!instr.getInstruction().defs.contains(out))
{
instr.addIn(out);
}
}
// Add all ins of next commands to out
for (Instruction nextIns : instr.getNexts())
{
for (Temp ins : nextIns.getIn())
{
instr.addOut(ins);
}
}
}
} while(instructionsChanged(instructionList));
// Get interference graph
return getInterferenceGraph(instructionList);
}
private static LinkedList<LivenessEdge> getInterferenceGraph(LinkedList<Instruction> instructions)
{
HashSet<LivenessEdge> edges = new HashSet<LivenessEdge>();
for (Instruction instruction : instructions)
{
// Move instruction is being handled separately
if (instruction.getInstruction() instanceof AsmMOVE)
{
AsmMOVE mov = (AsmMOVE)instruction.getInstruction();
// Liveout
for (Temp liveOut : instruction.getOut())
{
if (!mov.defs.get(0).equals(liveOut))
{
// Add edge that is not the same as assigned variable
edges.add(new LivenessEdge(mov.defs.get(0), liveOut));
}
}
}
else
{
for (Temp defs : instruction.getInstruction().defs)
{
for (Temp liveOut : instruction.getOut())
{
edges.add(new LivenessEdge(defs, liveOut));
}
}
}
}
return new LinkedList<LivenessEdge>(edges);
}
private static boolean instructionsChanged(LinkedList<Instruction> instructions)
{
boolean changed = false;
for (Instruction instruction : instructions)
{
changed = changed || instruction.hasChanged();
}
return changed;
}
private static void resetInstructionChangedStatus(LinkedList<Instruction> instructions)
{
for (Instruction instruction : instructions)
{
instruction.reset();
}
}
}