mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-06-10 10:29:36 +00:00
137053f093
- Activate with option -rrig or -reportrig.
208 lines
6.3 KiB
Java
208 lines
6.3 KiB
Java
package dk.camelot64.kickc.model;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* The range, where a variable or set of variables are alive. The live ranges require all statements of the program graph to be indexed as it is stored using statement indices.
|
|
* <p>
|
|
* The definition of a variable being alive during a statement is that it is used after the statement by some later instruction in the flow.
|
|
* Note especially that a variable is not alive in the very last instruction that uses it. (Ie. in the statement x := y the variable y is not alive if it is not used again later. However in the preceding statement it is alive.)
|
|
*/
|
|
public class LiveRange {
|
|
|
|
/**
|
|
* Sorted non-overlapping intervals.
|
|
*/
|
|
private List<LiveInterval> intervals;
|
|
|
|
public LiveRange() {
|
|
this.intervals = new ArrayList<>();
|
|
}
|
|
|
|
/**
|
|
* Get the number of statements in the live range.
|
|
*
|
|
* @return The number of statements in the live range.
|
|
*/
|
|
public int size() {
|
|
int s = 0;
|
|
for(LiveInterval interval : intervals) {
|
|
s += interval.size();
|
|
}
|
|
return s;
|
|
}
|
|
|
|
public String toString(int maxIndex) {
|
|
StringBuilder range = new StringBuilder();
|
|
range.append(" ").append(String.format("%4d", size())).append(" : ");
|
|
StringBuilder canvas = new StringBuilder(" ".repeat(maxIndex+1));
|
|
for(LiveInterval interval : intervals) {
|
|
interval.paintOn(canvas);
|
|
}
|
|
range.append(canvas);
|
|
return range.toString();
|
|
}
|
|
|
|
/**
|
|
* Get the underlying statement intervals
|
|
* @return The intervals
|
|
*/
|
|
public List<LiveInterval> getIntervals() {
|
|
return intervals;
|
|
}
|
|
|
|
/**
|
|
* Add an index to the live range
|
|
*
|
|
* @param index The index to add
|
|
* @return true if the live range was modified. false otherwise
|
|
*/
|
|
public boolean add(int index) {
|
|
for(int i = 0; i < intervals.size(); i++) {
|
|
LiveInterval interval = intervals.get(i);
|
|
if(index < interval.firstStatementIdx - 1) {
|
|
// Add new interval before the current interval
|
|
intervals.add(i, new LiveInterval(index, index));
|
|
return true;
|
|
} else if(index == interval.firstStatementIdx - 1) {
|
|
// Extend the current interval downward
|
|
interval.firstStatementIdx = index;
|
|
return true;
|
|
} else if(index <= interval.lastStatementIdx) {
|
|
// Already inside the interval
|
|
return false;
|
|
} else if(index == interval.lastStatementIdx + 1) {
|
|
// Extend current interval upward - and check if next interval should be merged
|
|
interval.lastStatementIdx = index;
|
|
if(i < intervals.size() - 1) {
|
|
LiveInterval nextInterval = intervals.get(i + 1);
|
|
if(nextInterval.firstStatementIdx == index + 1) {
|
|
// Merge intervals
|
|
interval.lastStatementIdx = nextInterval.lastStatementIdx;
|
|
intervals.remove(i + 1);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
// Not added yet - add a new interval at the end
|
|
intervals.add(new LiveInterval(index, index));
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Determines if this live range overlaps another live range
|
|
*
|
|
* @param other The other live range
|
|
* @return true if there is an overlap
|
|
*/
|
|
public boolean overlaps(LiveRange other) {
|
|
if(this.getMaxIndex() == -1 || other.getMaxIndex() == -1) {
|
|
return false;
|
|
}
|
|
int maxIdx = getMaxIndex();
|
|
for(int i = 0; i <= maxIdx; i++) {
|
|
if(contains(i) && other.contains(i)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Adds another live range to this one - extending this live range to include the other one.
|
|
*
|
|
* @param other The live range to add
|
|
*/
|
|
public void add(LiveRange other) {
|
|
int otherMaxIndex = other.getMaxIndex();
|
|
for(int i = 0; i <= otherMaxIndex; i++) {
|
|
if(other.contains(i)) {
|
|
add(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines if the live range contains an index
|
|
*
|
|
* @param index
|
|
* @return true if the live range contains the index
|
|
*/
|
|
public boolean contains(int index) {
|
|
for(LiveInterval interval : intervals) {
|
|
if(interval.lastStatementIdx >= index) {
|
|
if(interval.firstStatementIdx <= index) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the maximal index contained in the live range
|
|
*
|
|
* @return The max index. -1 if the range is empty.
|
|
*/
|
|
int getMaxIndex() {
|
|
if(intervals.isEmpty()) {
|
|
return -1;
|
|
}
|
|
return intervals.get(intervals.size() - 1).lastStatementIdx;
|
|
}
|
|
|
|
public static class LiveInterval {
|
|
|
|
/**
|
|
* The statement index of the first statement where the variable is assigned.
|
|
*/
|
|
private int firstStatementIdx;
|
|
|
|
/**
|
|
* The statement index of the last statement where the variable alive when the statement ends.
|
|
* <ul><li>
|
|
* If the statement is in the middle of a block:
|
|
* The variable is always used in the following statement for assignment or calculation - but never after.
|
|
* </li><li>
|
|
* If the statement is the last in a block:
|
|
* The variable is available for use in the first statement of following blocks. There the interval may "continue" as another interval - or it may end if the variable is used in the phi-block, and then no more.
|
|
* </li></ul>
|
|
*/
|
|
private int lastStatementIdx;
|
|
|
|
public LiveInterval(int firstStatementIdx, int lastStatementIdx) {
|
|
this.firstStatementIdx = firstStatementIdx;
|
|
this.lastStatementIdx = lastStatementIdx;
|
|
}
|
|
|
|
public int getFirstStatementIdx() {
|
|
return firstStatementIdx;
|
|
}
|
|
|
|
public int getLastStatementIdx() {
|
|
return lastStatementIdx;
|
|
}
|
|
|
|
/**
|
|
* Get the number of statements in the live interval.
|
|
*
|
|
* @return The number of statements in the live interval.
|
|
*/
|
|
public int size() {
|
|
return lastStatementIdx - firstStatementIdx + 1;
|
|
}
|
|
|
|
public void paintOn(StringBuilder canvas) {
|
|
for(int i=firstStatementIdx; i<=lastStatementIdx;i++) {
|
|
canvas.setCharAt(i, '*');
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|