diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java
index 5b5481645..d9a683074 100644
--- a/src/main/java/dk/camelot64/kickc/Compiler.java
+++ b/src/main/java/dk/camelot64/kickc/Compiler.java
@@ -262,9 +262,9 @@ public class Compiler {
//program.getLog().setVerboseUplift(true);
new Pass4RegisterUpliftCombinations(program).performUplift(10_000);
- //program.getLog().setVerboseUplift(true);
- //new Pass4RegisterUpliftStatic(program).performUplift();
- //program.getLog().setVerboseUplift(false);
+ program.getLog().setVerboseUplift(true);
+ new Pass4RegisterUpliftStatic(program).performUplift();
+ program.getLog().setVerboseUplift(false);
// Attempt uplifting registers one at a time to catch remaining potential not realized by combination search
new Pass4RegisterUpliftRemains(program).performUplift(10_000);
diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/zpptrby1=zpptrby1_plus_zpptrby1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/zpptrby1=zpptrby1_plus_zpptrby1.asm
new file mode 100644
index 000000000..b6cc19312
--- /dev/null
+++ b/src/main/java/dk/camelot64/kickc/fragment/asm/zpptrby1=zpptrby1_plus_zpptrby1.asm
@@ -0,0 +1,6 @@
+lda {zpptrby1}
+asl
+sta {zpptrby1}
+lda {zpptrby1}+1
+rol
+sta {zpptrby1}+1
diff --git a/src/main/java/dk/camelot64/kickc/model/LiveRangeVariablesEffective.java b/src/main/java/dk/camelot64/kickc/model/LiveRangeVariablesEffective.java
index c80eda77c..271a892f5 100644
--- a/src/main/java/dk/camelot64/kickc/model/LiveRangeVariablesEffective.java
+++ b/src/main/java/dk/camelot64/kickc/model/LiveRangeVariablesEffective.java
@@ -8,23 +8,76 @@ import java.util.*;
public class LiveRangeVariablesEffective {
/** Effectively alive variables by statement index. */
- Map> effectiveLiveVariables;
+ Map effectiveLiveCombinations;
- public LiveRangeVariablesEffective(Map> effectiveLiveVariables) {
- this.effectiveLiveVariables = effectiveLiveVariables;
+ public LiveRangeVariablesEffective(Map effectiveLiveCombinations) {
+ this.effectiveLiveCombinations = effectiveLiveCombinations;
}
/**
- * Get all variables alive at a statement.
- * If the statement is inside a method this also includes all variables alive at the exit of the calls.
- *
- * This method requires a number of other analysis to be present and updated in the (global) program - especailly the Call Graph.
+ * Get all variables potentially alive at a statement.
+ * If the statement is inside a method this also includes all variables alive at the exit of any call.
*
* @param statement The statement to examine
- * @return All variables alive at the statement
+ * @return All variables potentially alive at the statement
*/
public Collection getAliveEffective(Statement statement) {
- return effectiveLiveVariables.get(statement.getIndex());
+ Set effectiveAliveTotal = new LinkedHashSet<>();
+ AliveCombinations aliveCombinations = effectiveLiveCombinations.get(statement.getIndex());
+ for (AliveCombination aliveCombination : aliveCombinations.getCombinations()) {
+ effectiveAliveTotal.addAll(aliveCombination.getAlive());
+ }
+ return effectiveAliveTotal;
+ }
+
+ /**
+ * Get all combinations of variables alive at a statement.
+ * If the statement is inside a method the different combinations in the result arises from different calls of the method
+ * (recursively up til the main()-method.
+ * Each combination includes all variables alive at the exit of any surrounding call.
+ *
+ * @param statement The statement to examine
+ * @return All combinations of variables alive at the statement
+ */
+ public AliveCombinations getAliveCombinations(Statement statement) {
+ return effectiveLiveCombinations.get(statement.getIndex());
+ }
+
+ /** Combinations of variables effectively alive at a specific statement.
+ * If the statement is inside a method the combinations are the live variables inside the method combined with each calling statements alive vars.
+ * As each caller might also be inside a methos there may be a large amount of combinations.
+ */
+ public static class AliveCombinations {
+
+ private Collection combinations;
+
+ public AliveCombinations(Collection> aliveCombinations) {
+ ArrayList combinations = new ArrayList<>();
+ for (Collection aliveCombination : aliveCombinations) {
+ combinations.add(new AliveCombination(aliveCombination));
+ }
+ this.combinations = combinations;
+ }
+
+ public Collection getCombinations() {
+ return combinations;
+ }
+
+ }
+
+ /** One single combinations of variables effectively alive at a specific statement. */
+ public static class AliveCombination {
+
+ private Collection alive;
+
+ public AliveCombination(Collection alive) {
+ this.alive = alive;
+ }
+
+ public Collection getAlive() {
+ return alive;
+ }
+
}
diff --git a/src/main/java/dk/camelot64/kickc/model/StatementBase.java b/src/main/java/dk/camelot64/kickc/model/StatementBase.java
index fa745ef88..a3f64480e 100644
--- a/src/main/java/dk/camelot64/kickc/model/StatementBase.java
+++ b/src/main/java/dk/camelot64/kickc/model/StatementBase.java
@@ -1,5 +1,6 @@
package dk.camelot64.kickc.model;
+import java.util.Collection;
import java.util.List;
/** Statement base class implementing shared properties and logic */
@@ -48,7 +49,22 @@ public abstract class StatementBase implements Statement {
return "";
}
LiveRangeVariables liveRanges = program.getLiveRangeVariables();
- List alive = liveRanges.getAlive(this);
+ StringBuilder alive = new StringBuilder();
+ alive.append(getAliveString(liveRanges.getAlive(this)));
+ LiveRangeVariablesEffective liveRangeVariablesEffective = program.getLiveRangeVariablesEffective();
+ if(liveRangeVariablesEffective!=null) {
+ LiveRangeVariablesEffective.AliveCombinations aliveCombinations = liveRangeVariablesEffective.getAliveCombinations(this);
+ alive.append(" ( ");
+ for (LiveRangeVariablesEffective.AliveCombination aliveCombination : aliveCombinations.getCombinations()) {
+ alive.append(getAliveString(aliveCombination.getAlive()));
+ alive.append(" ");
+ }
+ alive.append(")");
+ }
+ return alive.toString();
+ }
+
+ private String getAliveString(Collection alive) {
StringBuilder str = new StringBuilder();
str.append(" [ ");
for (VariableRef variableRef : alive) {
diff --git a/src/main/java/dk/camelot64/kickc/parser/KickC.g4 b/src/main/java/dk/camelot64/kickc/parser/KickC.g4
index e26b34c0d..3c80a75a9 100644
--- a/src/main/java/dk/camelot64/kickc/parser/KickC.g4
+++ b/src/main/java/dk/camelot64/kickc/parser/KickC.g4
@@ -90,7 +90,7 @@ parameterList
;
asmLines
- : asmLine ( asmLine )*
+ : asmLine*
;
asmLine
diff --git a/src/main/java/dk/camelot64/kickc/parser/KickCParser.java b/src/main/java/dk/camelot64/kickc/parser/KickCParser.java
index 9660d307c..84aabcc36 100644
--- a/src/main/java/dk/camelot64/kickc/parser/KickCParser.java
+++ b/src/main/java/dk/camelot64/kickc/parser/KickCParser.java
@@ -2315,19 +2315,17 @@ public class KickCParser extends Parser {
try {
enterOuterAlt(_localctx, 1);
{
- setState(288);
- asmLine();
- setState(292);
+ setState(291);
_errHandler.sync(this);
_la = _input.LA(1);
while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__26) | (1L << MNEMONIC) | (1L << NAME))) != 0)) {
{
{
- setState(289);
+ setState(288);
asmLine();
}
}
- setState(294);
+ setState(293);
_errHandler.sync(this);
_la = _input.LA(1);
}
@@ -2374,21 +2372,21 @@ public class KickCParser extends Parser {
AsmLineContext _localctx = new AsmLineContext(_ctx, getState());
enterRule(_localctx, 28, RULE_asmLine);
try {
- setState(297);
+ setState(296);
_errHandler.sync(this);
switch (_input.LA(1)) {
case T__26:
case NAME:
enterOuterAlt(_localctx, 1);
{
- setState(295);
+ setState(294);
asmLabel();
}
break;
case MNEMONIC:
enterOuterAlt(_localctx, 2);
{
- setState(296);
+ setState(295);
asmInstruction();
}
break;
@@ -2432,24 +2430,24 @@ public class KickCParser extends Parser {
AsmLabelContext _localctx = new AsmLabelContext(_ctx, getState());
enterRule(_localctx, 30, RULE_asmLabel);
try {
- setState(303);
+ setState(302);
_errHandler.sync(this);
switch (_input.LA(1)) {
case NAME:
enterOuterAlt(_localctx, 1);
{
- setState(299);
+ setState(298);
match(NAME);
- setState(300);
+ setState(299);
match(T__14);
}
break;
case T__26:
enterOuterAlt(_localctx, 2);
{
- setState(301);
+ setState(300);
match(T__26);
- setState(302);
+ setState(301);
match(T__14);
}
break;
@@ -2498,14 +2496,14 @@ public class KickCParser extends Parser {
try {
enterOuterAlt(_localctx, 1);
{
- setState(305);
+ setState(304);
match(MNEMONIC);
- setState(307);
+ setState(306);
_errHandler.sync(this);
switch ( getInterpreter().adaptivePredict(_input,30,_ctx) ) {
case 1:
{
- setState(306);
+ setState(305);
asmParamMode();
}
break;
@@ -2656,14 +2654,14 @@ public class KickCParser extends Parser {
AsmParamModeContext _localctx = new AsmParamModeContext(_ctx, getState());
enterRule(_localctx, 34, RULE_asmParamMode);
try {
- setState(332);
+ setState(331);
_errHandler.sync(this);
switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) {
case 1:
_localctx = new AsmModeAbsContext(_localctx);
enterOuterAlt(_localctx, 1);
{
- setState(309);
+ setState(308);
asmExpr(0);
}
break;
@@ -2671,9 +2669,9 @@ public class KickCParser extends Parser {
_localctx = new AsmModeImmContext(_localctx);
enterOuterAlt(_localctx, 2);
{
- setState(310);
+ setState(309);
match(T__44);
- setState(311);
+ setState(310);
asmExpr(0);
}
break;
@@ -2681,11 +2679,11 @@ public class KickCParser extends Parser {
_localctx = new AsmModeAbsXYContext(_localctx);
enterOuterAlt(_localctx, 3);
{
- setState(312);
+ setState(311);
asmExpr(0);
- setState(313);
+ setState(312);
match(T__16);
- setState(314);
+ setState(313);
match(NAME);
}
break;
@@ -2693,15 +2691,15 @@ public class KickCParser extends Parser {
_localctx = new AsmModeIndIdxXYContext(_localctx);
enterOuterAlt(_localctx, 4);
{
- setState(316);
+ setState(315);
match(T__2);
- setState(317);
+ setState(316);
asmExpr(0);
- setState(318);
+ setState(317);
match(T__3);
- setState(319);
+ setState(318);
match(T__16);
- setState(320);
+ setState(319);
match(NAME);
}
break;
@@ -2709,15 +2707,15 @@ public class KickCParser extends Parser {
_localctx = new AsmModeIdxIndXYContext(_localctx);
enterOuterAlt(_localctx, 5);
{
- setState(322);
+ setState(321);
match(T__2);
- setState(323);
+ setState(322);
asmExpr(0);
- setState(324);
+ setState(323);
match(T__16);
- setState(325);
+ setState(324);
match(NAME);
- setState(326);
+ setState(325);
match(T__3);
}
break;
@@ -2725,11 +2723,11 @@ public class KickCParser extends Parser {
_localctx = new AsmModeIndContext(_localctx);
enterOuterAlt(_localctx, 6);
{
- setState(328);
+ setState(327);
match(T__2);
- setState(329);
+ setState(328);
asmExpr(0);
- setState(330);
+ setState(329);
match(T__3);
}
break;
@@ -2900,7 +2898,7 @@ public class KickCParser extends Parser {
int _alt;
enterOuterAlt(_localctx, 1);
{
- setState(344);
+ setState(343);
_errHandler.sync(this);
switch (_input.LA(1)) {
case T__20:
@@ -2912,7 +2910,7 @@ public class KickCParser extends Parser {
_ctx = _localctx;
_prevctx = _localctx;
- setState(335);
+ setState(334);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__20) | (1L << T__21) | (1L << T__24) | (1L << T__25))) != 0)) ) {
_errHandler.recoverInline(this);
@@ -2922,7 +2920,7 @@ public class KickCParser extends Parser {
_errHandler.reportMatch(this);
consume();
}
- setState(336);
+ setState(335);
asmExpr(8);
}
break;
@@ -2931,7 +2929,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprLabelContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
- setState(337);
+ setState(336);
match(NAME);
}
break;
@@ -2940,7 +2938,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprLabelRelContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
- setState(338);
+ setState(337);
match(ASMREL);
}
break;
@@ -2949,11 +2947,11 @@ public class KickCParser extends Parser {
_localctx = new AsmExprReplaceContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
- setState(339);
+ setState(338);
match(T__0);
- setState(340);
+ setState(339);
match(NAME);
- setState(341);
+ setState(340);
match(T__1);
}
break;
@@ -2962,7 +2960,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprIntContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
- setState(342);
+ setState(341);
match(NUMBER);
}
break;
@@ -2971,7 +2969,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprCharContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
- setState(343);
+ setState(342);
match(CHAR);
}
break;
@@ -2979,7 +2977,7 @@ public class KickCParser extends Parser {
throw new NoViableAltException(this);
}
_ctx.stop = _input.LT(-1);
- setState(354);
+ setState(353);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,34,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -2987,16 +2985,16 @@ public class KickCParser extends Parser {
if ( _parseListeners!=null ) triggerExitRuleEvent();
_prevctx = _localctx;
{
- setState(352);
+ setState(351);
_errHandler.sync(this);
switch ( getInterpreter().adaptivePredict(_input,33,_ctx) ) {
case 1:
{
_localctx = new AsmExprBinaryContext(new AsmExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_asmExpr);
- setState(346);
+ setState(345);
if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)");
- setState(347);
+ setState(346);
_la = _input.LA(1);
if ( !(_la==T__17 || _la==T__31) ) {
_errHandler.recoverInline(this);
@@ -3006,7 +3004,7 @@ public class KickCParser extends Parser {
_errHandler.reportMatch(this);
consume();
}
- setState(348);
+ setState(347);
asmExpr(8);
}
break;
@@ -3014,9 +3012,9 @@ public class KickCParser extends Parser {
{
_localctx = new AsmExprBinaryContext(new AsmExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_asmExpr);
- setState(349);
+ setState(348);
if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)");
- setState(350);
+ setState(349);
_la = _input.LA(1);
if ( !(_la==T__24 || _la==T__25) ) {
_errHandler.recoverInline(this);
@@ -3026,14 +3024,14 @@ public class KickCParser extends Parser {
_errHandler.reportMatch(this);
consume();
}
- setState(351);
+ setState(350);
asmExpr(7);
}
break;
}
}
}
- setState(356);
+ setState(355);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,34,_ctx);
}
@@ -3117,7 +3115,7 @@ public class KickCParser extends Parser {
}
public static final String _serializedATN =
- "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3B\u0168\4\2\t\2\4"+
+ "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3B\u0167\4\2\t\2\4"+
"\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+
"\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\3\2\3\2\3\2\3\3\3\3\3\3\3\4\6\4\60\n\4\r\4\16\4\61"+
@@ -3137,29 +3135,29 @@ public class KickCParser extends Parser {
"\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3"+
"\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\7\r"+
"\u0116\n\r\f\r\16\r\u0119\13\r\3\16\3\16\3\16\7\16\u011e\n\16\f\16\16"+
- "\16\u0121\13\16\3\17\3\17\7\17\u0125\n\17\f\17\16\17\u0128\13\17\3\20"+
- "\3\20\5\20\u012c\n\20\3\21\3\21\3\21\3\21\5\21\u0132\n\21\3\22\3\22\5"+
- "\22\u0136\n\22\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23"+
- "\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\5\23\u014f"+
- "\n\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\5\24\u015b\n\24"+
- "\3\24\3\24\3\24\3\24\3\24\3\24\7\24\u0163\n\24\f\24\16\24\u0166\13\24"+
- "\3\24\2\6\22\26\30&\25\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&\2\13"+
- "\3\2\27\30\3\2\31\32\5\2\24\24\27\30\33\37\3\2 !\4\2\24\24\"#\3\2\33\34"+
- "\4\2\27\30$*\4\2\27\30\33\34\4\2\24\24\"\"\2\u019b\2(\3\2\2\2\4+\3\2\2"+
- "\2\6/\3\2\2\2\b\u0082\3\2\2\2\n\u0085\3\2\2\2\f\u0097\3\2\2\2\16\u0099"+
- "\3\2\2\2\20\u00a1\3\2\2\2\22\u00a4\3\2\2\2\24\u00c0\3\2\2\2\26\u00cc\3"+
- "\2\2\2\30\u00f1\3\2\2\2\32\u011a\3\2\2\2\34\u0122\3\2\2\2\36\u012b\3\2"+
- "\2\2 \u0131\3\2\2\2\"\u0133\3\2\2\2$\u014e\3\2\2\2&\u015a\3\2\2\2()\5"+
- "\6\4\2)*\7\2\2\3*\3\3\2\2\2+,\5\34\17\2,-\7\2\2\3-\5\3\2\2\2.\60\5\b\5"+
- "\2/.\3\2\2\2\60\61\3\2\2\2\61/\3\2\2\2\61\62\3\2\2\2\62\7\3\2\2\2\63\65"+
- "\7\3\2\2\64\66\5\6\4\2\65\64\3\2\2\2\65\66\3\2\2\2\66\67\3\2\2\2\67\u0083"+
- "\7\4\2\289\5\22\n\29:\7>\2\2:<\7\5\2\2;=\5\16\b\2<;\3\2\2\2<=\3\2\2\2"+
- "=>\3\2\2\2>?\7\6\2\2?A\7\3\2\2@B\5\6\4\2A@\3\2\2\2AB\3\2\2\2BC\3\2\2\2"+
- "CD\7\4\2\2D\u0083\3\2\2\2EG\7\7\2\2FE\3\2\2\2FG\3\2\2\2GH\3\2\2\2HI\5"+
- "\22\n\2IL\7>\2\2JK\7\b\2\2KM\5\24\13\2LJ\3\2\2\2LM\3\2\2\2MN\3\2\2\2N"+
- "O\7\t\2\2O\u0083\3\2\2\2PQ\5\26\f\2QR\7\b\2\2RS\5\30\r\2ST\7\t\2\2T\u0083"+
- "\3\2\2\2UV\5\30\r\2VW\7\t\2\2W\u0083\3\2\2\2XY\7\n\2\2YZ\7\5\2\2Z[\5\30"+
- "\r\2[\\\7\6\2\2\\_\5\b\5\2]^\7\13\2\2^`\5\b\5\2_]\3\2\2\2_`\3\2\2\2`\u0083"+
+ "\16\u0121\13\16\3\17\7\17\u0124\n\17\f\17\16\17\u0127\13\17\3\20\3\20"+
+ "\5\20\u012b\n\20\3\21\3\21\3\21\3\21\5\21\u0131\n\21\3\22\3\22\5\22\u0135"+
+ "\n\22\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23"+
+ "\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\3\23\5\23\u014e\n\23\3\24"+
+ "\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\5\24\u015a\n\24\3\24\3\24"+
+ "\3\24\3\24\3\24\3\24\7\24\u0162\n\24\f\24\16\24\u0165\13\24\3\24\2\6\22"+
+ "\26\30&\25\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&\2\13\3\2\27\30"+
+ "\3\2\31\32\5\2\24\24\27\30\33\37\3\2 !\4\2\24\24\"#\3\2\33\34\4\2\27\30"+
+ "$*\4\2\27\30\33\34\4\2\24\24\"\"\2\u019a\2(\3\2\2\2\4+\3\2\2\2\6/\3\2"+
+ "\2\2\b\u0082\3\2\2\2\n\u0085\3\2\2\2\f\u0097\3\2\2\2\16\u0099\3\2\2\2"+
+ "\20\u00a1\3\2\2\2\22\u00a4\3\2\2\2\24\u00c0\3\2\2\2\26\u00cc\3\2\2\2\30"+
+ "\u00f1\3\2\2\2\32\u011a\3\2\2\2\34\u0125\3\2\2\2\36\u012a\3\2\2\2 \u0130"+
+ "\3\2\2\2\"\u0132\3\2\2\2$\u014d\3\2\2\2&\u0159\3\2\2\2()\5\6\4\2)*\7\2"+
+ "\2\3*\3\3\2\2\2+,\5\34\17\2,-\7\2\2\3-\5\3\2\2\2.\60\5\b\5\2/.\3\2\2\2"+
+ "\60\61\3\2\2\2\61/\3\2\2\2\61\62\3\2\2\2\62\7\3\2\2\2\63\65\7\3\2\2\64"+
+ "\66\5\6\4\2\65\64\3\2\2\2\65\66\3\2\2\2\66\67\3\2\2\2\67\u0083\7\4\2\2"+
+ "89\5\22\n\29:\7>\2\2:<\7\5\2\2;=\5\16\b\2<;\3\2\2\2<=\3\2\2\2=>\3\2\2"+
+ "\2>?\7\6\2\2?A\7\3\2\2@B\5\6\4\2A@\3\2\2\2AB\3\2\2\2BC\3\2\2\2CD\7\4\2"+
+ "\2D\u0083\3\2\2\2EG\7\7\2\2FE\3\2\2\2FG\3\2\2\2GH\3\2\2\2HI\5\22\n\2I"+
+ "L\7>\2\2JK\7\b\2\2KM\5\24\13\2LJ\3\2\2\2LM\3\2\2\2MN\3\2\2\2NO\7\t\2\2"+
+ "O\u0083\3\2\2\2PQ\5\26\f\2QR\7\b\2\2RS\5\30\r\2ST\7\t\2\2T\u0083\3\2\2"+
+ "\2UV\5\30\r\2VW\7\t\2\2W\u0083\3\2\2\2XY\7\n\2\2YZ\7\5\2\2Z[\5\30\r\2"+
+ "[\\\7\6\2\2\\_\5\b\5\2]^\7\13\2\2^`\5\b\5\2_]\3\2\2\2_`\3\2\2\2`\u0083"+
"\3\2\2\2ab\7\f\2\2bc\7\5\2\2cd\5\30\r\2de\7\6\2\2ef\5\b\5\2f\u0083\3\2"+
"\2\2gh\7\r\2\2hi\5\b\5\2ij\7\f\2\2jk\7\5\2\2kl\5\30\r\2lm\7\6\2\2mn\7"+
"\t\2\2n\u0083\3\2\2\2op\7\16\2\2pr\7\5\2\2qs\5\n\6\2rq\3\2\2\2rs\3\2\2"+
@@ -3224,33 +3222,32 @@ public class KickCParser extends Parser {
"\31\3\2\2\2\u0119\u0117\3\2\2\2\u011a\u011f\5\30\r\2\u011b\u011c\7\23"+
"\2\2\u011c\u011e\5\30\r\2\u011d\u011b\3\2\2\2\u011e\u0121\3\2\2\2\u011f"+
"\u011d\3\2\2\2\u011f\u0120\3\2\2\2\u0120\33\3\2\2\2\u0121\u011f\3\2\2"+
- "\2\u0122\u0126\5\36\20\2\u0123\u0125\5\36\20\2\u0124\u0123\3\2\2\2\u0125"+
- "\u0128\3\2\2\2\u0126\u0124\3\2\2\2\u0126\u0127\3\2\2\2\u0127\35\3\2\2"+
- "\2\u0128\u0126\3\2\2\2\u0129\u012c\5 \21\2\u012a\u012c\5\"\22\2\u012b"+
- "\u0129\3\2\2\2\u012b\u012a\3\2\2\2\u012c\37\3\2\2\2\u012d\u012e\7>\2\2"+
- "\u012e\u0132\7\21\2\2\u012f\u0130\7\35\2\2\u0130\u0132\7\21\2\2\u0131"+
- "\u012d\3\2\2\2\u0131\u012f\3\2\2\2\u0132!\3\2\2\2\u0133\u0135\7\60\2\2"+
- "\u0134\u0136\5$\23\2\u0135\u0134\3\2\2\2\u0135\u0136\3\2\2\2\u0136#\3"+
- "\2\2\2\u0137\u014f\5&\24\2\u0138\u0139\7/\2\2\u0139\u014f\5&\24\2\u013a"+
- "\u013b\5&\24\2\u013b\u013c\7\23\2\2\u013c\u013d\7>\2\2\u013d\u014f\3\2"+
- "\2\2\u013e\u013f\7\5\2\2\u013f\u0140\5&\24\2\u0140\u0141\7\6\2\2\u0141"+
- "\u0142\7\23\2\2\u0142\u0143\7>\2\2\u0143\u014f\3\2\2\2\u0144\u0145\7\5"+
- "\2\2\u0145\u0146\5&\24\2\u0146\u0147\7\23\2\2\u0147\u0148\7>\2\2\u0148"+
- "\u0149\7\6\2\2\u0149\u014f\3\2\2\2\u014a\u014b\7\5\2\2\u014b\u014c\5&"+
- "\24\2\u014c\u014d\7\6\2\2\u014d\u014f\3\2\2\2\u014e\u0137\3\2\2\2\u014e"+
- "\u0138\3\2\2\2\u014e\u013a\3\2\2\2\u014e\u013e\3\2\2\2\u014e\u0144\3\2"+
- "\2\2\u014e\u014a\3\2\2\2\u014f%\3\2\2\2\u0150\u0151\b\24\1\2\u0151\u0152"+
- "\t\t\2\2\u0152\u015b\5&\24\n\u0153\u015b\7>\2\2\u0154\u015b\7?\2\2\u0155"+
- "\u0156\7\3\2\2\u0156\u0157\7>\2\2\u0157\u015b\7\4\2\2\u0158\u015b\7\65"+
- "\2\2\u0159\u015b\7\63\2\2\u015a\u0150\3\2\2\2\u015a\u0153\3\2\2\2\u015a"+
- "\u0154\3\2\2\2\u015a\u0155\3\2\2\2\u015a\u0158\3\2\2\2\u015a\u0159\3\2"+
- "\2\2\u015b\u0164\3\2\2\2\u015c\u015d\f\t\2\2\u015d\u015e\t\n\2\2\u015e"+
- "\u0163\5&\24\n\u015f\u0160\f\b\2\2\u0160\u0161\t\7\2\2\u0161\u0163\5&"+
- "\24\t\u0162\u015c\3\2\2\2\u0162\u015f\3\2\2\2\u0163\u0166\3\2\2\2\u0164"+
- "\u0162\3\2\2\2\u0164\u0165\3\2\2\2\u0165\'\3\2\2\2\u0166\u0164\3\2\2\2"+
- "%\61\65\2\2\u012d\u0131\7\21\2"+
+ "\2\u012e\u012f\7\35\2\2\u012f\u0131\7\21\2\2\u0130\u012c\3\2\2\2\u0130"+
+ "\u012e\3\2\2\2\u0131!\3\2\2\2\u0132\u0134\7\60\2\2\u0133\u0135\5$\23\2"+
+ "\u0134\u0133\3\2\2\2\u0134\u0135\3\2\2\2\u0135#\3\2\2\2\u0136\u014e\5"+
+ "&\24\2\u0137\u0138\7/\2\2\u0138\u014e\5&\24\2\u0139\u013a\5&\24\2\u013a"+
+ "\u013b\7\23\2\2\u013b\u013c\7>\2\2\u013c\u014e\3\2\2\2\u013d\u013e\7\5"+
+ "\2\2\u013e\u013f\5&\24\2\u013f\u0140\7\6\2\2\u0140\u0141\7\23\2\2\u0141"+
+ "\u0142\7>\2\2\u0142\u014e\3\2\2\2\u0143\u0144\7\5\2\2\u0144\u0145\5&\24"+
+ "\2\u0145\u0146\7\23\2\2\u0146\u0147\7>\2\2\u0147\u0148\7\6\2\2\u0148\u014e"+
+ "\3\2\2\2\u0149\u014a\7\5\2\2\u014a\u014b\5&\24\2\u014b\u014c\7\6\2\2\u014c"+
+ "\u014e\3\2\2\2\u014d\u0136\3\2\2\2\u014d\u0137\3\2\2\2\u014d\u0139\3\2"+
+ "\2\2\u014d\u013d\3\2\2\2\u014d\u0143\3\2\2\2\u014d\u0149\3\2\2\2\u014e"+
+ "%\3\2\2\2\u014f\u0150\b\24\1\2\u0150\u0151\t\t\2\2\u0151\u015a\5&\24\n"+
+ "\u0152\u015a\7>\2\2\u0153\u015a\7?\2\2\u0154\u0155\7\3\2\2\u0155\u0156"+
+ "\7>\2\2\u0156\u015a\7\4\2\2\u0157\u015a\7\65\2\2\u0158\u015a\7\63\2\2"+
+ "\u0159\u014f\3\2\2\2\u0159\u0152\3\2\2\2\u0159\u0153\3\2\2\2\u0159\u0154"+
+ "\3\2\2\2\u0159\u0157\3\2\2\2\u0159\u0158\3\2\2\2\u015a\u0163\3\2\2\2\u015b"+
+ "\u015c\f\t\2\2\u015c\u015d\t\n\2\2\u015d\u0162\5&\24\n\u015e\u015f\f\b"+
+ "\2\2\u015f\u0160\t\7\2\2\u0160\u0162\5&\24\t\u0161\u015b\3\2\2\2\u0161"+
+ "\u015e\3\2\2\2\u0162\u0165\3\2\2\2\u0163\u0161\3\2\2\2\u0163\u0164\3\2"+
+ "\2\2\u0164\'\3\2\2\2\u0165\u0163\3\2\2\2%\61\65 visitor = new ControlFlowGraphBaseVisitor() {
+ final ControlFlowGraphBaseVisitor visitor = new ControlFlowGraphBaseVisitor() {
@Override
public Void visitAssignment(StatementAssignment assignment) {
if (assignment.getlValue() instanceof VariableRef) {
@@ -278,7 +278,11 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
if(variable.getScopeNames().equals(alias.getScopeNames())){
aliases.add(variable, alias);
} else {
- getLog().append("Not aliassing across scopes: "+variable+" "+alias);
+ if(allowCrossScope) {
+ aliases.add(variable, alias);
+ } else {
+ program.getLog().append("Not aliassing across scopes: " + variable + " " + alias);
+ }
}
}
}
@@ -296,11 +300,13 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
if (phiRValue.getrValue() instanceof VariableRef) {
alias = (VariableRef) phiRValue.getrValue();
if(!variable.getScopeNames().equals(alias.getScopeNames())){
- getLog().append("Not aliassing across scopes: "+variable+" "+alias);
- alias = null;
- break;
+ if(!allowCrossScope) {
+ program.getLog().append("Not aliassing across scopes: " + variable + " " + alias);
+ alias = null;
+ break;
+ }
} else if(variable.equals(alias)) {
- getLog().append("Not aliassing identity: "+variable+" "+alias);
+ program.getLog().append("Not aliassing identity: "+variable+" "+alias);
alias = null;
break;
}
@@ -325,7 +331,7 @@ public class Pass2AliasElimination extends Pass2SsaOptimization {
return null;
}
};
- visitor.visitGraph(getGraph());
+ visitor.visitGraph(program.getGraph());
return aliases;
}
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java b/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java
index 3b214b205..7cf178d88 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass3LiveRangesEffectiveAnalysis.java
@@ -1,12 +1,12 @@
package dk.camelot64.kickc.passes;
-/**
- * Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
- */
import dk.camelot64.kickc.model.*;
import java.util.*;
+/**
+ * Find effective alive intervals for all variables in all statements. Add the intervals to the Program.
+ */
public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
public Pass3LiveRangesEffectiveAnalysis(Program program) {
@@ -19,17 +19,17 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
//getLog().append("Calculated effective variable live ranges");
}
-
private LiveRangeVariablesEffective findAliveEffective(Program program) {
LiveRangeVariables liveRangeVariables = program.getLiveRangeVariables();
- Map> effectiveLiveVariables = new HashMap<>();
+ Map effectiveLiveVariablesCombinations = new HashMap<>();
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for (Statement statement : block.getStatements()) {
- Collection aliveEffective = findAliveEffective( liveRangeVariables, statement);
- effectiveLiveVariables.put(statement.getIndex(), aliveEffective);
+ Collection> statementAliveCombinations = findAliveEffective(liveRangeVariables, statement);
+ LiveRangeVariablesEffective.AliveCombinations aliveCombinations = new LiveRangeVariablesEffective.AliveCombinations(statementAliveCombinations);
+ effectiveLiveVariablesCombinations.put(statement.getIndex(), aliveCombinations);
}
}
- return new LiveRangeVariablesEffective(effectiveLiveVariables);
+ return new LiveRangeVariablesEffective(effectiveLiveVariablesCombinations);
}
/**
@@ -41,10 +41,10 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
* @param statement The statement to examine
* @return All variables alive at the statement
*/
- private Collection findAliveEffective(LiveRangeVariables liveRangeVariables, Statement statement) {
+ private Collection> findAliveEffective(LiveRangeVariables liveRangeVariables, Statement statement) {
+ Set> combinations = new LinkedHashSet<>();
// Get variables alive from live range analysis
- Collection effectiveAlive = new LinkedHashSet<>();
- effectiveAlive.addAll(liveRangeVariables.getAlive(statement));
+ Collection effectiveAlive = liveRangeVariables.getAlive(statement);
// If the statement is inside a method recurse back to all calls
// For each call add the variables alive after the call that are not referenced (used/defined) inside the method
ControlFlowBlock block = getProgram().getGraph().getBlockFromStatementIdx(statement.getIndex());
@@ -57,16 +57,28 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
VariableReferenceInfo referenceInfo = new VariableReferenceInfo(getProgram());
Collection referencedInProcedure = referenceInfo.getReferenced(procedure.getRef().getLabelRef());
for (CallGraph.CallBlock.Call caller : callers) {
+ // Each caller creates its own combinations
StatementCall callStatement =
(StatementCall) getProgram().getGraph().getStatementByIndex(caller.getCallStatementIdx());
- Set callAliveEffective = new LinkedHashSet<>(findAliveEffective(liveRangeVariables, callStatement));
- // Clear out any variables referenced in the method
- callAliveEffective.removeAll(referencedInProcedure);
- effectiveAlive.addAll(callAliveEffective);
+ Collection> callerCombinations = findAliveEffective(liveRangeVariables, callStatement);
+ for (Collection callerCombination : callerCombinations) {
+ LinkedHashSet combination = new LinkedHashSet<>();
+ // Add alive at call
+ combination.addAll(callerCombination);
+ // Clear out any variables referenced in the method
+ combination.removeAll(referencedInProcedure);
+ // Add alive at statement
+ combination.addAll(effectiveAlive);
+ // Add combination
+ combinations.add(combination);
+ }
}
}
- return effectiveAlive;
+ if(combinations.size()==0) {
+ // Add the combination at the current statement if no other combinations have been created
+ combinations.add(effectiveAlive);
+ }
+ return combinations;
}
-
}
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java
index c47b67395..fc6d75543 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftCombinations.java
@@ -42,10 +42,10 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
* Stores the best combination directly in the {@link LiveRangeEquivalenceClassSet}.
*
* @param combinationIterator The combination iterator used for supplying different register allocations to test
- * @param maxCombinations The maximal number of combinations to test. It the iterator has more combinations he rest is skipped (and a message logged)
- * @param unknownFragments Receives any unknown ASM fragments encountered during the combinsation search
- * @param scope The scope where the variables are being tested. (Only used for logging)
- * @param program The program to test (used for accessing global data structures)
+ * @param maxCombinations The maximal number of combinations to test. It the iterator has more combinations he rest is skipped (and a message logged)
+ * @param unknownFragments Receives any unknown ASM fragments encountered during the combinsation search
+ * @param scope The scope where the variables are being tested. (Only used for logging)
+ * @param program The program to test (used for accessing global data structures)
*/
static void chooseBestUpliftCombination(
RegisterCombinationIterator combinationIterator, int maxCombinations,
@@ -93,15 +93,15 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
* Attempt generate ASM with a specific register combination.
* The generation may result in failure if
*
- * - The combination has assigned the same register to variables with overlapping live ranges
- * - The register combination results in clobbering registers containing values that are still alive
- * - some ASM fragments are missing
- * - the ALU register is used in a non-applicable way
+ * - The combination has assigned the same register to variables with overlapping live ranges
+ * - The register combination results in clobbering registers containing values that are still alive
+ * - some ASM fragments are missing
+ * - the ALU register is used in a non-applicable way
*
*
- * @param combination The register allocation combination
+ * @param combination The register allocation combination
* @param unknownFragments Will receive any AsmFragments that can not be found during the ASM code generation
- * @param scope The scope where the combination is tested. (Only used for logging)
+ * @param scope The scope where the combination is tested. (Only used for logging)
* @return true if the generation was successful
*/
public static boolean generateCombinationAsm(
@@ -167,6 +167,7 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
* Programs that take less cycles to execute have lower scores.
* In practice the score is calculated by multiplying cycles of ASM instructions with
* an estimate of the invocation count based on the loop depth of the instructions (10^depth).
+ *
* @param program The program containing the ASM to check
* @return The score of the ASM
*/
@@ -190,17 +191,17 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
return score;
}
-
/**
* Check the register allocation for whether a is register being allocated to two variables with overlapping live ranges
+ *
* @param program The program
* @return true if the register allocation contains an overlapping allocation. false otherwise.
*/
public static boolean isAllocationOverlapping(Program program) {
+ Pass2AliasElimination.Aliases aliases = Pass2AliasElimination.findAliasesCandidates(true, program);
for (ControlFlowBlock block : program.getGraph().getAllBlocks()) {
for (Statement statement : block.getStatements()) {
- LinkedHashMap usedRegisters = new LinkedHashMap<>();
- if (isStatementAllocationOverlapping(program, statement, usedRegisters)) {
+ if (isStatementAllocationOverlapping(program, statement, aliases)) {
return true;
}
}
@@ -211,32 +212,46 @@ public class Pass4RegisterUpliftCombinations extends Pass2Base {
/**
* Determine if a statement has an overlapping register allocation
*
- * @param program The program
- * @param statement The statement to check
+ * @param program The program
+ * @param statement The statement to check
* @param usedRegisters The used registers. Will be extended with all registers used in the statement.
* @return true if there is an overlapping register allocation
*/
- private static boolean isStatementAllocationOverlapping(
- Program program,
- Statement statement,
- LinkedHashMap usedRegisters) {
+ private static boolean isStatementAllocationOverlapping(Program program, Statement statement, Pass2AliasElimination.Aliases aliases) {
ProgramScope programScope = program.getScope();
- Collection alive = program.getLiveRangeVariablesEffective().getAliveEffective(statement);
- for (VariableRef varRef : alive) {
- Variable var = programScope.getVariable(varRef);
- Registers.Register allocation = var.getAllocation();
- LiveRangeEquivalenceClass allocationClass = usedRegisters.get(allocation);
- if (allocationClass != null && !allocationClass.contains(varRef)) {
- if (program.getLog().isVerboseUplift()) {
- StringBuilder msg = new StringBuilder();
- msg.append("Overlap register " + allocation + " in " + statement.toString(program));
- program.getLog().append(msg.toString());
+ LiveRangeVariablesEffective.AliveCombinations aliveCombinations = program.getLiveRangeVariablesEffective().getAliveCombinations(statement);
+ for (LiveRangeVariablesEffective.AliveCombination aliveCombination : aliveCombinations.getCombinations()) {
+ LinkedHashMap usedRegisters = new LinkedHashMap<>();
+ Collection alive = aliveCombination.getAlive();
+ for (VariableRef varRef : alive) {
+ Variable var = programScope.getVariable(varRef);
+ Registers.Register allocation = var.getAllocation();
+ LiveRangeEquivalenceClass allocationClass = usedRegisters.get(allocation);
+ if (allocationClass != null && !allocationClass.contains(varRef)) {
+ // Examine if the var is an alias of a var in the allocation class
+ boolean overlap = true;
+ Pass2AliasElimination.AliasSet aliasSet = aliases.findAliasSet(varRef);
+ if(aliasSet!=null) {
+ for (VariableRef aliasVar : aliasSet.getVars()) {
+ if(allocationClass.contains(aliasVar)) {
+ overlap = false;
+ }
+ }
+ }
+ if(overlap) {
+ if (program.getLog().isVerboseUplift()) {
+ StringBuilder msg = new StringBuilder();
+ msg.append("Overlap register " + allocation + " in " + statement.toString(program));
+ program.getLog().append(msg.toString());
+ }
+ return true;
+ }
+ } else {
+ LiveRangeEquivalenceClass varClass =
+ program.getLiveRangeEquivalenceClassSet().getEquivalenceClass(varRef);
+ usedRegisters.put(allocation, varClass);
}
- return true;
}
- LiveRangeEquivalenceClass varClass =
- program.getLiveRangeEquivalenceClassSet().getEquivalenceClass(varRef);
- usedRegisters.put(allocation, varClass);
}
return false;
}
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java
index e0faef631..f9a1de7bb 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegisterUpliftStatic.java
@@ -74,8 +74,15 @@ public class Pass4RegisterUpliftStatic extends Pass2Base {
setRegister(combination, "line::$7", Registers.getRegisterALU());
setRegister(combination, "initplottables::$6", Registers.getRegisterA());
setRegister(combination, "initplottables::$7", Registers.getRegisterALU());
- */
setRegister(combination, "initplottables::$6", Registers.getRegisterA());
+ */
+
+ setRegister(combination, "plot::x#0", Registers.getRegisterX());
+ setRegister(combination, "plot::x#1", Registers.getRegisterX());
+ setRegister(combination, "plot::x#2", Registers.getRegisterX());
+ setRegister(combination, "plot::x#3", Registers.getRegisterX());
+ setRegister(combination, "main::i#1", Registers.getRegisterX());
+ setRegister(combination, "main::i#2", Registers.getRegisterX());
boolean success = Pass4RegisterUpliftCombinations.generateCombinationAsm(
combination,