/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2010, Benedikt Huber (benedikt@vmars.tuwien.ac.at) 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.common.code; import com.jopdesign.common.code.SymbolicMarker.SymbolicMarkerType; import com.jopdesign.wcet.annotations.LoopBoundExpr; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * <p> Purpose: Instances represent execution frequency bounds for loops. * Simple loop bounds are relative to the execution frequency * of the entry edges of the loop; for more elaborated kinds of * relative bounds see below. Note that you need at least one bound * where the marker dominates the loop entry, otherwise the WCET problem * will be unbounded.</p> * We currently support the following loop bounds:<br/> * {@code loop = loop-bound-expr marker? } * <p>{@code loop-bound-expr} is a symbolic expression which is * evaluated in the domain of integer intervals. The form * {@code loop <= loop-bound-expr marker? } is a short hand for * {@code loop = [0,loop-bound-expr] marker? }.</p> * <p>Markers specify to which execution frequency loop bounds * are relative to. The mark {@code outer(n)} expresses * that the loop bound is relative to execution frequency of * the entry edges of the n-th outer loop. If the marker is * ommited, this is a short hand for {@code outer(0)}, the * execution frequency sum of the entry edges of the current loop.</p> * <p>To specify that the execution frequency of the loop body is bounded * relative to some method, use the marker {@code method methodID}.</p> * <p>TODO: maybe we also want to specify sums of (expr,marker) pairs</p> * <p>TODO: we also want to allow absolute execution bounds for the loop * as a whole. One idea would be to restrict the loop bound to 1, and then * add the absolute cost to continue edge. * </p> * * @author Benedikt Huber (benedikt@vmars.tuwien.ac.at) */ public class LoopBound { private static final long serialVersionUID = 1L; /* Invariant: There is always an entry for the marker LOOP_ENTRY */ private Map<SymbolicMarker, LoopBoundExpr> markerBounds; private final boolean isDefaultBound; private LoopBound(Map<SymbolicMarker, LoopBoundExpr> other) { markerBounds = new HashMap<SymbolicMarker, LoopBoundExpr>(other); isDefaultBound = false; } public static LoopBound boundedAbove(long ub) { return new LoopBound(LoopBoundExpr.numUpperBound(ub)); } public static LoopBound defaultBound(long ub) { return new LoopBound(LoopBoundExpr.numUpperBound(ub), true); } public static LoopBound simpleBound(LoopBoundExpr bound) { if (bound == null) throw new AssertionError("loop bound expr: null"); return new LoopBound(bound); } /** * Create a loop bound relative to the marker. If the marker is an outer loop, * or the enclosing method, the loop bound is also a valid basic bound */ public static LoopBound markerBound(LoopBoundExpr bound, SymbolicMarker marker) { LoopBoundExpr basicBound; if (marker.inSameMethod()) { basicBound = bound; } else { basicBound = LoopBoundExpr.ANY; } return markerBound(basicBound, bound, marker); } public static LoopBound markerBound( LoopBoundExpr basicBound, LoopBoundExpr markerBound, SymbolicMarker marker) { if (basicBound == null) throw new AssertionError("loop bound expr: null"); if (markerBound == null) throw new AssertionError("loop bound expr: null"); LoopBound bound = new LoopBound(basicBound); bound.addBound(markerBound, marker); return bound; } // public static LoopBound markerBound(LoopBoundExpr bound, SymbolicMarker marker) { // LoopBound loopBound = new LoopBound(bound); // loopBound.setBoundMarker(bound, marker); // return loopBound; // } public LoopBound clone() { return new LoopBound(markerBounds); } private LoopBound(LoopBoundExpr loopBoundRelativeToEntry) { markerBounds = new HashMap<SymbolicMarker, LoopBoundExpr>(); markerBounds.put(SymbolicMarker.LOOP_ENTRY, loopBoundRelativeToEntry); isDefaultBound = false; } private LoopBound(LoopBoundExpr loopBoundRelativeToEntry, boolean isDefaultBound) { markerBounds = new HashMap<SymbolicMarker, LoopBoundExpr>(); markerBounds.put(SymbolicMarker.LOOP_ENTRY, loopBoundRelativeToEntry); this.isDefaultBound = isDefaultBound; } public void addBound(LoopBound other) { for (Entry<SymbolicMarker, LoopBoundExpr> entry : other.markerBounds.entrySet()) { SymbolicMarker marker = entry.getKey(); markerBounds.put(marker, entry.getValue().intersect(markerBounds.get(marker))); } } public LoopBoundExpr getSimpleLoopBound() { return markerBounds.get(SymbolicMarker.LOOP_ENTRY); } public Long getLowerBound(ExecutionContext ctx) { return getSimpleLoopBound().lowerBound(ctx); } public Long getUpperBound(ExecutionContext ctx) { return getSimpleLoopBound().upperBound(ctx); } /** * @return true if this bound was created as default (fallback) bound using {@link #defaultBound(long)}. */ public boolean isDefaultBound() { return isDefaultBound; } public void addBound(LoopBoundExpr boundExpr, SymbolicMarker marker) { markerBounds.put(marker, boundExpr.intersect(markerBounds.get(marker))); } public String toString() { StringBuffer sb = new StringBuffer(); boolean first = true; for (Entry<SymbolicMarker, LoopBoundExpr> lbEntry : markerBounds.entrySet()) { if (first) { sb.append("; "); first = false; } boundToString(sb, lbEntry.getValue(), lbEntry.getKey()); } return sb.toString(); } private static void boundToString(StringBuffer sb, LoopBoundExpr bound, SymbolicMarker marker) { sb.append(bound.toString()); if (marker != null) { if (marker.getMarkerType() == SymbolicMarkerType.OUTER_LOOP_MARKER) { if (marker.getOuterLoopDistance() != 0) { sb.append("outer("); sb.append(marker.getOuterLoopDistance()); sb.append(")"); } } else if (marker.getMarkerType() == SymbolicMarkerType.METHOD_MARKER) { sb.append("method("); sb.append(marker.getMethodName()); sb.append(")"); } } } public Set<Entry<SymbolicMarker, LoopBoundExpr>> getLoopBounds() { return this.markerBounds.entrySet(); } }