package synthesijer.scheduler.opt;
import java.util.ArrayList;
import java.util.Hashtable;
import synthesijer.scheduler.Op;
import synthesijer.scheduler.Operand;
import synthesijer.scheduler.SchedulerBoard;
import synthesijer.scheduler.SchedulerInfo;
import synthesijer.scheduler.SchedulerItem;
import synthesijer.scheduler.SchedulerSlot;
import synthesijer.scheduler.VariableOperand;
public class SimpleChaining implements SchedulerInfoOptimizer{
@Override
public SchedulerInfo opt(SchedulerInfo info){
SchedulerInfo result = info.getSameInfo();
for(SchedulerBoard b: info.getBoardsList()){
result.addBoard(conv(b));
}
return result;
}
@Override
public String getKey(){
return "simple_chaining";
}
private SchedulerSlot copySlots(SchedulerSlot slot){
SchedulerSlot newSlot = new SchedulerSlot(slot.getStepId());
for(SchedulerItem item: slot.getItems()){
newSlot.addItem(item);
item.setSlot(newSlot);
}
return newSlot;
}
private SchedulerSlot chaining(ArrayList<SchedulerSlot> bb){
Hashtable<Operand, SchedulerItem> predItem = new Hashtable<>();
SchedulerSlot newSlot = null;
int last = 0;
for(SchedulerSlot s: bb){
last = s.getNextStep()[0];
for(SchedulerItem item : s.getItems()){
int num = item.getSrcOperand().length;
for(int i = 0; i < num; i++){
Operand o = item.getSrcOperand()[i];
if((o instanceof VariableOperand) && predItem.containsKey(o)){
((VariableOperand)o).setChaining(item, predItem.get(o));
}
}
predItem.put(item.getDestOperand(), item);
}
if(newSlot == null){
newSlot = copySlots(s);
}else{
for(SchedulerItem item: s.getItems()){
newSlot.addItem(item);
item.setSlot(newSlot);
}
}
}
for(SchedulerItem item: newSlot.getItems()){
item.setBranchId(last);
}
return newSlot;
}
private boolean isExcept(SchedulerItem item){
Op op = item.getOp();
switch(op){
case METHOD_ENTRY:
case METHOD_EXIT:
case MUL32:
case MUL64:
case DIV32:
case DIV64:
case MOD32:
case MOD64:
case LSHIFT32:
case LOGIC_RSHIFT32:
case ARITH_RSHIFT32:
case LSHIFT64:
case LOGIC_RSHIFT64:
case ARITH_RSHIFT64:
case JP:
case JT:
case RETURN:
case SELECT:
case ARRAY_ACCESS:
case ARRAY_ACCESS0:
case ARRAY_ACCESS_WAIT:
case ARRAY_INDEX:
case CALL:
case EXT_CALL:
case FIELD_ACCESS:
case BREAK:
case CONTINUE:
case FADD32:
case FSUB32:
case FMUL32:
case FDIV32:
case FADD64:
case FSUB64:
case FMUL64:
case FDIV64:
case CONV_F2I:
case CONV_I2F:
case CONV_D2L:
case CONV_L2D:
case CONV_F2D:
case CONV_D2F:
case FLT32:
case FLEQ32:
case FGT32:
case FGEQ32:
case FCOMPEQ32:
case FNEQ32:
case FLT64:
case FLEQ64:
case FGT64:
case FGEQ64:
case FCOMPEQ64:
case FNEQ64:
case UNDEFINED:
return true;
default:
return false;
}
}
private boolean hasVolatile(SchedulerSlot slot){
for(SchedulerItem item: slot.getItems()){
VariableOperand o = item.getDestOperand();
if(o.isVolatileFlag() || o.isPublic()) return true;
}
return false;
}
private boolean isChained(int degree, ArrayList<SchedulerSlot> bb, SchedulerSlot slot){
if(slot.hasBranchOp()) return false;
if(slot.getNextStep().length > 1) return false;
if(degree > 1) return false;
if(slot.getLatency() > 0) return false; // just simple
if(isExcept(slot.getItems()[0])) return false; // just simple
if(hasVolatile(slot)) return false; // jsut simple
if(bb == null) return true; // the first one except the above is a top of chained slots
int last = bb.get(bb.size()-1).getNextStep()[0];
return last == slot.getStepId(); // true when chained
}
public SchedulerBoard conv(SchedulerBoard src){
Hashtable<SchedulerSlot, Integer> degrees = src.getEntryDegrees();
SchedulerBoard ret = src.genSameEnvBoard();
SchedulerSlot[] slots = src.getSlots();
ArrayList<SchedulerSlot> bb = null;
for(int i = 0; i < slots.length; i++){
SchedulerSlot slot = slots[i];
int d = degrees.get(slot);
if(isChained(d, bb, slot) == false){
if(bb != null && bb.size() > 0){
ret.addSlot(chaining(bb));
}
ret.addSlot(slot);
bb = null; // reset
}else{
if(bb == null){
bb = new ArrayList<>();
}
bb.add(slot);
}
}
if(bb != null && bb.size() > 0){
ret.addSlot(chaining(bb));
}
return ret;
}
}