/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2008, Benedikt Huber (benedikt.huber@gmail.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.wcet.uppaal.translator;
import com.jopdesign.common.code.CallString;
import com.jopdesign.common.code.ControlFlowGraph;
import com.jopdesign.common.code.ControlFlowGraph.BasicBlockNode;
import com.jopdesign.common.code.ControlFlowGraph.CFGNode;
import com.jopdesign.common.code.ControlFlowGraph.CfgVisitor;
import com.jopdesign.common.code.ControlFlowGraph.ReturnNode;
import com.jopdesign.common.code.ExecutionContext;
import com.jopdesign.common.graphutils.LoopColoring;
import com.jopdesign.common.graphutils.ProgressMeasure.RelativeProgress;
import com.jopdesign.wcet.WCETProcessorModel;
import com.jopdesign.wcet.analysis.AnalysisContextLocal;
import com.jopdesign.wcet.analysis.LocalAnalysis;
import com.jopdesign.wcet.analysis.RecursiveWcetAnalysis;
import com.jopdesign.wcet.analysis.WcetCost;
import com.jopdesign.wcet.analysis.cache.MethodCacheAnalysis;
import com.jopdesign.wcet.ipet.IPETConfig.CacheCostCalculationMethod;
import com.jopdesign.wcet.uppaal.model.Location;
import com.jopdesign.wcet.uppaal.model.Transition;
import com.jopdesign.wcet.uppaal.model.TransitionAttributes;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Build UppAal templates for a Java method.
* We map the CFG's nodes and edges to
* {@link Location}s and {@link Transition}s.
* Nodes are mapped to subgraphs (with unique start and end node),
* i.e. instances of <code>FlowGraph<Location,Transition></code>
*
* @author Benedikt Huber <benedikt.huber@gmail.com>
*
*/
public class MethodBuilder implements CfgVisitor {
/* input */
private final JavaTranslator jTrans;
private final InvokeBuilder invokeBuilder;
private final SubAutomaton methodAuto;
private final int mId;
private final ControlFlowGraph cfg;
private final TemplateBuilder tBuilder;
/* state */
private Map<CFGNode,SubAutomaton> nodeTemplates = new HashMap<CFGNode, SubAutomaton>();
public MethodBuilder(JavaTranslator jt, TemplateBuilder tBuilder, InvokeBuilder invokeBuilder,
SubAutomaton methodAuto, int mId, ControlFlowGraph cfg) {
this.jTrans = jt;
this.tBuilder = tBuilder;
this.mId = mId;
this.cfg = cfg;
this.methodAuto = methodAuto;
this.invokeBuilder = invokeBuilder;
}
public void build() {
this.nodeTemplates = new HashMap<CFGNode, SubAutomaton>();
this.tBuilder.addDescription("Template for method "+cfg.getMethodInfo());
/* Translate the CFGs nodes */
for(CFGNode node : cfg.vertexSet()) {
node.accept(this);
}
/* Translate the CFGs edges */
for(ControlFlowGraph.CFGEdge edge : cfg.edgeSet()) {
buildEdge(edge);
}
}
public void visitVirtualNode(ControlFlowGraph.VirtualNode n) {
SubAutomaton localTranslation = null;
switch(n.getKind()) {
case ENTRY: localTranslation = SubAutomaton.singleton(methodAuto.getEntry()); break;
case EXIT: localTranslation = SubAutomaton.singleton(methodAuto.getExit()); break;
case SPLIT: localTranslation = createSpecialCommited("SPLIT_"+n.getId(), n);break;
case JOIN: localTranslation = createSpecialCommited("JOIN_"+n.getId(), n);break;
case RETURN: localTranslation = createSpecialCommited("RETURN_"+n.getId(), n);break;
}
this.nodeTemplates.put(n,localTranslation);
}
public void visitReturnNode(ReturnNode n) {
visitVirtualNode(n);
}
private SubAutomaton createSpecialCommited(String name, ControlFlowGraph.VirtualNode n) {
Location split = tBuilder.createLocation(name+"_"+this.mId+"_"+n.getId());
split.setCommited();
return SubAutomaton.singleton(split);
}
public void visitBasicBlockNode(BasicBlockNode n) {
ExecutionContext ctx = new ExecutionContext(n.getBasicBlock().getMethodInfo());
SubAutomaton bbLoc =
createBasicBlock(n.getId(),jTrans.getProject().getWCETProcessorModel().basicBlockWCET(ctx,n.getBasicBlock()));
this.nodeTemplates.put(n,bbLoc);
}
public void visitInvokeNode(ControlFlowGraph.InvokeNode n) {
ExecutionContext ctx = new ExecutionContext(n.getBasicBlock().getMethodInfo());
MethodCacheAnalysis mca = new MethodCacheAnalysis(jTrans.getProject());
WCETProcessorModel proc = jTrans.getProject().getWCETProcessorModel();
SubAutomaton invokeAuto;
long staticWCET = proc.basicBlockWCET(ctx, n.getBasicBlock());
if(jTrans.getCacheSim().isAlwaysMiss()) {
staticWCET += mca.getInvokeReturnMissCost(n.getInvokeSite(),CallString.EMPTY);
}
invokeAuto = invokeBuilder.translateInvoke(this,n,staticWCET);
this.nodeTemplates.put(n,invokeAuto);
}
public void visitSummaryNode(ControlFlowGraph.SummaryNode n) {
RecursiveWcetAnalysis<AnalysisContextLocal> an =
new RecursiveWcetAnalysis<AnalysisContextLocal>(
jTrans.getProject(),
new LocalAnalysis());
WcetCost cost = an.runWCETComputation("SUBGRAPH"+n.getId(),
n.getSubGraph(),
new AnalysisContextLocal(CacheCostCalculationMethod.ALWAYS_MISS)
).getTotalCost();
SubAutomaton sumLoc = createBasicBlock(n.getId(),cost.getCost());
this.nodeTemplates.put(n,sumLoc);
}
private void buildEdge(ControlFlowGraph.CFGEdge edge) {
Set<CFGNode> hols = cfg.getLoopColoring().getHeadOfLoops();
Set<ControlFlowGraph.CFGEdge> backEdges = cfg.getLoopColoring().getBackEdges();
Map<ControlFlowGraph.CFGEdge, LoopColoring.IterationBranchLabel<CFGNode>> edgeColoring =
cfg.getLoopColoring().getIterationBranchEdges();
CFGNode src = cfg.getEdgeSource(edge);
CFGNode target = cfg.getEdgeTarget(edge);
if(src == cfg.getEntry() && target == cfg.getExit()) return;
Transition transition = tBuilder.createTransition(
nodeTemplates.get(src).getExit(),
nodeTemplates.get(target).getEntry());
TransitionAttributes attrs = transition.getAttrs();
LoopColoring.IterationBranchLabel<CFGNode> edgeColor = edgeColoring.get(edge);
if(jTrans.getConfig().useProgressMeasure) {
if(src instanceof ControlFlowGraph.InvokeNode) {
attrs.appendUpdate("pm := pm + 1");
} else {
RelativeProgress<CFGNode> progress = jTrans.getProgress(cfg.getMethodInfo()).get(edge);
String progressExpr = "pm := pm + " + progress.staticDiff;
for(Entry<CFGNode, Long> loopDiff : progress.loopDiff.entrySet()) {
progressExpr += String.format(" - %d * %s",loopDiff.getValue(),
tBuilder.getLoopVar(loopDiff.getKey()));
}
attrs.appendUpdate(progressExpr);
}
}
if(edgeColor != null) {
for(CFGNode loop : edgeColor.getContinues()) {
attrs.appendGuard(tBuilder.contLoopGuard(loop));
attrs.appendUpdate(tBuilder.incrLoopCounter(loop));
}
for(CFGNode loop : edgeColor.getExits()) {
attrs.appendGuard(tBuilder.exitLoopGuard(loop));
attrs.appendUpdate(tBuilder.resetLoopCounter(loop));
}
}
if(hols.contains(target) && ! backEdges.contains(edge)) {
attrs.appendUpdate(tBuilder.resetLoopCounter(target));
}
}
SubAutomaton createBasicBlock(int nID, long blockWCET) {
Location bbNode = tBuilder.createLocation("N"+this.mId+"_"+nID);
tBuilder.waitAtLocation(bbNode,blockWCET);
return SubAutomaton.singleton(bbNode);
}
public int getId() {
return mId;
}
}