package xsched.analysis.wala.schedule_extraction;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Map.Entry;
import xsched.analysis.core.TaskSchedule;
import xsched.analysis.core.TaskScheduleManager;
import xsched.analysis.wala.util.SimpleGraph;
import com.ibm.wala.ssa.ISSABasicBlock;
public class NormalNodeFlowData extends FlowData {
private static boolean DEBUG = false;
//null for fresh sets; in meet operations, we will call mergeWithForward edge etc multiple times which will instantiate those
//in node analysis operations we call duplicate which instantiates those
//in the initial setup code we call initEmpty()
protected Set<LoopContext> loopContexts;
//a phi node in a certain context can point to multiple task variables from different contexts
protected HashMap<PhiVariable, Set<TaskVariable>> phiMappings;
protected SimpleGraph<TaskVariable> partialSchedule;
protected NormalNodeVisitor visitor;
//just to improve debugging
final ISSABasicBlock basicBlock;
NormalNodeFlowData(ISSABasicBlock basicBlock) {
this.basicBlock = basicBlock;
}
public SimpleGraph<TaskVariable> partialSchedule() {
return partialSchedule;
}
public NormalNodeVisitor createNodeVisitor() {
return new NormalNodeVisitor(this);
}
public NormalNodeVisitor nodeVisitor() {
if(visitor == null)
visitor = this.createNodeVisitor();
return visitor;
}
boolean isTask(int ssaVariable) {
Iterator<TaskVariable> nodes = this.partialSchedule.iterator();
while(nodes.hasNext()) {
TaskVariable node = nodes.next();
if(node.ssaVariable == ssaVariable)
return true;
}
return false;
}
Set<LoopContext> loopContexts() {
return loopContexts;
}
void initEmpty() {
assert this.isInitial();
this.loopContexts = new HashSet<LoopContext>();
this.partialSchedule = new SimpleGraph<TaskVariable>();
}
NormalNodeFlowData duplicate(ISSABasicBlock forBasicBlock) {
NormalNodeFlowData data = new NormalNodeFlowData(forBasicBlock);
data.copyState(this);
return data;
}
//never returns null
Set<TaskVariable> taskVariableForSSAVariable(LoopContext ctxt, int ssaVariable) {
if(phiMappings != null) {
Set<TaskVariable> tasks = phiMappings.get(new PhiVariable(ctxt, ssaVariable));
if(tasks != null)
return tasks;
}
//ssaVariable is not a phi node, then it must be a scheduled task
TaskVariable scheduledTask = new TaskVariable(ctxt, ssaVariable);
if(partialSchedule.containsNode(scheduledTask)) {
return Collections.singleton(scheduledTask);
} else {
return Collections.emptySet();
}
}
void addLoopContext(LoopContext lc) {
if(DEBUG)
System.out.println("NormalNodeFlowData: node of block " + basicBlock.getGraphNodeId() + " adding loop context: " + lc);
this.loopContexts.add(lc);
}
void addFormalTaskParameter(int ssaVariable) {
partialSchedule.addNode(new TaskVariable(LoopContext.emptyLoopContext(), ssaVariable));
}
void addTaskScheduleSite(TaskVariable variable) {
if(DEBUG)
System.out.println("NormalNodeFlowData: node of block " + basicBlock.getGraphNodeId() + " adding task variable: " + variable);
partialSchedule.addNode(variable);
}
void addHappensBeforeEdge(TaskVariable src, TaskVariable trgt) {
if(DEBUG)
System.out.println("NormalNodeFlowData: node of block " + basicBlock.getGraphNodeId() + " adding hb edge: " + src + "->" + trgt);
this.partialSchedule.addEdge(src, trgt);
}
boolean isInitial() {
assert (loopContexts != null && partialSchedule != null)
|| (loopContexts == null && phiMappings == null && partialSchedule == null);
return loopContexts == null;
}
void killHappensBeforeRelationshipsContaining(TaskVariable task) {
this.partialSchedule.removeAllIncidentEdges(task);
}
@Override
boolean stateEquals(FlowData otherData) {
assert otherData instanceof NormalNodeFlowData;
NormalNodeFlowData other = (NormalNodeFlowData)otherData;
assert ! other.isInitial();
return ! isInitial() && other.loopContexts.equals(loopContexts)
&& other.partialSchedule.stateEquals(partialSchedule) && other.phiMappings.equals(phiMappings);
}
protected void addAllPhiVariables(PhiVariable phi, Collection<TaskVariable> toAdd) {
if (phiMappings == null)
phiMappings = new HashMap<PhiVariable, Set<TaskVariable>>();
Set<TaskVariable> tasks = phiMappings.get(phi);
if(tasks == null) {
tasks = new HashSet<TaskVariable>();
phiMappings.put(phi, tasks);
}
tasks.addAll(toAdd);
}
@Override
public void copyState(FlowData v) {
assert(v instanceof NormalNodeFlowData);
assert v != null;
NormalNodeFlowData other = (NormalNodeFlowData)v;
assert ! other.isInitial();
//when duplicating, the basic blocks can be different
//assert this.isInitial() || other.basicBlock.equals(basicBlock);
this.loopContexts = new HashSet<LoopContext>(other.loopContexts);
this.partialSchedule = new SimpleGraph<TaskVariable>();
this.partialSchedule.addAllNodesAndEdges(other.partialSchedule);
if (other.phiMappings != null) {
this.phiMappings = new HashMap<PhiVariable, Set<TaskVariable>>();
for(Entry<PhiVariable, Set<TaskVariable>> entry : other.phiMappings.entrySet()) {
this.addAllPhiVariables(entry.getKey(), entry.getValue());
}
}
}
/**
* compress the node flow data into a task schedule where each task ssa variable is related with each other
* @return
*/
public <SM extends TaskScheduleManager<Integer>> TaskSchedule<Integer, SM> makeTaskSchedule(SM manager) {
return new TaskSchedule<Integer, SM>(manager);
}
@Override
public String toString() {
return "Node Flow Data " + basicBlock.getGraphNodeId();
}
public void print(PrintStream out) {
out.println("Loop Contexts: " + loopContexts);
out.println("Scheduled Tasks: " + this.partialSchedule.nodesToString());
out.println("Phi Mappings: " + phiMappings);
out.println("HB Edges: " + this.partialSchedule.edgesToString());
}
}