From b20327590f2119ef1419e5d3755069dcad7dda26 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Mon, 6 Nov 2017 08:20:33 +0100 Subject: [PATCH] Working on better live ranges that take into account the call-path taken to the current statement and any aliases on that path (due to phi statements) --- .../java/dk/camelot64/kickc/Compiler.java | 6 +- .../asm/zpptrby1=zpptrby1_plus_zpptrby1.asm | 6 + .../model/LiveRangeVariablesEffective.java | 71 +++++- .../camelot64/kickc/model/StatementBase.java | 18 +- .../java/dk/camelot64/kickc/parser/KickC.g4 | 2 +- .../camelot64/kickc/parser/KickCParser.java | 209 +++++++++--------- .../kickc/passes/Pass2AliasElimination.java | 24 +- .../Pass3LiveRangesEffectiveAnalysis.java | 46 ++-- .../Pass4RegisterUpliftCombinations.java | 81 ++++--- .../passes/Pass4RegisterUpliftStatic.java | 9 +- 10 files changed, 292 insertions(+), 180 deletions(-) create mode 100644 src/main/java/dk/camelot64/kickc/fragment/asm/zpptrby1=zpptrby1_plus_zpptrby1.asm 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,