diff --git a/src/main/java/dk/camelot64/kickc/model/Program.java b/src/main/java/dk/camelot64/kickc/model/Program.java index bf988636a..060923bac 100644 --- a/src/main/java/dk/camelot64/kickc/model/Program.java +++ b/src/main/java/dk/camelot64/kickc/model/Program.java @@ -37,7 +37,7 @@ public class Program { /** Absolute start address of the code. Null to start ad 0x080d. PASS 0-5 (STATIC) */ private Number programPc; /** Reserved ZP addresses that the compiler cannot use. PASS 0-5 (STATIC) */ - private List reservedZps; + private List reservedZps; /** Resource files that should be copied to the output folder to be compiled with the generated ASM. PASS 0-5 (STATIC) */ private List asmResourceFiles; /** Comments for the (main) file. PASS 0-4 (STATIC) */ @@ -398,15 +398,15 @@ public class Program { * * @param reservedZp addresses to reserve */ - public void addReservedZps(List reservedZp) { - for(Number zp : reservedZp) { + public void addReservedZps(List reservedZp) { + for(Integer zp : reservedZp) { if(!this.reservedZps.contains(zp)) { this.reservedZps.add(zp); } } } - public List getReservedZps() { + public List getReservedZps() { return reservedZps; } diff --git a/src/main/java/dk/camelot64/kickc/model/Registers.java b/src/main/java/dk/camelot64/kickc/model/Registers.java index 53899e07e..e8fbb8e95 100644 --- a/src/main/java/dk/camelot64/kickc/model/Registers.java +++ b/src/main/java/dk/camelot64/kickc/model/Registers.java @@ -4,6 +4,7 @@ import dk.camelot64.kickc.model.values.ConstantValue; import dk.camelot64.kickc.model.values.Value; import java.util.Locale; +import java.util.Objects; /** The different registers available for a program */ public class Registers { @@ -49,6 +50,7 @@ public class Registers { ZP_DWORD, ZP_STRUCT, ZP_BOOL, + ZP_VAR, CONSTANT } @@ -97,15 +99,48 @@ public class Registers { if(o == null || getClass() != o.getClass()) { return false; } - RegisterZp that = (RegisterZp) o; - return zp == that.zp; } @Override public int hashCode() { - return zp; + return zp+31*getClass().hashCode(); + } + + } + + /** A zero page address used as a register for a declared register allocation. Size is initially unknown and will be resolved when performing allocation by setting the type. */ + public static class RegisterZpDeclared extends RegisterZp { + + private RegisterType type; + + public RegisterZpDeclared(int zp) { + super(zp); + this.type = RegisterType.ZP_VAR; + } + + @Override + public RegisterType getType() { + return type; + } + + public void setType(RegisterType type) { + this.type = type; + } + + @Override + public boolean equals(Object o) { + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; + if(!super.equals(o)) return false; + RegisterZpDeclared that = (RegisterZpDeclared) o; + return type == that.type; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), type); } } @@ -186,7 +221,6 @@ public class Registers { } - /** A zero page address used as a register for a boolean variable. */ public static class RegisterZpBool extends RegisterZp { diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java index 8fb164811..dc8fde57f 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java @@ -24,7 +24,7 @@ public class Procedure extends Scope { /** Comments preceding the procedure in the source code. */ private List comments; /** Reserved zeropage addresses. */ - private List reservedZps; + private List reservedZps; /** The code segment to put the procedure into. */ private String codeSegment; @@ -120,16 +120,16 @@ public class Procedure extends Scope { * * @return reserved addresses */ - public List getReservedZps() { + public List getReservedZps() { return reservedZps; } /** * Gets any reserved zero-page addresses that the compiler is not allowed to use. * - * @param reservedZp reserved addresses + * @param reservedZps reserved addresses */ - public void setReservedZps(List reservedZps) { + public void setReservedZps(List reservedZps) { this.reservedZps = reservedZps; } diff --git a/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 b/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 index f13c41f91..b87f896c3 100644 --- a/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 +++ b/src/main/java/dk/camelot64/kickc/parser/KickCParser.g4 @@ -97,7 +97,7 @@ directive | EXTERN #directiveExtern | EXPORT #directiveExport | ALIGN PAR_BEGIN NUMBER PAR_END #directiveAlign - | REGISTER ( PAR_BEGIN NAME PAR_END)? #directiveRegister + | REGISTER ( PAR_BEGIN ( NAME | NUMBER ) PAR_END)? #directiveRegister | INLINE #directiveInline | VOLATILE #directiveVolatile | INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt diff --git a/src/main/java/dk/camelot64/kickc/parser/KickCParser.java b/src/main/java/dk/camelot64/kickc/parser/KickCParser.java index ff8308e56..164bd4ebb 100644 --- a/src/main/java/dk/camelot64/kickc/parser/KickCParser.java +++ b/src/main/java/dk/camelot64/kickc/parser/KickCParser.java @@ -1663,8 +1663,9 @@ public class KickCParser extends Parser { public static class DirectiveRegisterContext extends DirectiveContext { public TerminalNode REGISTER() { return getToken(KickCParser.REGISTER, 0); } public TerminalNode PAR_BEGIN() { return getToken(KickCParser.PAR_BEGIN, 0); } - public TerminalNode NAME() { return getToken(KickCParser.NAME, 0); } public TerminalNode PAR_END() { return getToken(KickCParser.PAR_END, 0); } + public TerminalNode NAME() { return getToken(KickCParser.NAME, 0); } + public TerminalNode NUMBER() { return getToken(KickCParser.NUMBER, 0); } public DirectiveRegisterContext(DirectiveContext ctx) { copyFrom(ctx); } @Override public void enterRule(ParseTreeListener listener) { @@ -1741,7 +1742,15 @@ public class KickCParser extends Parser { setState(250); match(PAR_BEGIN); setState(251); - match(NAME); + _la = _input.LA(1); + if ( !(_la==NUMBER || _la==NAME) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } setState(252); match(PAR_END); } @@ -6440,240 +6449,240 @@ public class KickCParser extends Parser { "\5+\u02cb\n+\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\5,\u02db\n,\3,"+ "\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\7,\u02e9\n,\f,\16,\u02ec\13,\3,\2\b"+ "\24.:>@V-\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\66"+ - "8:<>@BDFHJLNPRTV\2\r\3\2\26\27\5\2\21\22\30\31PP\4\2 ##\3\2\34\35\3\2"+ - "\23\25\3\2\21\22\3\2\36#\3\2ps\3\2no\3\2tu\3\2pq\2\u0355\2X\3\2\2\2\4"+ - "[\3\2\2\2\6a\3\2\2\2\bf\3\2\2\2\nh\3\2\2\2\fz\3\2\2\2\16|\3\2\2\2\20\u0084"+ - "\3\2\2\2\22\u008e\3\2\2\2\24\u0091\3\2\2\2\26\u00a4\3\2\2\2\30\u00a6\3"+ - "\2\2\2\32\u00b3\3\2\2\2\34\u00bf\3\2\2\2\36\u00f2\3\2\2\2 \u0114\3\2\2"+ - "\2\"\u0117\3\2\2\2$\u016f\3\2\2\2&\u0172\3\2\2\2(\u017d\3\2\2\2*\u0193"+ - "\3\2\2\2,\u0199\3\2\2\2.\u01aa\3\2\2\2\60\u01bc\3\2\2\2\62\u01bf\3\2\2"+ - "\2\64\u01cb\3\2\2\2\66\u01ce\3\2\2\28\u01d1\3\2\2\2:\u01d9\3\2\2\2<\u01e4"+ - "\3\2\2\2>\u01e9\3\2\2\2@\u022a\3\2\2\2B\u026b\3\2\2\2D\u0273\3\2\2\2F"+ - "\u0279\3\2\2\2H\u0293\3\2\2\2J\u0298\3\2\2\2L\u029e\3\2\2\2N\u02a4\3\2"+ - "\2\2P\u02a6\3\2\2\2R\u02aa\3\2\2\2T\u02ca\3\2\2\2V\u02da\3\2\2\2XY\5\6"+ - "\4\2YZ\7\2\2\3Z\3\3\2\2\2[\\\5J&\2\\]\7\2\2\3]\5\3\2\2\2^`\5\b\5\2_^\3"+ - "\2\2\2`c\3\2\2\2a_\3\2\2\2ab\3\2\2\2b\7\3\2\2\2ca\3\2\2\2dg\5\f\7\2eg"+ - "\5\n\6\2fd\3\2\2\2fe\3\2\2\2g\t\3\2\2\2hi\7(\2\2ij\7U\2\2j\13\3\2\2\2"+ - "kl\5\22\n\2lm\7\n\2\2m{\3\2\2\2no\5\62\32\2op\7\n\2\2p{\3\2\2\2qr\58\35"+ - "\2rs\7\n\2\2s{\3\2\2\2t{\5\30\r\2u{\5D#\2v{\5\36\20\2wx\5\16\b\2xy\7\n"+ - "\2\2y{\3\2\2\2zk\3\2\2\2zn\3\2\2\2zq\3\2\2\2zt\3\2\2\2zu\3\2\2\2zv\3\2"+ - "\2\2zw\3\2\2\2{\r\3\2\2\2|}\7)\2\2}~\5.\30\2~\177\7`\2\2\177\u0080\b\b"+ - "\1\2\u0080\17\3\2\2\2\u0081\u0083\5 \21\2\u0082\u0081\3\2\2\2\u0083\u0086"+ - "\3\2\2\2\u0084\u0082\3\2\2\2\u0084\u0085\3\2\2\2\u0085\u0087\3\2\2\2\u0086"+ - "\u0084\3\2\2\2\u0087\u008b\5.\30\2\u0088\u008a\5 \21\2\u0089\u0088\3\2"+ - "\2\2\u008a\u008d\3\2\2\2\u008b\u0089\3\2\2\2\u008b\u008c\3\2\2\2\u008c"+ - "\21\3\2\2\2\u008d\u008b\3\2\2\2\u008e\u008f\5\20\t\2\u008f\u0090\5\24"+ - "\13\2\u0090\23\3\2\2\2\u0091\u0092\b\13\1\2\u0092\u0093\5\26\f\2\u0093"+ - "\u0099\3\2\2\2\u0094\u0095\f\3\2\2\u0095\u0096\7\f\2\2\u0096\u0098\5\26"+ - "\f\2\u0097\u0094\3\2\2\2\u0098\u009b\3\2\2\2\u0099\u0097\3\2\2\2\u0099"+ - "\u009a\3\2\2\2\u009a\25\3\2\2\2\u009b\u0099\3\2\2\2\u009c\u009f\7`\2\2"+ - "\u009d\u009e\7&\2\2\u009e\u00a0\5@!\2\u009f\u009d\3\2\2\2\u009f\u00a0"+ - "\3\2\2\2\u00a0\u00a5\3\2\2\2\u00a1\u00a2\7`\2\2\u00a2\u00a3\7&\2\2\u00a3"+ - "\u00a5\5D#\2\u00a4\u009c\3\2\2\2\u00a4\u00a1\3\2\2\2\u00a5\27\3\2\2\2"+ - "\u00a6\u00a7\5\20\t\2\u00a7\u00a8\7`\2\2\u00a8\u00aa\7\b\2\2\u00a9\u00ab"+ - "\5\32\16\2\u00aa\u00a9\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab\u00ac\3\2\2\2"+ - "\u00ac\u00ad\7\t\2\2\u00ad\u00af\7\4\2\2\u00ae\u00b0\5\"\22\2\u00af\u00ae"+ - "\3\2\2\2\u00af\u00b0\3\2\2\2\u00b0\u00b1\3\2\2\2\u00b1\u00b2\7\5\2\2\u00b2"+ - "\31\3\2\2\2\u00b3\u00b8\5\34\17\2\u00b4\u00b5\7\f\2\2\u00b5\u00b7\5\34"+ - "\17\2\u00b6\u00b4\3\2\2\2\u00b7\u00ba\3\2\2\2\u00b8\u00b6\3\2\2\2\u00b8"+ - "\u00b9\3\2\2\2\u00b9\33\3\2\2\2\u00ba\u00b8\3\2\2\2\u00bb\u00bc\5\20\t"+ - "\2\u00bc\u00bd\7`\2\2\u00bd\u00c0\3\2\2\2\u00be\u00c0\7R\2\2\u00bf\u00bb"+ - "\3\2\2\2\u00bf\u00be\3\2\2\2\u00c0\35\3\2\2\2\u00c1\u00c2\7*\2\2\u00c2"+ - "\u00c3\7+\2\2\u00c3\u00c4\3\2\2\2\u00c4\u00c5\7\b\2\2\u00c5\u00ca\7W\2"+ - "\2\u00c6\u00c7\7\f\2\2\u00c7\u00c9\7W\2\2\u00c8\u00c6\3\2\2\2\u00c9\u00cc"+ - "\3\2\2\2\u00ca\u00c8\3\2\2\2\u00ca\u00cb\3\2\2\2\u00cb\u00cd\3\2\2\2\u00cc"+ - "\u00ca\3\2\2\2\u00cd\u00f3\7\t\2\2\u00ce\u00cf\7*\2\2\u00cf\u00d0\7,\2"+ - "\2\u00d0\u00d1\3\2\2\2\u00d1\u00d2\7\b\2\2\u00d2\u00d3\7W\2\2\u00d3\u00f3"+ - "\7\t\2\2\u00d4\u00d5\7*\2\2\u00d5\u00d6\7-\2\2\u00d6\u00d7\3\2\2\2\u00d7"+ - "\u00d8\7\b\2\2\u00d8\u00d9\7`\2\2\u00d9\u00f3\7\t\2\2\u00da\u00db\7*\2"+ - "\2\u00db\u00dc\7.\2\2\u00dc\u00dd\3\2\2\2\u00dd\u00de\7\b\2\2\u00de\u00df"+ - "\7U\2\2\u00df\u00f3\7\t\2\2\u00e0\u00e1\7*\2\2\u00e1\u00e2\7/\2\2\u00e2"+ - "\u00e3\3\2\2\2\u00e3\u00e4\7\b\2\2\u00e4\u00e5\7`\2\2\u00e5\u00f3\7\t"+ - "\2\2\u00e6\u00e7\7*\2\2\u00e7\u00e8\7\60\2\2\u00e8\u00e9\3\2\2\2\u00e9"+ - "\u00ea\7\b\2\2\u00ea\u00eb\7`\2\2\u00eb\u00f3\7\t\2\2\u00ec\u00ed\7*\2"+ - "\2\u00ed\u00ee\7\61\2\2\u00ee\u00ef\3\2\2\2\u00ef\u00f0\7\b\2\2\u00f0"+ - "\u00f1\7`\2\2\u00f1\u00f3\7\t\2\2\u00f2\u00c1\3\2\2\2\u00f2\u00ce\3\2"+ - "\2\2\u00f2\u00d4\3\2\2\2\u00f2\u00da\3\2\2\2\u00f2\u00e0\3\2\2\2\u00f2"+ - "\u00e6\3\2\2\2\u00f2\u00ec\3\2\2\2\u00f3\37\3\2\2\2\u00f4\u0115\7\62\2"+ - "\2\u00f5\u0115\7\63\2\2\u00f6\u0115\7\64\2\2\u00f7\u00f8\7\65\2\2\u00f8"+ - "\u00f9\7\b\2\2\u00f9\u00fa\7W\2\2\u00fa\u0115\7\t\2\2\u00fb\u00ff\7\66"+ - "\2\2\u00fc\u00fd\7\b\2\2\u00fd\u00fe\7`\2\2\u00fe\u0100\7\t\2\2\u00ff"+ - "\u00fc\3\2\2\2\u00ff\u0100\3\2\2\2\u0100\u0115\3\2\2\2\u0101\u0115\7\67"+ - "\2\2\u0102\u0115\78\2\2\u0103\u0107\79\2\2\u0104\u0105\7\b\2\2\u0105\u0106"+ - "\7`\2\2\u0106\u0108\7\t\2\2\u0107\u0104\3\2\2\2\u0107\u0108\3\2\2\2\u0108"+ - "\u0115\3\2\2\2\u0109\u010a\7+\2\2\u010a\u010b\7\b\2\2\u010b\u0110\7W\2"+ - "\2\u010c\u010d\7\f\2\2\u010d\u010f\7W\2\2\u010e\u010c\3\2\2\2\u010f\u0112"+ - "\3\2\2\2\u0110\u010e\3\2\2\2\u0110\u0111\3\2\2\2\u0111\u0113\3\2\2\2\u0112"+ - "\u0110\3\2\2\2\u0113\u0115\7\t\2\2\u0114\u00f4\3\2\2\2\u0114\u00f5\3\2"+ - "\2\2\u0114\u00f6\3\2\2\2\u0114\u00f7\3\2\2\2\u0114\u00fb\3\2\2\2\u0114"+ - "\u0101\3\2\2\2\u0114\u0102\3\2\2\2\u0114\u0103\3\2\2\2\u0114\u0109\3\2"+ - "\2\2\u0115!\3\2\2\2\u0116\u0118\5$\23\2\u0117\u0116\3\2\2\2\u0118\u0119"+ - "\3\2\2\2\u0119\u0117\3\2\2\2\u0119\u011a\3\2\2\2\u011a#\3\2\2\2\u011b"+ - "\u011c\5\22\n\2\u011c\u011d\7\n\2\2\u011d\u0170\3\2\2\2\u011e\u0120\7"+ - "\4\2\2\u011f\u0121\5\"\22\2\u0120\u011f\3\2\2\2\u0120\u0121\3\2\2\2\u0121"+ - "\u0122\3\2\2\2\u0122\u0170\7\5\2\2\u0123\u0124\5> \2\u0124\u0125\7\n\2"+ - "\2\u0125\u0170\3\2\2\2\u0126\u0127\7:\2\2\u0127\u0128\7\b\2\2\u0128\u0129"+ - "\5> \2\u0129\u012a\7\t\2\2\u012a\u012d\5$\23\2\u012b\u012c\7;\2\2\u012c"+ - "\u012e\5$\23\2\u012d\u012b\3\2\2\2\u012d\u012e\3\2\2\2\u012e\u0170\3\2"+ - "\2\2\u012f\u0131\5 \21\2\u0130\u012f\3\2\2\2\u0131\u0134\3\2\2\2\u0132"+ - "\u0130\3\2\2\2\u0132\u0133\3\2\2\2\u0133\u0135\3\2\2\2\u0134\u0132\3\2"+ - "\2\2\u0135\u0136\7<\2\2\u0136\u0137\7\b\2\2\u0137\u0138\5> \2\u0138\u0139"+ - "\7\t\2\2\u0139\u013a\5$\23\2\u013a\u0170\3\2\2\2\u013b\u013d\5 \21\2\u013c"+ - "\u013b\3\2\2\2\u013d\u0140\3\2\2\2\u013e\u013c\3\2\2\2\u013e\u013f\3\2"+ - "\2\2\u013f\u0141\3\2\2\2\u0140\u013e\3\2\2\2\u0141\u0142\7=\2\2\u0142"+ - "\u0143\5$\23\2\u0143\u0144\7<\2\2\u0144\u0145\7\b\2\2\u0145\u0146\5> "+ - "\2\u0146\u0147\7\t\2\2\u0147\u0148\7\n\2\2\u0148\u0170\3\2\2\2\u0149\u014b"+ - "\5 \21\2\u014a\u0149\3\2\2\2\u014b\u014e\3\2\2\2\u014c\u014a\3\2\2\2\u014c"+ - "\u014d\3\2\2\2\u014d\u014f\3\2\2\2\u014e\u014c\3\2\2\2\u014f\u0150\7>"+ - "\2\2\u0150\u0151\7\b\2\2\u0151\u0152\5*\26\2\u0152\u0153\7\t\2\2\u0153"+ - "\u0154\5$\23\2\u0154\u0170\3\2\2\2\u0155\u0156\7?\2\2\u0156\u0157\7\b"+ - "\2\2\u0157\u0158\5> \2\u0158\u0159\7\t\2\2\u0159\u015a\7\4\2\2\u015a\u015b"+ - "\5&\24\2\u015b\u015c\7\5\2\2\u015c\u0170\3\2\2\2\u015d\u015f\7@\2\2\u015e"+ - "\u0160\5> \2\u015f\u015e\3\2\2\2\u015f\u0160\3\2\2\2\u0160\u0161\3\2\2"+ - "\2\u0161\u0170\7\n\2\2\u0162\u0163\7A\2\2\u0163\u0170\7\n\2\2\u0164\u0165"+ - "\7B\2\2\u0165\u0170\7\n\2\2\u0166\u0168\7C\2\2\u0167\u0169\5F$\2\u0168"+ - "\u0167\3\2\2\2\u0168\u0169\3\2\2\2\u0169\u016a\3\2\2\2\u016a\u016b\7\4"+ - "\2\2\u016b\u016c\5J&\2\u016c\u016d\7w\2\2\u016d\u0170\3\2\2\2\u016e\u0170"+ - "\5D#\2\u016f\u011b\3\2\2\2\u016f\u011e\3\2\2\2\u016f\u0123\3\2\2\2\u016f"+ - "\u0126\3\2\2\2\u016f\u0132\3\2\2\2\u016f\u013e\3\2\2\2\u016f\u014c\3\2"+ - "\2\2\u016f\u0155\3\2\2\2\u016f\u015d\3\2\2\2\u016f\u0162\3\2\2\2\u016f"+ - "\u0164\3\2\2\2\u016f\u0166\3\2\2\2\u016f\u016e\3\2\2\2\u0170%\3\2\2\2"+ - "\u0171\u0173\5(\25\2\u0172\u0171\3\2\2\2\u0173\u0174\3\2\2\2\u0174\u0172"+ - "\3\2\2\2\u0174\u0175\3\2\2\2\u0175\u017b\3\2\2\2\u0176\u0177\7D\2\2\u0177"+ - "\u0179\7\13\2\2\u0178\u017a\5\"\22\2\u0179\u0178\3\2\2\2\u0179\u017a\3"+ - "\2\2\2\u017a\u017c\3\2\2\2\u017b\u0176\3\2\2\2\u017b\u017c\3\2\2\2\u017c"+ - "\'\3\2\2\2\u017d\u017e\7E\2\2\u017e\u017f\5@!\2\u017f\u0181\7\13\2\2\u0180"+ - "\u0182\5\"\22\2\u0181\u0180\3\2\2\2\u0181\u0182\3\2\2\2\u0182)\3\2\2\2"+ - "\u0183\u0184\5,\27\2\u0184\u0185\7\n\2\2\u0185\u0186\5> \2\u0186\u0188"+ - "\7\n\2\2\u0187\u0189\5> \2\u0188\u0187\3\2\2\2\u0188\u0189\3\2\2\2\u0189"+ - "\u0194\3\2\2\2\u018a\u018c\5\20\t\2\u018b\u018a\3\2\2\2\u018b\u018c\3"+ - "\2\2\2\u018c\u018d\3\2\2\2\u018d\u018e\7`\2\2\u018e\u018f\7\13\2\2\u018f"+ - "\u0190\5@!\2\u0190\u0191\7\r\2\2\u0191\u0192\5@!\2\u0192\u0194\3\2\2\2"+ - "\u0193\u0183\3\2\2\2\u0193\u018b\3\2\2\2\u0194+\3\2\2\2\u0195\u0197\5"+ - "\22\n\2\u0196\u0195\3\2\2\2\u0196\u0197\3\2\2\2\u0197\u019a\3\2\2\2\u0198"+ - "\u019a\5> \2\u0199\u0196\3\2\2\2\u0199\u0198\3\2\2\2\u019a-\3\2\2\2\u019b"+ - "\u019c\b\30\1\2\u019c\u019d\7\b\2\2\u019d\u019e\5.\30\2\u019e\u019f\7"+ - "\t\2\2\u019f\u01ab\3\2\2\2\u01a0\u01ab\7R\2\2\u01a1\u01a3\7Q\2\2\u01a2"+ - "\u01a4\7R\2\2\u01a3\u01a2\3\2\2\2\u01a3\u01a4\3\2\2\2\u01a4\u01ab\3\2"+ - "\2\2\u01a5\u01ab\5\62\32\2\u01a6\u01ab\5\60\31\2\u01a7\u01ab\58\35\2\u01a8"+ - "\u01ab\5\66\34\2\u01a9\u01ab\7\3\2\2\u01aa\u019b\3\2\2\2\u01aa\u01a0\3"+ - "\2\2\2\u01aa\u01a1\3\2\2\2\u01aa\u01a5\3\2\2\2\u01aa\u01a6\3\2\2\2\u01aa"+ - "\u01a7\3\2\2\2\u01aa\u01a8\3\2\2\2\u01aa\u01a9\3\2\2\2\u01ab\u01b9\3\2"+ - "\2\2\u01ac\u01ad\f\n\2\2\u01ad\u01b8\7\23\2\2\u01ae\u01af\f\t\2\2\u01af"+ - "\u01b1\7\6\2\2\u01b0\u01b2\5@!\2\u01b1\u01b0\3\2\2\2\u01b1\u01b2\3\2\2"+ - "\2\u01b2\u01b3\3\2\2\2\u01b3\u01b8\7\7\2\2\u01b4\u01b5\f\b\2\2\u01b5\u01b6"+ - "\7\b\2\2\u01b6\u01b8\7\t\2\2\u01b7\u01ac\3\2\2\2\u01b7\u01ae\3\2\2\2\u01b7"+ - "\u01b4\3\2\2\2\u01b8\u01bb\3\2\2\2\u01b9\u01b7\3\2\2\2\u01b9\u01ba\3\2"+ - "\2\2\u01ba/\3\2\2\2\u01bb\u01b9\3\2\2\2\u01bc\u01bd\7F\2\2\u01bd\u01be"+ - "\7`\2\2\u01be\61\3\2\2\2\u01bf\u01c1\7F\2\2\u01c0\u01c2\7`\2\2\u01c1\u01c0"+ - "\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2\u01c3\3\2\2\2\u01c3\u01c5\7\4\2\2\u01c4"+ - "\u01c6\5\64\33\2\u01c5\u01c4\3\2\2\2\u01c6\u01c7\3\2\2\2\u01c7\u01c5\3"+ - "\2\2\2\u01c7\u01c8\3\2\2\2\u01c8\u01c9\3\2\2\2\u01c9\u01ca\7\5\2\2\u01ca"+ - "\63\3\2\2\2\u01cb\u01cc\5\22\n\2\u01cc\u01cd\7\n\2\2\u01cd\65\3\2\2\2"+ - "\u01ce\u01cf\7G\2\2\u01cf\u01d0\7`\2\2\u01d0\67\3\2\2\2\u01d1\u01d3\7"+ - "G\2\2\u01d2\u01d4\7`\2\2\u01d3\u01d2\3\2\2\2\u01d3\u01d4\3\2\2\2\u01d4"+ - "\u01d5\3\2\2\2\u01d5\u01d6\7\4\2\2\u01d6\u01d7\5:\36\2\u01d7\u01d8\7\5"+ - "\2\2\u01d89\3\2\2\2\u01d9\u01da\b\36\1\2\u01da\u01db\5<\37\2\u01db\u01e1"+ - "\3\2\2\2\u01dc\u01dd\f\3\2\2\u01dd\u01de\7\f\2\2\u01de\u01e0\5<\37\2\u01df"+ - "\u01dc\3\2\2\2\u01e0\u01e3\3\2\2\2\u01e1\u01df\3\2\2\2\u01e1\u01e2\3\2"+ - "\2\2\u01e2;\3\2\2\2\u01e3\u01e1\3\2\2\2\u01e4\u01e7\7`\2\2\u01e5\u01e6"+ - "\7&\2\2\u01e6\u01e8\5@!\2\u01e7\u01e5\3\2\2\2\u01e7\u01e8\3\2\2\2\u01e8"+ - "=\3\2\2\2\u01e9\u01ea\b \1\2\u01ea\u01eb\5@!\2\u01eb\u01f1\3\2\2\2\u01ec"+ - "\u01ed\f\3\2\2\u01ed\u01ee\7\f\2\2\u01ee\u01f0\5@!\2\u01ef\u01ec\3\2\2"+ - "\2\u01f0\u01f3\3\2\2\2\u01f1\u01ef\3\2\2\2\u01f1\u01f2\3\2\2\2\u01f2?"+ - "\3\2\2\2\u01f3\u01f1\3\2\2\2\u01f4\u01f5\b!\1\2\u01f5\u01f6\7\b\2\2\u01f6"+ - "\u01f7\5> \2\u01f7\u01f8\7\t\2\2\u01f8\u022b\3\2\2\2\u01f9\u01fa\7H\2"+ - "\2\u01fa\u01fd\7\b\2\2\u01fb\u01fe\5@!\2\u01fc\u01fe\5.\30\2\u01fd\u01fb"+ - "\3\2\2\2\u01fd\u01fc\3\2\2\2\u01fe\u01ff\3\2\2\2\u01ff\u0200\7\t\2\2\u0200"+ - "\u022b\3\2\2\2\u0201\u0202\7I\2\2\u0202\u0205\7\b\2\2\u0203\u0206\5@!"+ - "\2\u0204\u0206\5.\30\2\u0205\u0203\3\2\2\2\u0205\u0204\3\2\2\2\u0206\u0207"+ - "\3\2\2\2\u0207\u0208\7\t\2\2\u0208\u022b\3\2\2\2\u0209\u020a\7\b\2\2\u020a"+ - "\u020b\5.\30\2\u020b\u020c\7\t\2\2\u020c\u020d\5@!\32\u020d\u022b\3\2"+ - "\2\2\u020e\u020f\t\2\2\2\u020f\u022b\5@!\31\u0210\u0211\7\23\2\2\u0211"+ - "\u022b\5@!\27\u0212\u0213\t\3\2\2\u0213\u022b\5@!\26\u0214\u0215\t\4\2"+ - "\2\u0215\u022b\5@!\22\u0216\u0217\7\4\2\2\u0217\u021c\5@!\2\u0218\u0219"+ - "\7\f\2\2\u0219\u021b\5@!\2\u021a\u0218\3\2\2\2\u021b\u021e\3\2\2\2\u021c"+ - "\u021a\3\2\2\2\u021c\u021d\3\2\2\2\u021d\u021f\3\2\2\2\u021e\u021c\3\2"+ - "\2\2\u021f\u0220\7\5\2\2\u0220\u022b\3\2\2\2\u0221\u022b\7`\2\2\u0222"+ - "\u022b\7W\2\2\u0223\u0225\7U\2\2\u0224\u0223\3\2\2\2\u0225\u0226\3\2\2"+ - "\2\u0226\u0224\3\2\2\2\u0226\u0227\3\2\2\2\u0227\u022b\3\2\2\2\u0228\u022b"+ - "\7V\2\2\u0229\u022b\7S\2\2\u022a\u01f4\3\2\2\2\u022a\u01f9\3\2\2\2\u022a"+ - "\u0201\3\2\2\2\u022a\u0209\3\2\2\2\u022a\u020e\3\2\2\2\u022a\u0210\3\2"+ - "\2\2\u022a\u0212\3\2\2\2\u022a\u0214\3\2\2\2\u022a\u0216\3\2\2\2\u022a"+ - "\u0221\3\2\2\2\u022a\u0222\3\2\2\2\u022a\u0224\3\2\2\2\u022a\u0228\3\2"+ - "\2\2\u022a\u0229\3\2\2\2\u022b\u0268\3\2\2\2\u022c\u022d\f\25\2\2\u022d"+ - "\u022e\t\5\2\2\u022e\u0267\5@!\26\u022f\u0230\f\24\2\2\u0230\u0231\t\6"+ - "\2\2\u0231\u0267\5@!\25\u0232\u0233\f\23\2\2\u0233\u0234\t\7\2\2\u0234"+ - "\u0267\5@!\24\u0235\u0236\f\21\2\2\u0236\u0237\t\b\2\2\u0237\u0267\5@"+ - "!\22\u0238\u0239\f\20\2\2\u0239\u023a\7\30\2\2\u023a\u0267\5@!\21\u023b"+ - "\u023c\f\17\2\2\u023c\u023d\7\32\2\2\u023d\u0267\5@!\20\u023e\u023f\f"+ - "\16\2\2\u023f\u0240\7\33\2\2\u0240\u0267\5@!\17\u0241\u0242\f\r\2\2\u0242"+ - "\u0243\7$\2\2\u0243\u0267\5@!\16\u0244\u0245\f\f\2\2\u0245\u0246\7%\2"+ - "\2\u0246\u0267\5@!\r\u0247\u0248\f\13\2\2\u0248\u0249\7\16\2\2\u0249\u024a"+ - "\5@!\2\u024a\u024b\7\13\2\2\u024b\u024c\5@!\f\u024c\u0267\3\2\2\2\u024d"+ - "\u024e\f\n\2\2\u024e\u024f\7&\2\2\u024f\u0267\5@!\n\u0250\u0251\f\t\2"+ - "\2\u0251\u0252\7\'\2\2\u0252\u0267\5@!\t\u0253\u0254\f \2\2\u0254\u0255"+ - "\7\17\2\2\u0255\u0267\7`\2\2\u0256\u0257\f\37\2\2\u0257\u0258\7\20\2\2"+ - "\u0258\u0267\7`\2\2\u0259\u025a\f\36\2\2\u025a\u025c\7\b\2\2\u025b\u025d"+ - "\5B\"\2\u025c\u025b\3\2\2\2\u025c\u025d\3\2\2\2\u025d\u025e\3\2\2\2\u025e"+ - "\u0267\7\t\2\2\u025f\u0260\f\33\2\2\u0260\u0261\7\6\2\2\u0261\u0262\5"+ - "> \2\u0262\u0263\7\7\2\2\u0263\u0267\3\2\2\2\u0264\u0265\f\30\2\2\u0265"+ - "\u0267\t\2\2\2\u0266\u022c\3\2\2\2\u0266\u022f\3\2\2\2\u0266\u0232\3\2"+ - "\2\2\u0266\u0235\3\2\2\2\u0266\u0238\3\2\2\2\u0266\u023b\3\2\2\2\u0266"+ - "\u023e\3\2\2\2\u0266\u0241\3\2\2\2\u0266\u0244\3\2\2\2\u0266\u0247\3\2"+ - "\2\2\u0266\u024d\3\2\2\2\u0266\u0250\3\2\2\2\u0266\u0253\3\2\2\2\u0266"+ - "\u0256\3\2\2\2\u0266\u0259\3\2\2\2\u0266\u025f\3\2\2\2\u0266\u0264\3\2"+ - "\2\2\u0267\u026a\3\2\2\2\u0268\u0266\3\2\2\2\u0268\u0269\3\2\2\2\u0269"+ - "A\3\2\2\2\u026a\u0268\3\2\2\2\u026b\u0270\5@!\2\u026c\u026d\7\f\2\2\u026d"+ - "\u026f\5@!\2\u026e\u026c\3\2\2\2\u026f\u0272\3\2\2\2\u0270\u026e\3\2\2"+ - "\2\u0270\u0271\3\2\2\2\u0271C\3\2\2\2\u0272\u0270\3\2\2\2\u0273\u0275"+ - "\7J\2\2\u0274\u0276\5F$\2\u0275\u0274\3\2\2\2\u0275\u0276\3\2\2\2\u0276"+ - "\u0277\3\2\2\2\u0277\u0278\7T\2\2\u0278E\3\2\2\2\u0279\u027a\7\b\2\2\u027a"+ - "\u027f\5H%\2\u027b\u027c\7\f\2\2\u027c\u027e\5H%\2\u027d\u027b\3\2\2\2"+ - "\u027e\u0281\3\2\2\2\u027f\u027d\3\2\2\2\u027f\u0280\3\2\2\2\u0280\u0282"+ - "\3\2\2\2\u0281\u027f\3\2\2\2\u0282\u0283\7\t\2\2\u0283G\3\2\2\2\u0284"+ - "\u0285\7K\2\2\u0285\u0294\7U\2\2\u0286\u0287\7L\2\2\u0287\u0294\7`\2\2"+ - "\u0288\u0289\7M\2\2\u0289\u0294\7U\2\2\u028a\u028b\7N\2\2\u028b\u0294"+ - "\5@!\2\u028c\u028d\7O\2\2\u028d\u0294\5@!\2\u028e\u0291\7,\2\2\u028f\u0292"+ - "\7\67\2\2\u0290\u0292\5@!\2\u0291\u028f\3\2\2\2\u0291\u0290\3\2\2\2\u0292"+ - "\u0294\3\2\2\2\u0293\u0284\3\2\2\2\u0293\u0286\3\2\2\2\u0293\u0288\3\2"+ - "\2\2\u0293\u028a\3\2\2\2\u0293\u028c\3\2\2\2\u0293\u028e\3\2\2\2\u0294"+ - "I\3\2\2\2\u0295\u0297\5L\'\2\u0296\u0295\3\2\2\2\u0297\u029a\3\2\2\2\u0298"+ - "\u0296\3\2\2\2\u0298\u0299\3\2\2\2\u0299K\3\2\2\2\u029a\u0298\3\2\2\2"+ - "\u029b\u029f\5N(\2\u029c\u029f\5P)\2\u029d\u029f\5R*\2\u029e\u029b\3\2"+ - "\2\2\u029e\u029c\3\2\2\2\u029e\u029d\3\2\2\2\u029fM\3\2\2\2\u02a0\u02a1"+ - "\7\u0084\2\2\u02a1\u02a5\7g\2\2\u02a2\u02a3\7\u0083\2\2\u02a3\u02a5\7"+ - "g\2\2\u02a4\u02a0\3\2\2\2\u02a4\u02a2\3\2\2\2\u02a5O\3\2\2\2\u02a6\u02a8"+ - "\7e\2\2\u02a7\u02a9\5T+\2\u02a8\u02a7\3\2\2\2\u02a8\u02a9\3\2\2\2\u02a9"+ - "Q\3\2\2\2\u02aa\u02ab\7d\2\2\u02ab\u02b0\5V,\2\u02ac\u02ad\7h\2\2\u02ad"+ - "\u02af\5V,\2\u02ae\u02ac\3\2\2\2\u02af\u02b2\3\2\2\2\u02b0\u02ae\3\2\2"+ - "\2\u02b0\u02b1\3\2\2\2\u02b1S\3\2\2\2\u02b2\u02b0\3\2\2\2\u02b3\u02cb"+ - "\5V,\2\u02b4\u02b5\7f\2\2\u02b5\u02cb\5V,\2\u02b6\u02b7\5V,\2\u02b7\u02b8"+ - "\7h\2\2\u02b8\u02b9\7\u0084\2\2\u02b9\u02cb\3\2\2\2\u02ba\u02bb\7i\2\2"+ - "\u02bb\u02bc\5V,\2\u02bc\u02bd\7j\2\2\u02bd\u02be\7h\2\2\u02be\u02bf\7"+ - "\u0084\2\2\u02bf\u02cb\3\2\2\2\u02c0\u02c1\7i\2\2\u02c1\u02c2\5V,\2\u02c2"+ - "\u02c3\7h\2\2\u02c3\u02c4\7\u0084\2\2\u02c4\u02c5\7j\2\2\u02c5\u02cb\3"+ - "\2\2\2\u02c6\u02c7\7i\2\2\u02c7\u02c8\5V,\2\u02c8\u02c9\7j\2\2\u02c9\u02cb"+ - "\3\2\2\2\u02ca\u02b3\3\2\2\2\u02ca\u02b4\3\2\2\2\u02ca\u02b6\3\2\2\2\u02ca"+ - "\u02ba\3\2\2\2\u02ca\u02c0\3\2\2\2\u02ca\u02c6\3\2\2\2\u02cbU\3\2\2\2"+ - "\u02cc\u02cd\b,\1\2\u02cd\u02ce\7k\2\2\u02ce\u02cf\5V,\2\u02cf\u02d0\7"+ - "l\2\2\u02d0\u02db\3\2\2\2\u02d1\u02d2\t\t\2\2\u02d2\u02db\5V,\n\u02d3"+ - "\u02db\7\u0084\2\2\u02d4\u02db\7\u0082\2\2\u02d5\u02d6\7v\2\2\u02d6\u02d7"+ - "\7\u0084\2\2\u02d7\u02db\7w\2\2\u02d8\u02db\7x\2\2\u02d9\u02db\7\u0081"+ - "\2\2\u02da\u02cc\3\2\2\2\u02da\u02d1\3\2\2\2\u02da\u02d3\3\2\2\2\u02da"+ - "\u02d4\3\2\2\2\u02da\u02d5\3\2\2\2\u02da\u02d8\3\2\2\2\u02da\u02d9\3\2"+ - "\2\2\u02db\u02ea\3\2\2\2\u02dc\u02dd\f\f\2\2\u02dd\u02de\7m\2\2\u02de"+ - "\u02e9\5V,\r\u02df\u02e0\f\13\2\2\u02e0\u02e1\t\n\2\2\u02e1\u02e9\5V,"+ - "\f\u02e2\u02e3\f\t\2\2\u02e3\u02e4\t\13\2\2\u02e4\u02e9\5V,\n\u02e5\u02e6"+ - "\f\b\2\2\u02e6\u02e7\t\f\2\2\u02e7\u02e9\5V,\t\u02e8\u02dc\3\2\2\2\u02e8"+ - "\u02df\3\2\2\2\u02e8\u02e2\3\2\2\2\u02e8\u02e5\3\2\2\2\u02e9\u02ec\3\2"+ - "\2\2\u02ea\u02e8\3\2\2\2\u02ea\u02eb\3\2\2\2\u02ebW\3\2\2\2\u02ec\u02ea"+ - "\3\2\2\2Gafz\u0084\u008b\u0099\u009f\u00a4\u00aa\u00af\u00b8\u00bf\u00ca"+ - "\u00f2\u00ff\u0107\u0110\u0114\u0119\u0120\u012d\u0132\u013e\u014c\u015f"+ - "\u0168\u016f\u0174\u0179\u017b\u0181\u0188\u018b\u0193\u0196\u0199\u01a3"+ - "\u01aa\u01b1\u01b7\u01b9\u01c1\u01c7\u01d3\u01e1\u01e7\u01f1\u01fd\u0205"+ - "\u021c\u0226\u022a\u025c\u0266\u0268\u0270\u0275\u027f\u0291\u0293\u0298"+ - "\u029e\u02a4\u02a8\u02b0\u02ca\u02da\u02e8\u02ea"; + "8:<>@BDFHJLNPRTV\2\16\4\2WW``\3\2\26\27\5\2\21\22\30\31PP\4\2 ##\3\2"+ + "\34\35\3\2\23\25\3\2\21\22\3\2\36#\3\2ps\3\2no\3\2tu\3\2pq\2\u0355\2X"+ + "\3\2\2\2\4[\3\2\2\2\6a\3\2\2\2\bf\3\2\2\2\nh\3\2\2\2\fz\3\2\2\2\16|\3"+ + "\2\2\2\20\u0084\3\2\2\2\22\u008e\3\2\2\2\24\u0091\3\2\2\2\26\u00a4\3\2"+ + "\2\2\30\u00a6\3\2\2\2\32\u00b3\3\2\2\2\34\u00bf\3\2\2\2\36\u00f2\3\2\2"+ + "\2 \u0114\3\2\2\2\"\u0117\3\2\2\2$\u016f\3\2\2\2&\u0172\3\2\2\2(\u017d"+ + "\3\2\2\2*\u0193\3\2\2\2,\u0199\3\2\2\2.\u01aa\3\2\2\2\60\u01bc\3\2\2\2"+ + "\62\u01bf\3\2\2\2\64\u01cb\3\2\2\2\66\u01ce\3\2\2\28\u01d1\3\2\2\2:\u01d9"+ + "\3\2\2\2<\u01e4\3\2\2\2>\u01e9\3\2\2\2@\u022a\3\2\2\2B\u026b\3\2\2\2D"+ + "\u0273\3\2\2\2F\u0279\3\2\2\2H\u0293\3\2\2\2J\u0298\3\2\2\2L\u029e\3\2"+ + "\2\2N\u02a4\3\2\2\2P\u02a6\3\2\2\2R\u02aa\3\2\2\2T\u02ca\3\2\2\2V\u02da"+ + "\3\2\2\2XY\5\6\4\2YZ\7\2\2\3Z\3\3\2\2\2[\\\5J&\2\\]\7\2\2\3]\5\3\2\2\2"+ + "^`\5\b\5\2_^\3\2\2\2`c\3\2\2\2a_\3\2\2\2ab\3\2\2\2b\7\3\2\2\2ca\3\2\2"+ + "\2dg\5\f\7\2eg\5\n\6\2fd\3\2\2\2fe\3\2\2\2g\t\3\2\2\2hi\7(\2\2ij\7U\2"+ + "\2j\13\3\2\2\2kl\5\22\n\2lm\7\n\2\2m{\3\2\2\2no\5\62\32\2op\7\n\2\2p{"+ + "\3\2\2\2qr\58\35\2rs\7\n\2\2s{\3\2\2\2t{\5\30\r\2u{\5D#\2v{\5\36\20\2"+ + "wx\5\16\b\2xy\7\n\2\2y{\3\2\2\2zk\3\2\2\2zn\3\2\2\2zq\3\2\2\2zt\3\2\2"+ + "\2zu\3\2\2\2zv\3\2\2\2zw\3\2\2\2{\r\3\2\2\2|}\7)\2\2}~\5.\30\2~\177\7"+ + "`\2\2\177\u0080\b\b\1\2\u0080\17\3\2\2\2\u0081\u0083\5 \21\2\u0082\u0081"+ + "\3\2\2\2\u0083\u0086\3\2\2\2\u0084\u0082\3\2\2\2\u0084\u0085\3\2\2\2\u0085"+ + "\u0087\3\2\2\2\u0086\u0084\3\2\2\2\u0087\u008b\5.\30\2\u0088\u008a\5 "+ + "\21\2\u0089\u0088\3\2\2\2\u008a\u008d\3\2\2\2\u008b\u0089\3\2\2\2\u008b"+ + "\u008c\3\2\2\2\u008c\21\3\2\2\2\u008d\u008b\3\2\2\2\u008e\u008f\5\20\t"+ + "\2\u008f\u0090\5\24\13\2\u0090\23\3\2\2\2\u0091\u0092\b\13\1\2\u0092\u0093"+ + "\5\26\f\2\u0093\u0099\3\2\2\2\u0094\u0095\f\3\2\2\u0095\u0096\7\f\2\2"+ + "\u0096\u0098\5\26\f\2\u0097\u0094\3\2\2\2\u0098\u009b\3\2\2\2\u0099\u0097"+ + "\3\2\2\2\u0099\u009a\3\2\2\2\u009a\25\3\2\2\2\u009b\u0099\3\2\2\2\u009c"+ + "\u009f\7`\2\2\u009d\u009e\7&\2\2\u009e\u00a0\5@!\2\u009f\u009d\3\2\2\2"+ + "\u009f\u00a0\3\2\2\2\u00a0\u00a5\3\2\2\2\u00a1\u00a2\7`\2\2\u00a2\u00a3"+ + "\7&\2\2\u00a3\u00a5\5D#\2\u00a4\u009c\3\2\2\2\u00a4\u00a1\3\2\2\2\u00a5"+ + "\27\3\2\2\2\u00a6\u00a7\5\20\t\2\u00a7\u00a8\7`\2\2\u00a8\u00aa\7\b\2"+ + "\2\u00a9\u00ab\5\32\16\2\u00aa\u00a9\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab"+ + "\u00ac\3\2\2\2\u00ac\u00ad\7\t\2\2\u00ad\u00af\7\4\2\2\u00ae\u00b0\5\""+ + "\22\2\u00af\u00ae\3\2\2\2\u00af\u00b0\3\2\2\2\u00b0\u00b1\3\2\2\2\u00b1"+ + "\u00b2\7\5\2\2\u00b2\31\3\2\2\2\u00b3\u00b8\5\34\17\2\u00b4\u00b5\7\f"+ + "\2\2\u00b5\u00b7\5\34\17\2\u00b6\u00b4\3\2\2\2\u00b7\u00ba\3\2\2\2\u00b8"+ + "\u00b6\3\2\2\2\u00b8\u00b9\3\2\2\2\u00b9\33\3\2\2\2\u00ba\u00b8\3\2\2"+ + "\2\u00bb\u00bc\5\20\t\2\u00bc\u00bd\7`\2\2\u00bd\u00c0\3\2\2\2\u00be\u00c0"+ + "\7R\2\2\u00bf\u00bb\3\2\2\2\u00bf\u00be\3\2\2\2\u00c0\35\3\2\2\2\u00c1"+ + "\u00c2\7*\2\2\u00c2\u00c3\7+\2\2\u00c3\u00c4\3\2\2\2\u00c4\u00c5\7\b\2"+ + "\2\u00c5\u00ca\7W\2\2\u00c6\u00c7\7\f\2\2\u00c7\u00c9\7W\2\2\u00c8\u00c6"+ + "\3\2\2\2\u00c9\u00cc\3\2\2\2\u00ca\u00c8\3\2\2\2\u00ca\u00cb\3\2\2\2\u00cb"+ + "\u00cd\3\2\2\2\u00cc\u00ca\3\2\2\2\u00cd\u00f3\7\t\2\2\u00ce\u00cf\7*"+ + "\2\2\u00cf\u00d0\7,\2\2\u00d0\u00d1\3\2\2\2\u00d1\u00d2\7\b\2\2\u00d2"+ + "\u00d3\7W\2\2\u00d3\u00f3\7\t\2\2\u00d4\u00d5\7*\2\2\u00d5\u00d6\7-\2"+ + "\2\u00d6\u00d7\3\2\2\2\u00d7\u00d8\7\b\2\2\u00d8\u00d9\7`\2\2\u00d9\u00f3"+ + "\7\t\2\2\u00da\u00db\7*\2\2\u00db\u00dc\7.\2\2\u00dc\u00dd\3\2\2\2\u00dd"+ + "\u00de\7\b\2\2\u00de\u00df\7U\2\2\u00df\u00f3\7\t\2\2\u00e0\u00e1\7*\2"+ + "\2\u00e1\u00e2\7/\2\2\u00e2\u00e3\3\2\2\2\u00e3\u00e4\7\b\2\2\u00e4\u00e5"+ + "\7`\2\2\u00e5\u00f3\7\t\2\2\u00e6\u00e7\7*\2\2\u00e7\u00e8\7\60\2\2\u00e8"+ + "\u00e9\3\2\2\2\u00e9\u00ea\7\b\2\2\u00ea\u00eb\7`\2\2\u00eb\u00f3\7\t"+ + "\2\2\u00ec\u00ed\7*\2\2\u00ed\u00ee\7\61\2\2\u00ee\u00ef\3\2\2\2\u00ef"+ + "\u00f0\7\b\2\2\u00f0\u00f1\7`\2\2\u00f1\u00f3\7\t\2\2\u00f2\u00c1\3\2"+ + "\2\2\u00f2\u00ce\3\2\2\2\u00f2\u00d4\3\2\2\2\u00f2\u00da\3\2\2\2\u00f2"+ + "\u00e0\3\2\2\2\u00f2\u00e6\3\2\2\2\u00f2\u00ec\3\2\2\2\u00f3\37\3\2\2"+ + "\2\u00f4\u0115\7\62\2\2\u00f5\u0115\7\63\2\2\u00f6\u0115\7\64\2\2\u00f7"+ + "\u00f8\7\65\2\2\u00f8\u00f9\7\b\2\2\u00f9\u00fa\7W\2\2\u00fa\u0115\7\t"+ + "\2\2\u00fb\u00ff\7\66\2\2\u00fc\u00fd\7\b\2\2\u00fd\u00fe\t\2\2\2\u00fe"+ + "\u0100\7\t\2\2\u00ff\u00fc\3\2\2\2\u00ff\u0100\3\2\2\2\u0100\u0115\3\2"+ + "\2\2\u0101\u0115\7\67\2\2\u0102\u0115\78\2\2\u0103\u0107\79\2\2\u0104"+ + "\u0105\7\b\2\2\u0105\u0106\7`\2\2\u0106\u0108\7\t\2\2\u0107\u0104\3\2"+ + "\2\2\u0107\u0108\3\2\2\2\u0108\u0115\3\2\2\2\u0109\u010a\7+\2\2\u010a"+ + "\u010b\7\b\2\2\u010b\u0110\7W\2\2\u010c\u010d\7\f\2\2\u010d\u010f\7W\2"+ + "\2\u010e\u010c\3\2\2\2\u010f\u0112\3\2\2\2\u0110\u010e\3\2\2\2\u0110\u0111"+ + "\3\2\2\2\u0111\u0113\3\2\2\2\u0112\u0110\3\2\2\2\u0113\u0115\7\t\2\2\u0114"+ + "\u00f4\3\2\2\2\u0114\u00f5\3\2\2\2\u0114\u00f6\3\2\2\2\u0114\u00f7\3\2"+ + "\2\2\u0114\u00fb\3\2\2\2\u0114\u0101\3\2\2\2\u0114\u0102\3\2\2\2\u0114"+ + "\u0103\3\2\2\2\u0114\u0109\3\2\2\2\u0115!\3\2\2\2\u0116\u0118\5$\23\2"+ + "\u0117\u0116\3\2\2\2\u0118\u0119\3\2\2\2\u0119\u0117\3\2\2\2\u0119\u011a"+ + "\3\2\2\2\u011a#\3\2\2\2\u011b\u011c\5\22\n\2\u011c\u011d\7\n\2\2\u011d"+ + "\u0170\3\2\2\2\u011e\u0120\7\4\2\2\u011f\u0121\5\"\22\2\u0120\u011f\3"+ + "\2\2\2\u0120\u0121\3\2\2\2\u0121\u0122\3\2\2\2\u0122\u0170\7\5\2\2\u0123"+ + "\u0124\5> \2\u0124\u0125\7\n\2\2\u0125\u0170\3\2\2\2\u0126\u0127\7:\2"+ + "\2\u0127\u0128\7\b\2\2\u0128\u0129\5> \2\u0129\u012a\7\t\2\2\u012a\u012d"+ + "\5$\23\2\u012b\u012c\7;\2\2\u012c\u012e\5$\23\2\u012d\u012b\3\2\2\2\u012d"+ + "\u012e\3\2\2\2\u012e\u0170\3\2\2\2\u012f\u0131\5 \21\2\u0130\u012f\3\2"+ + "\2\2\u0131\u0134\3\2\2\2\u0132\u0130\3\2\2\2\u0132\u0133\3\2\2\2\u0133"+ + "\u0135\3\2\2\2\u0134\u0132\3\2\2\2\u0135\u0136\7<\2\2\u0136\u0137\7\b"+ + "\2\2\u0137\u0138\5> \2\u0138\u0139\7\t\2\2\u0139\u013a\5$\23\2\u013a\u0170"+ + "\3\2\2\2\u013b\u013d\5 \21\2\u013c\u013b\3\2\2\2\u013d\u0140\3\2\2\2\u013e"+ + "\u013c\3\2\2\2\u013e\u013f\3\2\2\2\u013f\u0141\3\2\2\2\u0140\u013e\3\2"+ + "\2\2\u0141\u0142\7=\2\2\u0142\u0143\5$\23\2\u0143\u0144\7<\2\2\u0144\u0145"+ + "\7\b\2\2\u0145\u0146\5> \2\u0146\u0147\7\t\2\2\u0147\u0148\7\n\2\2\u0148"+ + "\u0170\3\2\2\2\u0149\u014b\5 \21\2\u014a\u0149\3\2\2\2\u014b\u014e\3\2"+ + "\2\2\u014c\u014a\3\2\2\2\u014c\u014d\3\2\2\2\u014d\u014f\3\2\2\2\u014e"+ + "\u014c\3\2\2\2\u014f\u0150\7>\2\2\u0150\u0151\7\b\2\2\u0151\u0152\5*\26"+ + "\2\u0152\u0153\7\t\2\2\u0153\u0154\5$\23\2\u0154\u0170\3\2\2\2\u0155\u0156"+ + "\7?\2\2\u0156\u0157\7\b\2\2\u0157\u0158\5> \2\u0158\u0159\7\t\2\2\u0159"+ + "\u015a\7\4\2\2\u015a\u015b\5&\24\2\u015b\u015c\7\5\2\2\u015c\u0170\3\2"+ + "\2\2\u015d\u015f\7@\2\2\u015e\u0160\5> \2\u015f\u015e\3\2\2\2\u015f\u0160"+ + "\3\2\2\2\u0160\u0161\3\2\2\2\u0161\u0170\7\n\2\2\u0162\u0163\7A\2\2\u0163"+ + "\u0170\7\n\2\2\u0164\u0165\7B\2\2\u0165\u0170\7\n\2\2\u0166\u0168\7C\2"+ + "\2\u0167\u0169\5F$\2\u0168\u0167\3\2\2\2\u0168\u0169\3\2\2\2\u0169\u016a"+ + "\3\2\2\2\u016a\u016b\7\4\2\2\u016b\u016c\5J&\2\u016c\u016d\7w\2\2\u016d"+ + "\u0170\3\2\2\2\u016e\u0170\5D#\2\u016f\u011b\3\2\2\2\u016f\u011e\3\2\2"+ + "\2\u016f\u0123\3\2\2\2\u016f\u0126\3\2\2\2\u016f\u0132\3\2\2\2\u016f\u013e"+ + "\3\2\2\2\u016f\u014c\3\2\2\2\u016f\u0155\3\2\2\2\u016f\u015d\3\2\2\2\u016f"+ + "\u0162\3\2\2\2\u016f\u0164\3\2\2\2\u016f\u0166\3\2\2\2\u016f\u016e\3\2"+ + "\2\2\u0170%\3\2\2\2\u0171\u0173\5(\25\2\u0172\u0171\3\2\2\2\u0173\u0174"+ + "\3\2\2\2\u0174\u0172\3\2\2\2\u0174\u0175\3\2\2\2\u0175\u017b\3\2\2\2\u0176"+ + "\u0177\7D\2\2\u0177\u0179\7\13\2\2\u0178\u017a\5\"\22\2\u0179\u0178\3"+ + "\2\2\2\u0179\u017a\3\2\2\2\u017a\u017c\3\2\2\2\u017b\u0176\3\2\2\2\u017b"+ + "\u017c\3\2\2\2\u017c\'\3\2\2\2\u017d\u017e\7E\2\2\u017e\u017f\5@!\2\u017f"+ + "\u0181\7\13\2\2\u0180\u0182\5\"\22\2\u0181\u0180\3\2\2\2\u0181\u0182\3"+ + "\2\2\2\u0182)\3\2\2\2\u0183\u0184\5,\27\2\u0184\u0185\7\n\2\2\u0185\u0186"+ + "\5> \2\u0186\u0188\7\n\2\2\u0187\u0189\5> \2\u0188\u0187\3\2\2\2\u0188"+ + "\u0189\3\2\2\2\u0189\u0194\3\2\2\2\u018a\u018c\5\20\t\2\u018b\u018a\3"+ + "\2\2\2\u018b\u018c\3\2\2\2\u018c\u018d\3\2\2\2\u018d\u018e\7`\2\2\u018e"+ + "\u018f\7\13\2\2\u018f\u0190\5@!\2\u0190\u0191\7\r\2\2\u0191\u0192\5@!"+ + "\2\u0192\u0194\3\2\2\2\u0193\u0183\3\2\2\2\u0193\u018b\3\2\2\2\u0194+"+ + "\3\2\2\2\u0195\u0197\5\22\n\2\u0196\u0195\3\2\2\2\u0196\u0197\3\2\2\2"+ + "\u0197\u019a\3\2\2\2\u0198\u019a\5> \2\u0199\u0196\3\2\2\2\u0199\u0198"+ + "\3\2\2\2\u019a-\3\2\2\2\u019b\u019c\b\30\1\2\u019c\u019d\7\b\2\2\u019d"+ + "\u019e\5.\30\2\u019e\u019f\7\t\2\2\u019f\u01ab\3\2\2\2\u01a0\u01ab\7R"+ + "\2\2\u01a1\u01a3\7Q\2\2\u01a2\u01a4\7R\2\2\u01a3\u01a2\3\2\2\2\u01a3\u01a4"+ + "\3\2\2\2\u01a4\u01ab\3\2\2\2\u01a5\u01ab\5\62\32\2\u01a6\u01ab\5\60\31"+ + "\2\u01a7\u01ab\58\35\2\u01a8\u01ab\5\66\34\2\u01a9\u01ab\7\3\2\2\u01aa"+ + "\u019b\3\2\2\2\u01aa\u01a0\3\2\2\2\u01aa\u01a1\3\2\2\2\u01aa\u01a5\3\2"+ + "\2\2\u01aa\u01a6\3\2\2\2\u01aa\u01a7\3\2\2\2\u01aa\u01a8\3\2\2\2\u01aa"+ + "\u01a9\3\2\2\2\u01ab\u01b9\3\2\2\2\u01ac\u01ad\f\n\2\2\u01ad\u01b8\7\23"+ + "\2\2\u01ae\u01af\f\t\2\2\u01af\u01b1\7\6\2\2\u01b0\u01b2\5@!\2\u01b1\u01b0"+ + "\3\2\2\2\u01b1\u01b2\3\2\2\2\u01b2\u01b3\3\2\2\2\u01b3\u01b8\7\7\2\2\u01b4"+ + "\u01b5\f\b\2\2\u01b5\u01b6\7\b\2\2\u01b6\u01b8\7\t\2\2\u01b7\u01ac\3\2"+ + "\2\2\u01b7\u01ae\3\2\2\2\u01b7\u01b4\3\2\2\2\u01b8\u01bb\3\2\2\2\u01b9"+ + "\u01b7\3\2\2\2\u01b9\u01ba\3\2\2\2\u01ba/\3\2\2\2\u01bb\u01b9\3\2\2\2"+ + "\u01bc\u01bd\7F\2\2\u01bd\u01be\7`\2\2\u01be\61\3\2\2\2\u01bf\u01c1\7"+ + "F\2\2\u01c0\u01c2\7`\2\2\u01c1\u01c0\3\2\2\2\u01c1\u01c2\3\2\2\2\u01c2"+ + "\u01c3\3\2\2\2\u01c3\u01c5\7\4\2\2\u01c4\u01c6\5\64\33\2\u01c5\u01c4\3"+ + "\2\2\2\u01c6\u01c7\3\2\2\2\u01c7\u01c5\3\2\2\2\u01c7\u01c8\3\2\2\2\u01c8"+ + "\u01c9\3\2\2\2\u01c9\u01ca\7\5\2\2\u01ca\63\3\2\2\2\u01cb\u01cc\5\22\n"+ + "\2\u01cc\u01cd\7\n\2\2\u01cd\65\3\2\2\2\u01ce\u01cf\7G\2\2\u01cf\u01d0"+ + "\7`\2\2\u01d0\67\3\2\2\2\u01d1\u01d3\7G\2\2\u01d2\u01d4\7`\2\2\u01d3\u01d2"+ + "\3\2\2\2\u01d3\u01d4\3\2\2\2\u01d4\u01d5\3\2\2\2\u01d5\u01d6\7\4\2\2\u01d6"+ + "\u01d7\5:\36\2\u01d7\u01d8\7\5\2\2\u01d89\3\2\2\2\u01d9\u01da\b\36\1\2"+ + "\u01da\u01db\5<\37\2\u01db\u01e1\3\2\2\2\u01dc\u01dd\f\3\2\2\u01dd\u01de"+ + "\7\f\2\2\u01de\u01e0\5<\37\2\u01df\u01dc\3\2\2\2\u01e0\u01e3\3\2\2\2\u01e1"+ + "\u01df\3\2\2\2\u01e1\u01e2\3\2\2\2\u01e2;\3\2\2\2\u01e3\u01e1\3\2\2\2"+ + "\u01e4\u01e7\7`\2\2\u01e5\u01e6\7&\2\2\u01e6\u01e8\5@!\2\u01e7\u01e5\3"+ + "\2\2\2\u01e7\u01e8\3\2\2\2\u01e8=\3\2\2\2\u01e9\u01ea\b \1\2\u01ea\u01eb"+ + "\5@!\2\u01eb\u01f1\3\2\2\2\u01ec\u01ed\f\3\2\2\u01ed\u01ee\7\f\2\2\u01ee"+ + "\u01f0\5@!\2\u01ef\u01ec\3\2\2\2\u01f0\u01f3\3\2\2\2\u01f1\u01ef\3\2\2"+ + "\2\u01f1\u01f2\3\2\2\2\u01f2?\3\2\2\2\u01f3\u01f1\3\2\2\2\u01f4\u01f5"+ + "\b!\1\2\u01f5\u01f6\7\b\2\2\u01f6\u01f7\5> \2\u01f7\u01f8\7\t\2\2\u01f8"+ + "\u022b\3\2\2\2\u01f9\u01fa\7H\2\2\u01fa\u01fd\7\b\2\2\u01fb\u01fe\5@!"+ + "\2\u01fc\u01fe\5.\30\2\u01fd\u01fb\3\2\2\2\u01fd\u01fc\3\2\2\2\u01fe\u01ff"+ + "\3\2\2\2\u01ff\u0200\7\t\2\2\u0200\u022b\3\2\2\2\u0201\u0202\7I\2\2\u0202"+ + "\u0205\7\b\2\2\u0203\u0206\5@!\2\u0204\u0206\5.\30\2\u0205\u0203\3\2\2"+ + "\2\u0205\u0204\3\2\2\2\u0206\u0207\3\2\2\2\u0207\u0208\7\t\2\2\u0208\u022b"+ + "\3\2\2\2\u0209\u020a\7\b\2\2\u020a\u020b\5.\30\2\u020b\u020c\7\t\2\2\u020c"+ + "\u020d\5@!\32\u020d\u022b\3\2\2\2\u020e\u020f\t\3\2\2\u020f\u022b\5@!"+ + "\31\u0210\u0211\7\23\2\2\u0211\u022b\5@!\27\u0212\u0213\t\4\2\2\u0213"+ + "\u022b\5@!\26\u0214\u0215\t\5\2\2\u0215\u022b\5@!\22\u0216\u0217\7\4\2"+ + "\2\u0217\u021c\5@!\2\u0218\u0219\7\f\2\2\u0219\u021b\5@!\2\u021a\u0218"+ + "\3\2\2\2\u021b\u021e\3\2\2\2\u021c\u021a\3\2\2\2\u021c\u021d\3\2\2\2\u021d"+ + "\u021f\3\2\2\2\u021e\u021c\3\2\2\2\u021f\u0220\7\5\2\2\u0220\u022b\3\2"+ + "\2\2\u0221\u022b\7`\2\2\u0222\u022b\7W\2\2\u0223\u0225\7U\2\2\u0224\u0223"+ + "\3\2\2\2\u0225\u0226\3\2\2\2\u0226\u0224\3\2\2\2\u0226\u0227\3\2\2\2\u0227"+ + "\u022b\3\2\2\2\u0228\u022b\7V\2\2\u0229\u022b\7S\2\2\u022a\u01f4\3\2\2"+ + "\2\u022a\u01f9\3\2\2\2\u022a\u0201\3\2\2\2\u022a\u0209\3\2\2\2\u022a\u020e"+ + "\3\2\2\2\u022a\u0210\3\2\2\2\u022a\u0212\3\2\2\2\u022a\u0214\3\2\2\2\u022a"+ + "\u0216\3\2\2\2\u022a\u0221\3\2\2\2\u022a\u0222\3\2\2\2\u022a\u0224\3\2"+ + "\2\2\u022a\u0228\3\2\2\2\u022a\u0229\3\2\2\2\u022b\u0268\3\2\2\2\u022c"+ + "\u022d\f\25\2\2\u022d\u022e\t\6\2\2\u022e\u0267\5@!\26\u022f\u0230\f\24"+ + "\2\2\u0230\u0231\t\7\2\2\u0231\u0267\5@!\25\u0232\u0233\f\23\2\2\u0233"+ + "\u0234\t\b\2\2\u0234\u0267\5@!\24\u0235\u0236\f\21\2\2\u0236\u0237\t\t"+ + "\2\2\u0237\u0267\5@!\22\u0238\u0239\f\20\2\2\u0239\u023a\7\30\2\2\u023a"+ + "\u0267\5@!\21\u023b\u023c\f\17\2\2\u023c\u023d\7\32\2\2\u023d\u0267\5"+ + "@!\20\u023e\u023f\f\16\2\2\u023f\u0240\7\33\2\2\u0240\u0267\5@!\17\u0241"+ + "\u0242\f\r\2\2\u0242\u0243\7$\2\2\u0243\u0267\5@!\16\u0244\u0245\f\f\2"+ + "\2\u0245\u0246\7%\2\2\u0246\u0267\5@!\r\u0247\u0248\f\13\2\2\u0248\u0249"+ + "\7\16\2\2\u0249\u024a\5@!\2\u024a\u024b\7\13\2\2\u024b\u024c\5@!\f\u024c"+ + "\u0267\3\2\2\2\u024d\u024e\f\n\2\2\u024e\u024f\7&\2\2\u024f\u0267\5@!"+ + "\n\u0250\u0251\f\t\2\2\u0251\u0252\7\'\2\2\u0252\u0267\5@!\t\u0253\u0254"+ + "\f \2\2\u0254\u0255\7\17\2\2\u0255\u0267\7`\2\2\u0256\u0257\f\37\2\2\u0257"+ + "\u0258\7\20\2\2\u0258\u0267\7`\2\2\u0259\u025a\f\36\2\2\u025a\u025c\7"+ + "\b\2\2\u025b\u025d\5B\"\2\u025c\u025b\3\2\2\2\u025c\u025d\3\2\2\2\u025d"+ + "\u025e\3\2\2\2\u025e\u0267\7\t\2\2\u025f\u0260\f\33\2\2\u0260\u0261\7"+ + "\6\2\2\u0261\u0262\5> \2\u0262\u0263\7\7\2\2\u0263\u0267\3\2\2\2\u0264"+ + "\u0265\f\30\2\2\u0265\u0267\t\3\2\2\u0266\u022c\3\2\2\2\u0266\u022f\3"+ + "\2\2\2\u0266\u0232\3\2\2\2\u0266\u0235\3\2\2\2\u0266\u0238\3\2\2\2\u0266"+ + "\u023b\3\2\2\2\u0266\u023e\3\2\2\2\u0266\u0241\3\2\2\2\u0266\u0244\3\2"+ + "\2\2\u0266\u0247\3\2\2\2\u0266\u024d\3\2\2\2\u0266\u0250\3\2\2\2\u0266"+ + "\u0253\3\2\2\2\u0266\u0256\3\2\2\2\u0266\u0259\3\2\2\2\u0266\u025f\3\2"+ + "\2\2\u0266\u0264\3\2\2\2\u0267\u026a\3\2\2\2\u0268\u0266\3\2\2\2\u0268"+ + "\u0269\3\2\2\2\u0269A\3\2\2\2\u026a\u0268\3\2\2\2\u026b\u0270\5@!\2\u026c"+ + "\u026d\7\f\2\2\u026d\u026f\5@!\2\u026e\u026c\3\2\2\2\u026f\u0272\3\2\2"+ + "\2\u0270\u026e\3\2\2\2\u0270\u0271\3\2\2\2\u0271C\3\2\2\2\u0272\u0270"+ + "\3\2\2\2\u0273\u0275\7J\2\2\u0274\u0276\5F$\2\u0275\u0274\3\2\2\2\u0275"+ + "\u0276\3\2\2\2\u0276\u0277\3\2\2\2\u0277\u0278\7T\2\2\u0278E\3\2\2\2\u0279"+ + "\u027a\7\b\2\2\u027a\u027f\5H%\2\u027b\u027c\7\f\2\2\u027c\u027e\5H%\2"+ + "\u027d\u027b\3\2\2\2\u027e\u0281\3\2\2\2\u027f\u027d\3\2\2\2\u027f\u0280"+ + "\3\2\2\2\u0280\u0282\3\2\2\2\u0281\u027f\3\2\2\2\u0282\u0283\7\t\2\2\u0283"+ + "G\3\2\2\2\u0284\u0285\7K\2\2\u0285\u0294\7U\2\2\u0286\u0287\7L\2\2\u0287"+ + "\u0294\7`\2\2\u0288\u0289\7M\2\2\u0289\u0294\7U\2\2\u028a\u028b\7N\2\2"+ + "\u028b\u0294\5@!\2\u028c\u028d\7O\2\2\u028d\u0294\5@!\2\u028e\u0291\7"+ + ",\2\2\u028f\u0292\7\67\2\2\u0290\u0292\5@!\2\u0291\u028f\3\2\2\2\u0291"+ + "\u0290\3\2\2\2\u0292\u0294\3\2\2\2\u0293\u0284\3\2\2\2\u0293\u0286\3\2"+ + "\2\2\u0293\u0288\3\2\2\2\u0293\u028a\3\2\2\2\u0293\u028c\3\2\2\2\u0293"+ + "\u028e\3\2\2\2\u0294I\3\2\2\2\u0295\u0297\5L\'\2\u0296\u0295\3\2\2\2\u0297"+ + "\u029a\3\2\2\2\u0298\u0296\3\2\2\2\u0298\u0299\3\2\2\2\u0299K\3\2\2\2"+ + "\u029a\u0298\3\2\2\2\u029b\u029f\5N(\2\u029c\u029f\5P)\2\u029d\u029f\5"+ + "R*\2\u029e\u029b\3\2\2\2\u029e\u029c\3\2\2\2\u029e\u029d\3\2\2\2\u029f"+ + "M\3\2\2\2\u02a0\u02a1\7\u0084\2\2\u02a1\u02a5\7g\2\2\u02a2\u02a3\7\u0083"+ + "\2\2\u02a3\u02a5\7g\2\2\u02a4\u02a0\3\2\2\2\u02a4\u02a2\3\2\2\2\u02a5"+ + "O\3\2\2\2\u02a6\u02a8\7e\2\2\u02a7\u02a9\5T+\2\u02a8\u02a7\3\2\2\2\u02a8"+ + "\u02a9\3\2\2\2\u02a9Q\3\2\2\2\u02aa\u02ab\7d\2\2\u02ab\u02b0\5V,\2\u02ac"+ + "\u02ad\7h\2\2\u02ad\u02af\5V,\2\u02ae\u02ac\3\2\2\2\u02af\u02b2\3\2\2"+ + "\2\u02b0\u02ae\3\2\2\2\u02b0\u02b1\3\2\2\2\u02b1S\3\2\2\2\u02b2\u02b0"+ + "\3\2\2\2\u02b3\u02cb\5V,\2\u02b4\u02b5\7f\2\2\u02b5\u02cb\5V,\2\u02b6"+ + "\u02b7\5V,\2\u02b7\u02b8\7h\2\2\u02b8\u02b9\7\u0084\2\2\u02b9\u02cb\3"+ + "\2\2\2\u02ba\u02bb\7i\2\2\u02bb\u02bc\5V,\2\u02bc\u02bd\7j\2\2\u02bd\u02be"+ + "\7h\2\2\u02be\u02bf\7\u0084\2\2\u02bf\u02cb\3\2\2\2\u02c0\u02c1\7i\2\2"+ + "\u02c1\u02c2\5V,\2\u02c2\u02c3\7h\2\2\u02c3\u02c4\7\u0084\2\2\u02c4\u02c5"+ + "\7j\2\2\u02c5\u02cb\3\2\2\2\u02c6\u02c7\7i\2\2\u02c7\u02c8\5V,\2\u02c8"+ + "\u02c9\7j\2\2\u02c9\u02cb\3\2\2\2\u02ca\u02b3\3\2\2\2\u02ca\u02b4\3\2"+ + "\2\2\u02ca\u02b6\3\2\2\2\u02ca\u02ba\3\2\2\2\u02ca\u02c0\3\2\2\2\u02ca"+ + "\u02c6\3\2\2\2\u02cbU\3\2\2\2\u02cc\u02cd\b,\1\2\u02cd\u02ce\7k\2\2\u02ce"+ + "\u02cf\5V,\2\u02cf\u02d0\7l\2\2\u02d0\u02db\3\2\2\2\u02d1\u02d2\t\n\2"+ + "\2\u02d2\u02db\5V,\n\u02d3\u02db\7\u0084\2\2\u02d4\u02db\7\u0082\2\2\u02d5"+ + "\u02d6\7v\2\2\u02d6\u02d7\7\u0084\2\2\u02d7\u02db\7w\2\2\u02d8\u02db\7"+ + "x\2\2\u02d9\u02db\7\u0081\2\2\u02da\u02cc\3\2\2\2\u02da\u02d1\3\2\2\2"+ + "\u02da\u02d3\3\2\2\2\u02da\u02d4\3\2\2\2\u02da\u02d5\3\2\2\2\u02da\u02d8"+ + "\3\2\2\2\u02da\u02d9\3\2\2\2\u02db\u02ea\3\2\2\2\u02dc\u02dd\f\f\2\2\u02dd"+ + "\u02de\7m\2\2\u02de\u02e9\5V,\r\u02df\u02e0\f\13\2\2\u02e0\u02e1\t\13"+ + "\2\2\u02e1\u02e9\5V,\f\u02e2\u02e3\f\t\2\2\u02e3\u02e4\t\f\2\2\u02e4\u02e9"+ + "\5V,\n\u02e5\u02e6\f\b\2\2\u02e6\u02e7\t\r\2\2\u02e7\u02e9\5V,\t\u02e8"+ + "\u02dc\3\2\2\2\u02e8\u02df\3\2\2\2\u02e8\u02e2\3\2\2\2\u02e8\u02e5\3\2"+ + "\2\2\u02e9\u02ec\3\2\2\2\u02ea\u02e8\3\2\2\2\u02ea\u02eb\3\2\2\2\u02eb"+ + "W\3\2\2\2\u02ec\u02ea\3\2\2\2Gafz\u0084\u008b\u0099\u009f\u00a4\u00aa"+ + "\u00af\u00b8\u00bf\u00ca\u00f2\u00ff\u0107\u0110\u0114\u0119\u0120\u012d"+ + "\u0132\u013e\u014c\u015f\u0168\u016f\u0174\u0179\u017b\u0181\u0188\u018b"+ + "\u0193\u0196\u0199\u01a3\u01aa\u01b1\u01b7\u01b9\u01c1\u01c7\u01d3\u01e1"+ + "\u01e7\u01f1\u01fd\u0205\u021c\u0226\u022a\u025c\u0266\u0268\u0270\u0275"+ + "\u027f\u0291\u0293\u0298\u029e\u02a4\u02a8\u02b0\u02ca\u02da\u02e8\u02ea"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index 774abd131..9ea19d090 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -1,6 +1,5 @@ package dk.camelot64.kickc.passes; -import dk.camelot64.kickc.parser.*; import dk.camelot64.kickc.NumberParser; import dk.camelot64.kickc.SourceLoader; import dk.camelot64.kickc.asm.AsmClobber; @@ -10,7 +9,13 @@ import dk.camelot64.kickc.model.statements.*; import dk.camelot64.kickc.model.symbols.*; import dk.camelot64.kickc.model.types.*; import dk.camelot64.kickc.model.values.*; -import org.antlr.v4.runtime.*; +import dk.camelot64.kickc.parser.CParser; +import dk.camelot64.kickc.parser.KickCParser; +import dk.camelot64.kickc.parser.KickCParserBaseVisitor; +import org.antlr.v4.runtime.BufferedTokenStream; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; @@ -100,10 +105,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor reservedZps = new ArrayList<>(); + List reservedZps = new ArrayList<>(); for(TerminalNode reservedNum : ctx.NUMBER()) { Number reservedZp = NumberParser.parseLiteral(reservedNum.getText()); - reservedZps.add(reservedZp); + reservedZps.add(reservedZp.intValue()); } program.addReservedZps(reservedZps); return null; @@ -663,6 +668,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor255) { + throw new CompileError("Error! Register not on zeropage " + directiveRegister.getAddress(), source); + } + Registers.Register register = new Registers.RegisterZpDeclared(address.intValue()); + lValue.setDeclaredRegister(register); } } else { throw new CompileError("Unsupported variable directive " + directive, source); @@ -753,11 +766,18 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor reservedZps = new ArrayList<>(); + List reservedZps = new ArrayList<>(); for(TerminalNode reservedNum : ctx.NUMBER()) { - Number reservedZp = NumberParser.parseLiteral(reservedNum.getText()); + int reservedZp = NumberParser.parseLiteral(reservedNum.getText()).intValue(); reservedZps.add(reservedZp); } return new DirectiveReserveZp(reservedZps); @@ -1213,10 +1233,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor exprNotConsumed = null; /** @@ -1569,24 +1590,27 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor reservedZp; + List reservedZp; - public DirectiveReserveZp(List reservedZp) { + public DirectiveReserveZp(List reservedZp) { this.reservedZp = reservedZp; } - public List getReservedZp() { + public List getReservedZp() { return reservedZp; } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2IdenticalPhiElimination.java b/src/main/java/dk/camelot64/kickc/passes/Pass2IdenticalPhiElimination.java index 7a3e7528e..a350f7a1d 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2IdenticalPhiElimination.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2IdenticalPhiElimination.java @@ -2,9 +2,13 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.ControlFlowBlock; import dk.camelot64.kickc.model.Program; +import dk.camelot64.kickc.model.Registers; import dk.camelot64.kickc.model.statements.Statement; import dk.camelot64.kickc.model.statements.StatementPhiBlock; +import dk.camelot64.kickc.model.symbols.Symbol; +import dk.camelot64.kickc.model.symbols.SymbolVariable; import dk.camelot64.kickc.model.values.RValue; +import dk.camelot64.kickc.model.values.SymbolVariableRef; import dk.camelot64.kickc.model.values.VariableRef; import java.util.LinkedHashMap; @@ -34,6 +38,14 @@ public class Pass2IdenticalPhiElimination extends Pass2SsaOptimization { RValue rValue = null; boolean identical = true; for(StatementPhiBlock.PhiRValue phiRValue : phiVariable.getValues()) { + if(phiRValue.getrValue() instanceof SymbolVariableRef) { + SymbolVariable symbolVar = (SymbolVariable) getScope().getSymbol((SymbolVariableRef) phiRValue.getrValue()); + if(symbolVar.getDeclaredRegister() !=null) { + // Do not collapse PHI's for variables with declared registers (this prevents procedure parameters from being turned into constants) + identical = false; + break; + } + } if(phiRValue.getrValue().equals(phiVariable.getVariable())) { // Self PHI - skip that continue; @@ -43,7 +55,7 @@ public class Pass2IdenticalPhiElimination extends Pass2SsaOptimization { } else { if(!rValue.equals(phiRValue.getrValue())) { identical = false; - continue; + break; } } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java index f181b9eb1..8047f1c94 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java @@ -1,14 +1,14 @@ package dk.camelot64.kickc.passes; import dk.camelot64.kickc.model.*; -import dk.camelot64.kickc.model.symbols.Procedure; -import dk.camelot64.kickc.model.types.SymbolTypeStruct; -import dk.camelot64.kickc.model.values.VariableRef; import dk.camelot64.kickc.model.symbols.ConstantVar; +import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Scope; import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypePointer; +import dk.camelot64.kickc.model.types.SymbolTypeStruct; +import dk.camelot64.kickc.model.values.VariableRef; import java.util.*; @@ -24,18 +24,31 @@ public class Pass4RegistersFinalize extends Pass2Base { private int currentZp = 2; /** All reserved zeropage addresses not available for the compiler. */ - private List reservedZp; + private List reservedZp; public Pass4RegistersFinalize(Program program) { super(program); this.reservedZp = new ArrayList<>(); + // Add all ZP's declared as reserved this.reservedZp.addAll(program.getReservedZps()); + // Add all ZP's declared as reserved in a procedure for(Procedure procedure : getSymbols().getAllProcedures(true)) { - List procedureReservedZps = procedure.getReservedZps(); + List procedureReservedZps = procedure.getReservedZps(); if(procedureReservedZps!=null) { this.reservedZp.addAll(procedureReservedZps); } } + // Add all ZP's declared hardcoded register for a live variable + for(Variable variable : getSymbols().getAllVariables(true)) { + if(variable.getDeclaredRegister() instanceof Registers.RegisterZpDeclared) { + int zp = ((Registers.RegisterZpDeclared) variable.getDeclaredRegister()).getZp(); + int sizeBytes = variable.getType().getSizeBytes(); + for(int i=0;iscreen + sta.z at+1 + txa + sta.z i + lda #main.msg + sta.z msg+1 + b1: + ldy.z i + lda (msg),y + cmp #0 + bne b2 + rts + b2: + ldy.z i + lda (msg),y + jsr print_char + inx + inx + inc.z i + jmp b1 +} +// print_char(byte* zeropage($fa) at, byte register(X) idx, byte register(A) ch) +print_char: { + .label at = $fa + stx.z $ff + ldy.z $ff + sta (at),y + rts +} diff --git a/src/test/ref/var-register-zp-3.cfg b/src/test/ref/var-register-zp-3.cfg new file mode 100644 index 000000000..dc71d46eb --- /dev/null +++ b/src/test/ref/var-register-zp-3.cfg @@ -0,0 +1,48 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + [5] call print2 + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return +print2: scope:[print2] from main + [7] phi() + to:print2::@1 +print2::@1: scope:[print2] from print2 print2::@3 + [8] (byte) print2::j#2 ← phi( print2/(byte) 0 print2::@3/(byte) print2::j#1 ) + [8] (byte*) print2::at#1 ← phi( print2/(const byte*) screen#0 print2::@3/(byte*) print2::at#1 ) + [8] (byte) print2::i#2 ← phi( print2/(byte) 0 print2::@3/(byte) print2::i#1 ) + [8] (byte*) print2::msg#1 ← phi( print2/(const string) main::msg print2::@3/(byte*) print2::msg#1 ) + [9] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 + to:print2::@return +print2::@return: scope:[print2] from print2::@1 + [10] return + to:@return +print2::@2: scope:[print2] from print2::@1 + [11] (byte*) print_char::at#0 ← (byte*) print2::at#1 + [12] (byte) print_char::idx#0 ← (byte) print2::j#2 + [13] (byte) print_char::ch#0 ← *((byte*) print2::msg#1 + (byte) print2::i#2) + [14] call print_char + to:print2::@3 +print2::@3: scope:[print2] from print2::@2 + [15] (byte) print2::j#1 ← (byte) print2::j#2 + (byte) 2 + [16] (byte) print2::i#1 ← ++ (byte) print2::i#2 + to:print2::@1 +print_char: scope:[print_char] from print2::@2 + [17] (byte) print_char::idx#1 ← phi( print2::@2/(byte) print_char::idx#0 ) + [17] (byte*) print_char::at#1 ← phi( print2::@2/(byte*) print_char::at#0 ) + [17] (byte) print_char::ch#1 ← phi( print2::@2/(byte) print_char::ch#0 ) + [18] *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 + to:print_char::@return +print_char::@return: scope:[print_char] from print_char + [19] return + to:@return diff --git a/src/test/ref/var-register-zp-3.log b/src/test/ref/var-register-zp-3.log new file mode 100644 index 000000000..3ccd65ed1 --- /dev/null +++ b/src/test/ref/var-register-zp-3.log @@ -0,0 +1,772 @@ +Warning! Adding boolean cast to non-boolean condition *((byte*) print2::msg + (byte) print2::i) +Identified constant variable (byte*) screen +Culled Empty Block (label) @1 +Culled Empty Block (label) print2::@4 +Culled Empty Block (label) print2::@3 +Culled Empty Block (label) print2::@5 +Culled Empty Block (label) print2::@6 +Culled Empty Block (label) @2 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) screen#0 ← ((byte*)) (number) $400 + to:@3 +main: scope:[main] from @3 + (byte*) print2::at#0 ← (byte*) screen#0 + (byte*) print2::msg#0 ← (const string) main::msg + call print2 + to:main::@1 +main::@1: scope:[main] from main + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +print2: scope:[print2] from main + (byte*) print2::at#3 ← phi( main/(byte*) print2::at#0 ) + (byte*) print2::msg#3 ← phi( main/(byte*) print2::msg#0 ) + (byte) print2::j#0 ← (number) 0 + (byte) print2::i#0 ← (number) 0 + to:print2::@1 +print2::@1: scope:[print2] from print2 print2::@7 + (byte) print2::j#4 ← phi( print2/(byte) print2::j#0 print2::@7/(byte) print2::j#1 ) + (byte*) print2::at#2 ← phi( print2/(byte*) print2::at#3 print2::@7/(byte*) print2::at#4 ) + (byte) print2::i#2 ← phi( print2/(byte) print2::i#0 print2::@7/(byte) print2::i#1 ) + (byte*) print2::msg#1 ← phi( print2/(byte*) print2::msg#3 print2::@7/(byte*) print2::msg#4 ) + (bool~) print2::$1 ← (number) 0 != *((byte*) print2::msg#1 + (byte) print2::i#2) + if((bool~) print2::$1) goto print2::@2 + to:print2::@return +print2::@2: scope:[print2] from print2::@1 + (byte) print2::i#3 ← phi( print2::@1/(byte) print2::i#2 ) + (byte*) print2::msg#2 ← phi( print2::@1/(byte*) print2::msg#1 ) + (byte) print2::j#2 ← phi( print2::@1/(byte) print2::j#4 ) + (byte*) print2::at#1 ← phi( print2::@1/(byte*) print2::at#2 ) + (byte*) print_char::at#0 ← (byte*) print2::at#1 + (byte) print_char::idx#0 ← (byte) print2::j#2 + (byte) print_char::ch#0 ← *((byte*) print2::msg#2 + (byte) print2::i#3) + call print_char + to:print2::@7 +print2::@7: scope:[print2] from print2::@2 + (byte*) print2::at#4 ← phi( print2::@2/(byte*) print2::at#1 ) + (byte*) print2::msg#4 ← phi( print2::@2/(byte*) print2::msg#2 ) + (byte) print2::i#4 ← phi( print2::@2/(byte) print2::i#3 ) + (byte) print2::j#3 ← phi( print2::@2/(byte) print2::j#2 ) + (byte) print2::j#1 ← (byte) print2::j#3 + (number) 2 + (byte) print2::i#1 ← ++ (byte) print2::i#4 + to:print2::@1 +print2::@return: scope:[print2] from print2::@1 + return + to:@return +print_char: scope:[print_char] from print2::@2 + (byte) print_char::idx#1 ← phi( print2::@2/(byte) print_char::idx#0 ) + (byte*) print_char::at#1 ← phi( print2::@2/(byte*) print_char::at#0 ) + (byte) print_char::ch#1 ← phi( print2::@2/(byte) print_char::ch#0 ) + *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 + to:print_char::@return +print_char::@return: scope:[print_char] from print_char + return + to:@return +@3: scope:[] from @begin + call main + to:@4 +@4: scope:[] from @3 + to:@end +@end: scope:[] from @4 + +SYMBOL TABLE SSA +(label) @3 +(label) @4 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@return +(const string) main::msg = (string) "hello" +(void()) print2((byte*) print2::at , (byte*) print2::msg) +(bool~) print2::$1 +(label) print2::@1 +(label) print2::@2 +(label) print2::@7 +(label) print2::@return +(byte*) print2::at !zp ZP_VAR:250 +(byte*) print2::at#0 !zp ZP_VAR:250 +(byte*) print2::at#1 !zp ZP_VAR:250 +(byte*) print2::at#2 !zp ZP_VAR:250 +(byte*) print2::at#3 !zp ZP_VAR:250 +(byte*) print2::at#4 !zp ZP_VAR:250 +(byte) print2::i +(byte) print2::i#0 +(byte) print2::i#1 +(byte) print2::i#2 +(byte) print2::i#3 +(byte) print2::i#4 +(byte) print2::j +(byte) print2::j#0 +(byte) print2::j#1 +(byte) print2::j#2 +(byte) print2::j#3 +(byte) print2::j#4 +(byte*) print2::msg !zp ZP_VAR:252 +(byte*) print2::msg#0 !zp ZP_VAR:252 +(byte*) print2::msg#1 !zp ZP_VAR:252 +(byte*) print2::msg#2 !zp ZP_VAR:252 +(byte*) print2::msg#3 !zp ZP_VAR:252 +(byte*) print2::msg#4 !zp ZP_VAR:252 +(void()) print_char((byte*) print_char::at , (byte) print_char::idx , (byte) print_char::ch) +(label) print_char::@return +(byte*) print_char::at !zp ZP_VAR:250 +(byte*) print_char::at#0 !zp ZP_VAR:250 +(byte*) print_char::at#1 !zp ZP_VAR:250 +(byte) print_char::ch !reg byte a +(byte) print_char::ch#0 !reg byte a +(byte) print_char::ch#1 !reg byte a +(byte) print_char::idx !reg byte x +(byte) print_char::idx#0 !reg byte x +(byte) print_char::idx#1 !reg byte x +(byte*) screen +(byte*) screen#0 + +Adding number conversion cast (unumber) 0 in (byte) print2::j#0 ← (number) 0 +Adding number conversion cast (unumber) 0 in (byte) print2::i#0 ← (number) 0 +Adding number conversion cast (unumber) 0 in (bool~) print2::$1 ← (number) 0 != *((byte*) print2::msg#1 + (byte) print2::i#2) +Adding number conversion cast (unumber) 2 in (byte) print2::j#1 ← (byte) print2::j#3 + (number) 2 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) screen#0 ← (byte*)(number) $400 +Inlining cast (byte) print2::j#0 ← (unumber)(number) 0 +Inlining cast (byte) print2::i#0 ← (unumber)(number) 0 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 2 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 2 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte*) print2::at#1 = (byte*) print2::at#2 (byte*) print2::at#4 +Alias (byte) print2::j#2 = (byte) print2::j#4 (byte) print2::j#3 +Alias (byte*) print2::msg#1 = (byte*) print2::msg#2 (byte*) print2::msg#4 +Alias (byte) print2::i#2 = (byte) print2::i#3 (byte) print2::i#4 +Successful SSA optimization Pass2AliasElimination +Simple Condition (bool~) print2::$1 [10] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) screen#0 = (byte*) 1024 +Constant (const byte*) print2::msg#0 = main::msg +Constant (const byte) print2::j#0 = 0 +Constant (const byte) print2::i#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte*) print2::at#0 = screen#0 +Constant (const byte*) print2::msg#3 = print2::msg#0 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte*) print2::at#3 = print2::at#0 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with var siblings (const byte*) print2::msg#0 +Inlining constant with var siblings (const byte) print2::j#0 +Inlining constant with var siblings (const byte) print2::i#0 +Inlining constant with var siblings (const byte*) print2::at#0 +Inlining constant with var siblings (const byte*) print2::msg#3 +Inlining constant with var siblings (const byte*) print2::at#3 +Constant inlined print2::at#0 = (const byte*) screen#0 +Constant inlined print2::msg#3 = (const string) main::msg +Constant inlined print2::j#0 = (byte) 0 +Constant inlined print2::msg#0 = (const string) main::msg +Constant inlined print2::i#0 = (byte) 0 +Constant inlined print2::at#3 = (const byte*) screen#0 +Successful SSA optimization Pass2ConstantInlining +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @3 +Adding NOP phi() at start of @4 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@1 +Adding NOP phi() at start of print2 +CALL GRAPH +Calls in [] to main:2 +Calls in [main] to print2:6 +Calls in [print2] to print_char:19 + +Created 7 initial phi equivalence classes +Coalesced [16] print_char::ch#2 ← print_char::ch#0 +Coalesced [17] print_char::at#2 ← print_char::at#0 +Coalesced [18] print_char::idx#2 ← print_char::idx#0 +Coalesced (already) [22] print2::msg#5 ← print2::msg#1 +Coalesced [23] print2::i#5 ← print2::i#1 +Coalesced (already) [24] print2::at#5 ← print2::at#1 +Coalesced [25] print2::j#5 ← print2::j#1 +Coalesced down to 7 phi equivalence classes +Culled Empty Block (label) @4 +Culled Empty Block (label) main::@1 +Renumbering block @3 to @1 +Renumbering block print2::@7 to print2::@3 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +Adding NOP phi() at start of print2 + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + [5] call print2 + to:main::@return +main::@return: scope:[main] from main + [6] return + to:@return +print2: scope:[print2] from main + [7] phi() + to:print2::@1 +print2::@1: scope:[print2] from print2 print2::@3 + [8] (byte) print2::j#2 ← phi( print2/(byte) 0 print2::@3/(byte) print2::j#1 ) + [8] (byte*) print2::at#1 ← phi( print2/(const byte*) screen#0 print2::@3/(byte*) print2::at#1 ) + [8] (byte) print2::i#2 ← phi( print2/(byte) 0 print2::@3/(byte) print2::i#1 ) + [8] (byte*) print2::msg#1 ← phi( print2/(const string) main::msg print2::@3/(byte*) print2::msg#1 ) + [9] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 + to:print2::@return +print2::@return: scope:[print2] from print2::@1 + [10] return + to:@return +print2::@2: scope:[print2] from print2::@1 + [11] (byte*) print_char::at#0 ← (byte*) print2::at#1 + [12] (byte) print_char::idx#0 ← (byte) print2::j#2 + [13] (byte) print_char::ch#0 ← *((byte*) print2::msg#1 + (byte) print2::i#2) + [14] call print_char + to:print2::@3 +print2::@3: scope:[print2] from print2::@2 + [15] (byte) print2::j#1 ← (byte) print2::j#2 + (byte) 2 + [16] (byte) print2::i#1 ← ++ (byte) print2::i#2 + to:print2::@1 +print_char: scope:[print_char] from print2::@2 + [17] (byte) print_char::idx#1 ← phi( print2::@2/(byte) print_char::idx#0 ) + [17] (byte*) print_char::at#1 ← phi( print2::@2/(byte*) print_char::at#0 ) + [17] (byte) print_char::ch#1 ← phi( print2::@2/(byte) print_char::ch#0 ) + [18] *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 + to:print_char::@return +print_char::@return: scope:[print_char] from print_char + [19] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(void()) print2((byte*) print2::at , (byte*) print2::msg) +(byte*) print2::at !zp ZP_VAR:250 +(byte*) print2::at#1 !zp ZP_VAR:250 4.125 +(byte) print2::i +(byte) print2::i#1 22.0 +(byte) print2::i#2 6.285714285714286 +(byte) print2::j +(byte) print2::j#1 11.0 +(byte) print2::j#2 5.5 +(byte*) print2::msg !zp ZP_VAR:252 +(byte*) print2::msg#1 !zp ZP_VAR:252 5.5 +(void()) print_char((byte*) print_char::at , (byte) print_char::idx , (byte) print_char::ch) +(byte*) print_char::at !zp ZP_VAR:250 +(byte*) print_char::at#0 !zp ZP_VAR:250 7.333333333333333 +(byte*) print_char::at#1 !zp ZP_VAR:250 13.0 +(byte) print_char::ch !reg byte a +(byte) print_char::ch#0 !reg byte a 22.0 +(byte) print_char::ch#1 !reg byte a 13.0 +(byte) print_char::idx !reg byte x +(byte) print_char::idx#0 !reg byte x 11.0 +(byte) print_char::idx#1 !reg byte x 13.0 +(byte*) screen + +Initial phi equivalence classes +[ print2::msg#1 ] +[ print2::i#2 print2::i#1 ] +[ print2::at#1 ] +[ print2::j#2 print2::j#1 ] +[ print_char::ch#1 print_char::ch#0 ] +[ print_char::at#1 print_char::at#0 ] +[ print_char::idx#1 print_char::idx#0 ] +Complete equivalence classes +[ print2::msg#1 ] +[ print2::i#2 print2::i#1 ] +[ print2::at#1 ] +[ print2::j#2 print2::j#1 ] +[ print_char::ch#1 print_char::ch#0 ] +[ print_char::at#1 print_char::at#0 ] +[ print_char::idx#1 print_char::idx#0 ] +Setting declared register type (byte*) print2::msg#1 to ZP_WORD +Setting declared register type (byte*) print2::at#1 to ZP_WORD +Setting declared register type (byte*) print_char::at#1 to ZP_WORD +Allocated zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] +Allocated zp ZP_BYTE:3 [ print2::j#2 print2::j#1 ] + +INITIAL ASM +Target platform is c64basic + // File Comments +// Test declaring a variable as register on a specific ZP address + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label screen = $400 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + // [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + // [5] call print2 + // [7] phi from main to print2 [phi:main->print2] + print2_from_main: + jsr print2 + jmp breturn + // main::@return + breturn: + // [6] return + rts + msg: .text "hello" + .byte 0 +} + // print2 +// print2(byte* zeropage($fa) at, byte* zeropage($fc) msg) +print2: { + .label j = 3 + .label i = 2 + .label msg = $fc + .label at = $fa + // [8] phi from print2 to print2::@1 [phi:print2->print2::@1] + b1_from_print2: + // [8] phi (byte) print2::j#2 = (byte) 0 [phi:print2->print2::@1#0] -- vbuz1=vbuc1 + lda #0 + sta.z j + // [8] phi (byte*) print2::at#1 = (const byte*) screen#0 [phi:print2->print2::@1#1] -- pbuz1=pbuc1 + lda #screen + sta.z at+1 + // [8] phi (byte) print2::i#2 = (byte) 0 [phi:print2->print2::@1#2] -- vbuz1=vbuc1 + lda #0 + sta.z i + // [8] phi (byte*) print2::msg#1 = (const string) main::msg [phi:print2->print2::@1#3] -- pbuz1=pbuc1 + lda #main.msg + sta.z msg+1 + jmp b1 + // print2::@1 + b1: + // [9] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 -- vbuc1_neq_pbuz1_derefidx_vbuz2_then_la1 + ldy.z i + lda (msg),y + cmp #0 + bne b2 + jmp breturn + // print2::@return + breturn: + // [10] return + rts + // print2::@2 + b2: + // [11] (byte*) print_char::at#0 ← (byte*) print2::at#1 + // [12] (byte) print_char::idx#0 ← (byte) print2::j#2 -- vbuxx=vbuz1 + ldx.z j + // [13] (byte) print_char::ch#0 ← *((byte*) print2::msg#1 + (byte) print2::i#2) -- vbuaa=pbuz1_derefidx_vbuz2 + ldy.z i + lda (msg),y + // [14] call print_char + // [17] phi from print2::@2 to print_char [phi:print2::@2->print_char] + print_char_from_b2: + // [17] phi (byte) print_char::idx#1 = (byte) print_char::idx#0 [phi:print2::@2->print_char#0] -- register_copy + // [17] phi (byte*) print_char::at#1 = (byte*) print_char::at#0 [phi:print2::@2->print_char#1] -- register_copy + // [17] phi (byte) print_char::ch#1 = (byte) print_char::ch#0 [phi:print2::@2->print_char#2] -- register_copy + jsr print_char + jmp b3 + // print2::@3 + b3: + // [15] (byte) print2::j#1 ← (byte) print2::j#2 + (byte) 2 -- vbuz1=vbuz1_plus_2 + lda.z j + clc + adc #2 + sta.z j + // [16] (byte) print2::i#1 ← ++ (byte) print2::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [8] phi from print2::@3 to print2::@1 [phi:print2::@3->print2::@1] + b1_from_b3: + // [8] phi (byte) print2::j#2 = (byte) print2::j#1 [phi:print2::@3->print2::@1#0] -- register_copy + // [8] phi (byte*) print2::at#1 = (byte*) print2::at#1 [phi:print2::@3->print2::@1#1] -- register_copy + // [8] phi (byte) print2::i#2 = (byte) print2::i#1 [phi:print2::@3->print2::@1#2] -- register_copy + // [8] phi (byte*) print2::msg#1 = (byte*) print2::msg#1 [phi:print2::@3->print2::@1#3] -- register_copy + jmp b1 +} + // print_char +// print_char(byte* zeropage($fa) at, byte register(X) idx, byte register(A) ch) +print_char: { + .label at = $fa + // [18] *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 -- pbuz1_derefidx_vbuxx=vbuaa + stx.z $ff + ldy.z $ff + sta (at),y + jmp breturn + // print_char::@return + breturn: + // [19] return + rts +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [9] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 ] ( main:2::print2:5 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ print2::j#2 print2::j#1 ] +Statement [13] (byte) print_char::ch#0 ← *((byte*) print2::msg#1 + (byte) print2::i#2) [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 print_char::at#0 print_char::idx#0 print_char::ch#0 ] ( main:2::print2:5 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 print_char::at#0 print_char::idx#0 print_char::ch#0 ] ) always clobbers reg byte a +Statement [18] *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 [ ] ( main:2::print2:5::print_char:14 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 ] ) always clobbers reg byte y +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:3 [ print2::j#2 print2::j#1 ] +Statement [9] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 ] ( main:2::print2:5 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 ] ) always clobbers reg byte a reg byte y +Statement [13] (byte) print_char::ch#0 ← *((byte*) print2::msg#1 + (byte) print2::i#2) [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 print_char::at#0 print_char::idx#0 print_char::ch#0 ] ( main:2::print2:5 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 print_char::at#0 print_char::idx#0 print_char::ch#0 ] ) always clobbers reg byte a reg byte y +Statement [18] *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 [ ] ( main:2::print2:5::print_char:14 [ print2::msg#1 print2::i#2 print2::at#1 print2::j#2 ] ) always clobbers reg byte y +Potential registers zp ZP_WORD:252 [ print2::msg#1 ] : zp ZP_WORD:252 , +Potential registers zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] : zp ZP_BYTE:2 , reg byte x , +Potential registers zp ZP_WORD:250 [ print2::at#1 ] : zp ZP_WORD:250 , +Potential registers zp ZP_BYTE:3 [ print2::j#2 print2::j#1 ] : zp ZP_BYTE:3 , reg byte x , +Potential registers reg byte a [ print_char::ch#1 print_char::ch#0 ] : reg byte a , +Potential registers zp ZP_WORD:250 [ print_char::at#1 print_char::at#0 ] : zp ZP_WORD:250 , +Potential registers reg byte x [ print_char::idx#1 print_char::idx#0 ] : reg byte x , + +REGISTER UPLIFT SCOPES +Uplift Scope [print_char] 35: reg byte a [ print_char::ch#1 print_char::ch#0 ] 24: reg byte x [ print_char::idx#1 print_char::idx#0 ] 20.33: zp ZP_WORD:250 [ print_char::at#1 print_char::at#0 ] +Uplift Scope [print2] 28.29: zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] 16.5: zp ZP_BYTE:3 [ print2::j#2 print2::j#1 ] 5.5: zp ZP_WORD:252 [ print2::msg#1 ] 4.12: zp ZP_WORD:250 [ print2::at#1 ] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [print_char] best 848 combination reg byte a [ print_char::ch#1 print_char::ch#0 ] reg byte x [ print_char::idx#1 print_char::idx#0 ] zp ZP_WORD:250 [ print_char::at#1 print_char::at#0 ] +Uplifting [print2] best 728 combination zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] reg byte x [ print2::j#2 print2::j#1 ] zp ZP_WORD:252 [ print2::msg#1 ] zp ZP_WORD:250 [ print2::at#1 ] +Uplifting [main] best 728 combination +Uplifting [] best 728 combination +Attempting to uplift remaining variables inzp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] +Uplifting [print2] best 728 combination zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] +Coalescing zero page register [ zp ZP_WORD:250 [ print2::at#1 ] ] with [ zp ZP_WORD:250 [ print_char::at#1 print_char::at#0 ] ] - score: 1 + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test declaring a variable as register on a specific ZP address + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label screen = $400 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + // [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + // [5] call print2 + // [7] phi from main to print2 [phi:main->print2] + print2_from_main: + jsr print2 + jmp breturn + // main::@return + breturn: + // [6] return + rts + msg: .text "hello" + .byte 0 +} + // print2 +// print2(byte* zeropage($fa) at, byte* zeropage($fc) msg) +print2: { + .label i = 2 + .label msg = $fc + .label at = $fa + // [8] phi from print2 to print2::@1 [phi:print2->print2::@1] + b1_from_print2: + // [8] phi (byte) print2::j#2 = (byte) 0 [phi:print2->print2::@1#0] -- vbuxx=vbuc1 + ldx #0 + // [8] phi (byte*) print2::at#1 = (const byte*) screen#0 [phi:print2->print2::@1#1] -- pbuz1=pbuc1 + lda #screen + sta.z at+1 + // [8] phi (byte) print2::i#2 = (byte) 0 [phi:print2->print2::@1#2] -- vbuz1=vbuc1 + lda #0 + sta.z i + // [8] phi (byte*) print2::msg#1 = (const string) main::msg [phi:print2->print2::@1#3] -- pbuz1=pbuc1 + lda #main.msg + sta.z msg+1 + jmp b1 + // print2::@1 + b1: + // [9] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 -- vbuc1_neq_pbuz1_derefidx_vbuz2_then_la1 + ldy.z i + lda (msg),y + cmp #0 + bne b2 + jmp breturn + // print2::@return + breturn: + // [10] return + rts + // print2::@2 + b2: + // [11] (byte*) print_char::at#0 ← (byte*) print2::at#1 + // [12] (byte) print_char::idx#0 ← (byte) print2::j#2 + // [13] (byte) print_char::ch#0 ← *((byte*) print2::msg#1 + (byte) print2::i#2) -- vbuaa=pbuz1_derefidx_vbuz2 + ldy.z i + lda (msg),y + // [14] call print_char + // [17] phi from print2::@2 to print_char [phi:print2::@2->print_char] + print_char_from_b2: + // [17] phi (byte) print_char::idx#1 = (byte) print_char::idx#0 [phi:print2::@2->print_char#0] -- register_copy + // [17] phi (byte*) print_char::at#1 = (byte*) print_char::at#0 [phi:print2::@2->print_char#1] -- register_copy + // [17] phi (byte) print_char::ch#1 = (byte) print_char::ch#0 [phi:print2::@2->print_char#2] -- register_copy + jsr print_char + jmp b3 + // print2::@3 + b3: + // [15] (byte) print2::j#1 ← (byte) print2::j#2 + (byte) 2 -- vbuxx=vbuxx_plus_2 + inx + inx + // [16] (byte) print2::i#1 ← ++ (byte) print2::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [8] phi from print2::@3 to print2::@1 [phi:print2::@3->print2::@1] + b1_from_b3: + // [8] phi (byte) print2::j#2 = (byte) print2::j#1 [phi:print2::@3->print2::@1#0] -- register_copy + // [8] phi (byte*) print2::at#1 = (byte*) print2::at#1 [phi:print2::@3->print2::@1#1] -- register_copy + // [8] phi (byte) print2::i#2 = (byte) print2::i#1 [phi:print2::@3->print2::@1#2] -- register_copy + // [8] phi (byte*) print2::msg#1 = (byte*) print2::msg#1 [phi:print2::@3->print2::@1#3] -- register_copy + jmp b1 +} + // print_char +// print_char(byte* zeropage($fa) at, byte register(X) idx, byte register(A) ch) +print_char: { + .label at = $fa + // [18] *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 -- pbuz1_derefidx_vbuxx=vbuaa + stx.z $ff + ldy.z $ff + sta (at),y + jmp breturn + // print_char::@return + breturn: + // [19] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp breturn +Removing instruction jmp b1 +Removing instruction jmp breturn +Removing instruction jmp b3 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing instruction lda #0 with TXA +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction print2_from_main: +Removing instruction breturn: +Removing instruction b1_from_print2: +Removing instruction breturn: +Removing instruction print_char_from_b2: +Removing instruction b3: +Removing instruction b1_from_b3: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(const string) main::msg msg = (string) "hello" +(void()) print2((byte*) print2::at , (byte*) print2::msg) +(label) print2::@1 +(label) print2::@2 +(label) print2::@3 +(label) print2::@return +(byte*) print2::at !zp ZP_WORD:250 +(byte*) print2::at#1 at !zp ZP_WORD:250 4.125 +(byte) print2::i +(byte) print2::i#1 i zp ZP_BYTE:2 22.0 +(byte) print2::i#2 i zp ZP_BYTE:2 6.285714285714286 +(byte) print2::j +(byte) print2::j#1 reg byte x 11.0 +(byte) print2::j#2 reg byte x 5.5 +(byte*) print2::msg !zp ZP_WORD:252 +(byte*) print2::msg#1 msg !zp ZP_WORD:252 5.5 +(void()) print_char((byte*) print_char::at , (byte) print_char::idx , (byte) print_char::ch) +(label) print_char::@return +(byte*) print_char::at !zp ZP_WORD:250 +(byte*) print_char::at#0 at !zp ZP_WORD:250 7.333333333333333 +(byte*) print_char::at#1 at !zp ZP_WORD:250 13.0 +(byte) print_char::ch !reg byte a +(byte) print_char::ch#0 !reg byte a 22.0 +(byte) print_char::ch#1 !reg byte a 13.0 +(byte) print_char::idx !reg byte x +(byte) print_char::idx#0 !reg byte x 11.0 +(byte) print_char::idx#1 !reg byte x 13.0 +(byte*) screen +(const byte*) screen#0 screen = (byte*) 1024 + +zp ZP_WORD:252 [ print2::msg#1 ] +zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] +zp ZP_WORD:250 [ print2::at#1 print_char::at#1 print_char::at#0 ] +reg byte x [ print2::j#2 print2::j#1 ] +reg byte a [ print_char::ch#1 print_char::ch#0 ] +reg byte x [ print_char::idx#1 print_char::idx#0 ] + + +FINAL ASSEMBLER +Score: 647 + + // File Comments +// Test declaring a variable as register on a specific ZP address + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label screen = $400 + // @begin + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + // [4] phi from @1 to main [phi:@1->main] + // [3] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + // print2(screen, "hello") + // [5] call print2 + // [7] phi from main to print2 [phi:main->print2] + jsr print2 + // main::@return + // } + // [6] return + rts + msg: .text "hello" + .byte 0 +} + // print2 +// print2(byte* zeropage($fa) at, byte* zeropage($fc) msg) +print2: { + .label i = 2 + .label msg = $fc + .label at = $fa + // [8] phi from print2 to print2::@1 [phi:print2->print2::@1] + // [8] phi (byte) print2::j#2 = (byte) 0 [phi:print2->print2::@1#0] -- vbuxx=vbuc1 + ldx #0 + // [8] phi (byte*) print2::at#1 = (const byte*) screen#0 [phi:print2->print2::@1#1] -- pbuz1=pbuc1 + lda #screen + sta.z at+1 + // [8] phi (byte) print2::i#2 = (byte) 0 [phi:print2->print2::@1#2] -- vbuz1=vbuc1 + txa + sta.z i + // [8] phi (byte*) print2::msg#1 = (const string) main::msg [phi:print2->print2::@1#3] -- pbuz1=pbuc1 + lda #main.msg + sta.z msg+1 + // print2::@1 + b1: + // for(byte i=0; msg[i]; i++) + // [9] if((byte) 0!=*((byte*) print2::msg#1 + (byte) print2::i#2)) goto print2::@2 -- vbuc1_neq_pbuz1_derefidx_vbuz2_then_la1 + ldy.z i + lda (msg),y + cmp #0 + bne b2 + // print2::@return + // } + // [10] return + rts + // print2::@2 + b2: + // print_char(at, j, msg[i]) + // [11] (byte*) print_char::at#0 ← (byte*) print2::at#1 + // [12] (byte) print_char::idx#0 ← (byte) print2::j#2 + // [13] (byte) print_char::ch#0 ← *((byte*) print2::msg#1 + (byte) print2::i#2) -- vbuaa=pbuz1_derefidx_vbuz2 + ldy.z i + lda (msg),y + // [14] call print_char + // [17] phi from print2::@2 to print_char [phi:print2::@2->print_char] + // [17] phi (byte) print_char::idx#1 = (byte) print_char::idx#0 [phi:print2::@2->print_char#0] -- register_copy + // [17] phi (byte*) print_char::at#1 = (byte*) print_char::at#0 [phi:print2::@2->print_char#1] -- register_copy + // [17] phi (byte) print_char::ch#1 = (byte) print_char::ch#0 [phi:print2::@2->print_char#2] -- register_copy + jsr print_char + // print2::@3 + // j += 2 + // [15] (byte) print2::j#1 ← (byte) print2::j#2 + (byte) 2 -- vbuxx=vbuxx_plus_2 + inx + inx + // for(byte i=0; msg[i]; i++) + // [16] (byte) print2::i#1 ← ++ (byte) print2::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [8] phi from print2::@3 to print2::@1 [phi:print2::@3->print2::@1] + // [8] phi (byte) print2::j#2 = (byte) print2::j#1 [phi:print2::@3->print2::@1#0] -- register_copy + // [8] phi (byte*) print2::at#1 = (byte*) print2::at#1 [phi:print2::@3->print2::@1#1] -- register_copy + // [8] phi (byte) print2::i#2 = (byte) print2::i#1 [phi:print2::@3->print2::@1#2] -- register_copy + // [8] phi (byte*) print2::msg#1 = (byte*) print2::msg#1 [phi:print2::@3->print2::@1#3] -- register_copy + jmp b1 +} + // print_char +// print_char(byte* zeropage($fa) at, byte register(X) idx, byte register(A) ch) +print_char: { + .label at = $fa + // at[idx] = ch + // [18] *((byte*) print_char::at#1 + (byte) print_char::idx#1) ← (byte) print_char::ch#1 -- pbuz1_derefidx_vbuxx=vbuaa + stx.z $ff + ldy.z $ff + sta (at),y + // print_char::@return + // } + // [19] return + rts +} + // File Data + diff --git a/src/test/ref/var-register-zp-3.sym b/src/test/ref/var-register-zp-3.sym new file mode 100644 index 000000000..03e630d4b --- /dev/null +++ b/src/test/ref/var-register-zp-3.sym @@ -0,0 +1,41 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@return +(const string) main::msg msg = (string) "hello" +(void()) print2((byte*) print2::at , (byte*) print2::msg) +(label) print2::@1 +(label) print2::@2 +(label) print2::@3 +(label) print2::@return +(byte*) print2::at !zp ZP_WORD:250 +(byte*) print2::at#1 at !zp ZP_WORD:250 4.125 +(byte) print2::i +(byte) print2::i#1 i zp ZP_BYTE:2 22.0 +(byte) print2::i#2 i zp ZP_BYTE:2 6.285714285714286 +(byte) print2::j +(byte) print2::j#1 reg byte x 11.0 +(byte) print2::j#2 reg byte x 5.5 +(byte*) print2::msg !zp ZP_WORD:252 +(byte*) print2::msg#1 msg !zp ZP_WORD:252 5.5 +(void()) print_char((byte*) print_char::at , (byte) print_char::idx , (byte) print_char::ch) +(label) print_char::@return +(byte*) print_char::at !zp ZP_WORD:250 +(byte*) print_char::at#0 at !zp ZP_WORD:250 7.333333333333333 +(byte*) print_char::at#1 at !zp ZP_WORD:250 13.0 +(byte) print_char::ch !reg byte a +(byte) print_char::ch#0 !reg byte a 22.0 +(byte) print_char::ch#1 !reg byte a 13.0 +(byte) print_char::idx !reg byte x +(byte) print_char::idx#0 !reg byte x 11.0 +(byte) print_char::idx#1 !reg byte x 13.0 +(byte*) screen +(const byte*) screen#0 screen = (byte*) 1024 + +zp ZP_WORD:252 [ print2::msg#1 ] +zp ZP_BYTE:2 [ print2::i#2 print2::i#1 ] +zp ZP_WORD:250 [ print2::at#1 print_char::at#1 print_char::at#0 ] +reg byte x [ print2::j#2 print2::j#1 ] +reg byte a [ print_char::ch#1 print_char::ch#0 ] +reg byte x [ print_char::idx#1 print_char::idx#0 ] diff --git a/src/test/ref/var-register-zp.asm b/src/test/ref/var-register-zp.asm new file mode 100644 index 000000000..a7e0d9720 --- /dev/null +++ b/src/test/ref/var-register-zp.asm @@ -0,0 +1,48 @@ +// Test declaring a variable as register on a specific ZP address +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label SCREEN = $400 +main: { + .label _1 = 6 + .label i = 2 + .label j = 4 + .label k = 6 + lda #<0 + sta.z j + sta.z j+1 + sta.z i + b1: + lda.z i + cmp #4 + bcc b2 + rts + b2: + lda.z i + asl + tay + lda.z j + sta SCREEN,y + lda.z j+1 + sta SCREEN+1,y + inc.z i + inc.z j + bne !+ + inc.z j+1 + !: + lda.z i + sta.z _1 + lda #0 + sta.z _1+1 + asl.z k + rol.z k+1 + lda.z i + asl + tay + lda.z k + sta SCREEN,y + lda.z k+1 + sta SCREEN+1,y + inc.z i + jmp b1 +} diff --git a/src/test/ref/var-register-zp.cfg b/src/test/ref/var-register-zp.cfg new file mode 100644 index 000000000..3f8b10119 --- /dev/null +++ b/src/test/ref/var-register-zp.cfg @@ -0,0 +1,31 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@2 + [5] (signed word) main::j#2 ← phi( main/(signed byte) 0 main::@2/(signed word) main::j#1 ) + [5] (byte) main::i#3 ← phi( main/(byte) 0 main::@2/(byte) main::i#2 ) + [6] if((byte) main::i#3<(byte) 4) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [7] return + to:@return +main::@2: scope:[main] from main::@1 + [8] (byte~) main::$3 ← (byte) main::i#3 << (byte) 1 + [9] *((const signed word*) SCREEN#0 + (byte~) main::$3) ← (signed word) main::j#2 + [10] (byte) main::i#1 ← ++ (byte) main::i#3 + [11] (signed word) main::j#1 ← ++ (signed word) main::j#2 + [12] (signed word~) main::$1 ← (signed word)(byte) main::i#1 + [13] (signed word) main::k#0 ← (signed word~) main::$1 << (byte) 1 + [14] (byte~) main::$4 ← (byte) main::i#1 << (byte) 1 + [15] *((const signed word*) SCREEN#0 + (byte~) main::$4) ← (signed word) main::k#0 + [16] (byte) main::i#2 ← ++ (byte) main::i#1 + to:main::@1 diff --git a/src/test/ref/var-register-zp.log b/src/test/ref/var-register-zp.log new file mode 100644 index 000000000..bdcfd51e8 --- /dev/null +++ b/src/test/ref/var-register-zp.log @@ -0,0 +1,593 @@ +Fixing pointer array-indexing *((signed word*) SCREEN + (byte) main::i) +Fixing pointer array-indexing *((signed word*) SCREEN + (byte) main::i) +Identified constant variable (signed word*) SCREEN +Culled Empty Block (label) main::@4 +Culled Empty Block (label) main::@3 +Culled Empty Block (label) main::@5 +Culled Empty Block (label) main::@6 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (signed word*) SCREEN#0 ← ((signed word*)) (number) $400 + to:@1 +main: scope:[main] from @1 + (byte) main::i#0 ← (number) 0 + (signed word) main::j#0 ← (number) 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + (signed word) main::j#3 ← phi( main/(signed word) main::j#0 main::@2/(signed word) main::j#1 ) + (byte) main::i#3 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#2 ) + (bool~) main::$0 ← (byte) main::i#3 < (number) 4 + if((bool~) main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + (signed word) main::j#2 ← phi( main::@1/(signed word) main::j#3 ) + (byte) main::i#4 ← phi( main::@1/(byte) main::i#3 ) + (byte~) main::$3 ← (byte) main::i#4 * (const byte) SIZEOF_SIGNED_WORD + *((signed word*) SCREEN#0 + (byte~) main::$3) ← (signed word) main::j#2 + (byte) main::i#1 ← ++ (byte) main::i#4 + (signed word) main::j#1 ← ++ (signed word) main::j#2 + (signed word~) main::$1 ← ((signed word)) (byte) main::i#1 + (number~) main::$2 ← (signed word~) main::$1 * (number) 2 + (signed word) main::k#0 ← (number~) main::$2 + (byte~) main::$4 ← (byte) main::i#1 * (const byte) SIZEOF_SIGNED_WORD + *((signed word*) SCREEN#0 + (byte~) main::$4) ← (signed word) main::k#0 + (byte) main::i#2 ← ++ (byte) main::i#1 + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +SYMBOL TABLE SSA +(label) @1 +(label) @2 +(label) @begin +(label) @end +(signed word*) SCREEN +(signed word*) SCREEN#0 +(const byte) SIZEOF_SIGNED_WORD = (byte) 2 +(void()) main() +(bool~) main::$0 +(signed word~) main::$1 +(number~) main::$2 +(byte~) main::$3 +(byte~) main::$4 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i !zp ZP_VAR:2 +(byte) main::i#0 !zp ZP_VAR:2 +(byte) main::i#1 !zp ZP_VAR:2 +(byte) main::i#2 !zp ZP_VAR:2 +(byte) main::i#3 !zp ZP_VAR:2 +(byte) main::i#4 !zp ZP_VAR:2 +(signed word) main::j !zp ZP_VAR:4 +(signed word) main::j#0 !zp ZP_VAR:4 +(signed word) main::j#1 !zp ZP_VAR:4 +(signed word) main::j#2 !zp ZP_VAR:4 +(signed word) main::j#3 !zp ZP_VAR:4 +(signed word) main::k +(signed word) main::k#0 + +Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0 +Adding number conversion cast (snumber) 0 in (signed word) main::j#0 ← (number) 0 +Adding number conversion cast (unumber) 4 in (bool~) main::$0 ← (byte) main::i#3 < (number) 4 +Adding number conversion cast (snumber) 2 in (number~) main::$2 ← (signed word~) main::$1 * (number) 2 +Adding number conversion cast (snumber) main::$2 in (number~) main::$2 ← (signed word~) main::$1 * (snumber)(number) 2 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (signed word*) SCREEN#0 ← (signed word*)(number) $400 +Inlining cast (byte) main::i#0 ← (unumber)(number) 0 +Inlining cast (signed word) main::j#0 ← (snumber)(number) 0 +Inlining cast (signed word~) main::$1 ← (signed word)(byte) main::i#1 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (signed word*) 1024 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant integer cast 4 +Simplifying constant integer cast 2 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized signed number type (signed byte) 0 +Finalized unsigned number type (byte) 4 +Finalized signed number type (signed byte) 2 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inferred type updated to signed word in (snumber~) main::$2 ← (signed word~) main::$1 * (signed byte) 2 +Alias (byte) main::i#3 = (byte) main::i#4 +Alias (signed word) main::j#2 = (signed word) main::j#3 +Alias (signed word) main::k#0 = (signed word~) main::$2 +Successful SSA optimization Pass2AliasElimination +Simple Condition (bool~) main::$0 [5] if((byte) main::i#3<(byte) 4) goto main::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const signed word*) SCREEN#0 = (signed word*) 1024 +Constant (const byte) main::i#0 = 0 +Constant (const signed word) main::j#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Rewriting multiplication to use shift [2] (byte~) main::$3 ← (byte) main::i#3 * (const byte) SIZEOF_SIGNED_WORD +Rewriting multiplication to use shift [7] (signed word) main::k#0 ← (signed word~) main::$1 * (signed byte) 2 +Rewriting multiplication to use shift [8] (byte~) main::$4 ← (byte) main::i#1 * (const byte) SIZEOF_SIGNED_WORD +Successful SSA optimization Pass2MultiplyToShiftRewriting +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const signed word) main::j#0 +Constant inlined main::i#0 = (byte) 0 +Constant inlined main::j#0 = (signed byte) 0 +Successful SSA optimization Pass2ConstantInlining +Eliminating unused constant (const byte) SIZEOF_SIGNED_WORD +Successful SSA optimization PassNEliminateUnusedVars +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:2 + +Created 2 initial phi equivalence classes +Coalesced [18] main::i#5 ← main::i#2 +Coalesced [19] main::j#4 ← main::j#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) @2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @1 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + [1] phi() + [2] call main + to:@end +@end: scope:[] from @1 + [3] phi() +main: scope:[main] from @1 + [4] phi() + to:main::@1 +main::@1: scope:[main] from main main::@2 + [5] (signed word) main::j#2 ← phi( main/(signed byte) 0 main::@2/(signed word) main::j#1 ) + [5] (byte) main::i#3 ← phi( main/(byte) 0 main::@2/(byte) main::i#2 ) + [6] if((byte) main::i#3<(byte) 4) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [7] return + to:@return +main::@2: scope:[main] from main::@1 + [8] (byte~) main::$3 ← (byte) main::i#3 << (byte) 1 + [9] *((const signed word*) SCREEN#0 + (byte~) main::$3) ← (signed word) main::j#2 + [10] (byte) main::i#1 ← ++ (byte) main::i#3 + [11] (signed word) main::j#1 ← ++ (signed word) main::j#2 + [12] (signed word~) main::$1 ← (signed word)(byte) main::i#1 + [13] (signed word) main::k#0 ← (signed word~) main::$1 << (byte) 1 + [14] (byte~) main::$4 ← (byte) main::i#1 << (byte) 1 + [15] *((const signed word*) SCREEN#0 + (byte~) main::$4) ← (signed word) main::k#0 + [16] (byte) main::i#2 ← ++ (byte) main::i#1 + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +(signed word*) SCREEN +(void()) main() +(signed word~) main::$1 22.0 +(byte~) main::$3 22.0 +(byte~) main::$4 22.0 +(byte) main::i !zp ZP_VAR:2 +(byte) main::i#1 !zp ZP_VAR:2 5.5 +(byte) main::i#2 !zp ZP_VAR:2 22.0 +(byte) main::i#3 !zp ZP_VAR:2 11.0 +(signed word) main::j !zp ZP_VAR:4 +(signed word) main::j#1 !zp ZP_VAR:4 3.6666666666666665 +(signed word) main::j#2 !zp ZP_VAR:4 6.6000000000000005 +(signed word) main::k +(signed word) main::k#0 11.0 + +Initial phi equivalence classes +[ main::i#3 main::i#2 ] +[ main::j#2 main::j#1 ] +Added variable main::$3 to zero page equivalence class [ main::$3 ] +Added variable main::i#1 to zero page equivalence class [ main::i#1 ] +Added variable main::$1 to zero page equivalence class [ main::$1 ] +Added variable main::k#0 to zero page equivalence class [ main::k#0 ] +Added variable main::$4 to zero page equivalence class [ main::$4 ] +Complete equivalence classes +[ main::i#3 main::i#2 ] +[ main::j#2 main::j#1 ] +[ main::$3 ] +[ main::i#1 ] +[ main::$1 ] +[ main::k#0 ] +[ main::$4 ] +Setting declared register type (byte) main::i#3 to ZP_BYTE +Setting declared register type (signed word) main::j#2 to ZP_WORD +Allocated zp ZP_BYTE:3 [ main::$3 ] +Allocated zp ZP_WORD:6 [ main::$1 ] +Allocated zp ZP_WORD:8 [ main::k#0 ] +Allocated zp ZP_BYTE:10 [ main::$4 ] + +INITIAL ASM +Target platform is c64basic + // File Comments +// Test declaring a variable as register on a specific ZP address + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + // [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + .label _1 = 6 + .label _3 = 3 + .label _4 = $a + .label i = 2 + .label j = 4 + .label k = 8 + // [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + // [5] phi (signed word) main::j#2 = (signed byte) 0 [phi:main->main::@1#0] -- vwsz1=vbsc1 + lda #<0 + sta.z j + lda #>0 + sta.z j+1 + // [5] phi (byte) main::i#3 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + lda #0 + sta.z i + jmp b1 + // main::@1 + b1: + // [6] if((byte) main::i#3<(byte) 4) goto main::@2 -- vbuz1_lt_vbuc1_then_la1 + lda.z i + cmp #4 + bcc b2 + jmp breturn + // main::@return + breturn: + // [7] return + rts + // main::@2 + b2: + // [8] (byte~) main::$3 ← (byte) main::i#3 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda.z i + asl + sta.z _3 + // [9] *((const signed word*) SCREEN#0 + (byte~) main::$3) ← (signed word) main::j#2 -- pwsc1_derefidx_vbuz1=vwsz2 + ldy.z _3 + lda.z j + sta SCREEN,y + lda.z j+1 + sta SCREEN+1,y + // [10] (byte) main::i#1 ← ++ (byte) main::i#3 -- vbuz1=_inc_vbuz1 + inc.z i + // [11] (signed word) main::j#1 ← ++ (signed word) main::j#2 -- vwsz1=_inc_vwsz1 + inc.z j + bne !+ + inc.z j+1 + !: + // [12] (signed word~) main::$1 ← (signed word)(byte) main::i#1 -- vwsz1=_sword_vbuz2 + lda.z i + sta.z _1 + lda #0 + sta.z _1+1 + // [13] (signed word) main::k#0 ← (signed word~) main::$1 << (byte) 1 -- vwsz1=vwsz2_rol_1 + lda.z _1 + asl + sta.z k + lda.z _1+1 + rol + sta.z k+1 + // [14] (byte~) main::$4 ← (byte) main::i#1 << (byte) 1 -- vbuz1=vbuz2_rol_1 + lda.z i + asl + sta.z _4 + // [15] *((const signed word*) SCREEN#0 + (byte~) main::$4) ← (signed word) main::k#0 -- pwsc1_derefidx_vbuz1=vwsz2 + ldy.z _4 + lda.z k + sta SCREEN,y + lda.z k+1 + sta SCREEN+1,y + // [16] (byte) main::i#2 ← ++ (byte) main::i#1 -- vbuz1=_inc_vbuz1 + inc.z i + // [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + b1_from_b2: + // [5] phi (signed word) main::j#2 = (signed word) main::j#1 [phi:main::@2->main::@1#0] -- register_copy + // [5] phi (byte) main::i#3 = (byte) main::i#2 [phi:main::@2->main::@1#1] -- register_copy + jmp b1 +} + // File Data + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] if((byte) main::i#3<(byte) 4) goto main::@2 [ main::i#3 main::j#2 ] ( main:2 [ main::i#3 main::j#2 ] ) always clobbers reg byte a +Statement [8] (byte~) main::$3 ← (byte) main::i#3 << (byte) 1 [ main::i#3 main::j#2 main::$3 ] ( main:2 [ main::i#3 main::j#2 main::$3 ] ) always clobbers reg byte a +Statement [9] *((const signed word*) SCREEN#0 + (byte~) main::$3) ← (signed word) main::j#2 [ main::i#3 main::j#2 ] ( main:2 [ main::i#3 main::j#2 ] ) always clobbers reg byte a +Statement [12] (signed word~) main::$1 ← (signed word)(byte) main::i#1 [ main::j#1 main::i#1 main::$1 ] ( main:2 [ main::j#1 main::i#1 main::$1 ] ) always clobbers reg byte a +Statement [13] (signed word) main::k#0 ← (signed word~) main::$1 << (byte) 1 [ main::j#1 main::i#1 main::k#0 ] ( main:2 [ main::j#1 main::i#1 main::k#0 ] ) always clobbers reg byte a +Statement [14] (byte~) main::$4 ← (byte) main::i#1 << (byte) 1 [ main::j#1 main::i#1 main::k#0 main::$4 ] ( main:2 [ main::j#1 main::i#1 main::k#0 main::$4 ] ) always clobbers reg byte a +Statement [15] *((const signed word*) SCREEN#0 + (byte~) main::$4) ← (signed word) main::k#0 [ main::j#1 main::i#1 ] ( main:2 [ main::j#1 main::i#1 ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ main::i#3 main::i#2 ] : zp ZP_BYTE:2 , +Potential registers zp ZP_WORD:4 [ main::j#2 main::j#1 ] : zp ZP_WORD:4 , +Potential registers zp ZP_BYTE:3 [ main::$3 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:2 [ main::i#1 ] : zp ZP_BYTE:2 , +Potential registers zp ZP_WORD:6 [ main::$1 ] : zp ZP_WORD:6 , +Potential registers zp ZP_WORD:8 [ main::k#0 ] : zp ZP_WORD:8 , +Potential registers zp ZP_BYTE:10 [ main::$4 ] : zp ZP_BYTE:10 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 33: zp ZP_BYTE:2 [ main::i#3 main::i#2 ] 22: zp ZP_BYTE:3 [ main::$3 ] 22: zp ZP_WORD:6 [ main::$1 ] 22: zp ZP_BYTE:10 [ main::$4 ] 11: zp ZP_WORD:8 [ main::k#0 ] 10.27: zp ZP_WORD:4 [ main::j#2 main::j#1 ] 5.5: zp ZP_BYTE:2 [ main::i#1 ] +Uplift Scope [] + +Uplifting [main] best 1288 combination zp ZP_BYTE:2 [ main::i#3 main::i#2 ] reg byte a [ main::$3 ] zp ZP_WORD:6 [ main::$1 ] reg byte a [ main::$4 ] zp ZP_WORD:8 [ main::k#0 ] zp ZP_WORD:4 [ main::j#2 main::j#1 ] zp ZP_BYTE:2 [ main::i#1 ] +Uplifting [] best 1288 combination +Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#3 main::i#2 ] +Uplifting [main] best 1288 combination zp ZP_BYTE:2 [ main::i#3 main::i#2 ] +Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#1 ] +Uplifting [main] best 1288 combination zp ZP_BYTE:2 [ main::i#1 ] +Coalescing zero page register [ zp ZP_BYTE:2 [ main::i#3 main::i#2 ] ] with [ zp ZP_BYTE:2 [ main::i#1 ] ] - score: 2 +Coalescing zero page register [ zp ZP_WORD:6 [ main::$1 ] ] with [ zp ZP_WORD:8 [ main::k#0 ] ] - score: 1 + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test declaring a variable as register on a specific ZP address + // Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + // @begin +bbegin: + // [1] phi from @begin to @1 [phi:@begin->@1] +b1_from_bbegin: + jmp b1 + // @1 +b1: + // [2] call main + // [4] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main + // [3] phi from @1 to @end [phi:@1->@end] +bend_from_b1: + jmp bend + // @end +bend: + // main +main: { + .label _1 = 6 + .label i = 2 + .label j = 4 + .label k = 6 + // [5] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + // [5] phi (signed word) main::j#2 = (signed byte) 0 [phi:main->main::@1#0] -- vwsz1=vbsc1 + lda #<0 + sta.z j + lda #>0 + sta.z j+1 + // [5] phi (byte) main::i#3 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + lda #0 + sta.z i + jmp b1 + // main::@1 + b1: + // [6] if((byte) main::i#3<(byte) 4) goto main::@2 -- vbuz1_lt_vbuc1_then_la1 + lda.z i + cmp #4 + bcc b2 + jmp breturn + // main::@return + breturn: + // [7] return + rts + // main::@2 + b2: + // [8] (byte~) main::$3 ← (byte) main::i#3 << (byte) 1 -- vbuaa=vbuz1_rol_1 + lda.z i + asl + // [9] *((const signed word*) SCREEN#0 + (byte~) main::$3) ← (signed word) main::j#2 -- pwsc1_derefidx_vbuaa=vwsz1 + tay + lda.z j + sta SCREEN,y + lda.z j+1 + sta SCREEN+1,y + // [10] (byte) main::i#1 ← ++ (byte) main::i#3 -- vbuz1=_inc_vbuz1 + inc.z i + // [11] (signed word) main::j#1 ← ++ (signed word) main::j#2 -- vwsz1=_inc_vwsz1 + inc.z j + bne !+ + inc.z j+1 + !: + // [12] (signed word~) main::$1 ← (signed word)(byte) main::i#1 -- vwsz1=_sword_vbuz2 + lda.z i + sta.z _1 + lda #0 + sta.z _1+1 + // [13] (signed word) main::k#0 ← (signed word~) main::$1 << (byte) 1 -- vwsz1=vwsz1_rol_1 + asl.z k + rol.z k+1 + // [14] (byte~) main::$4 ← (byte) main::i#1 << (byte) 1 -- vbuaa=vbuz1_rol_1 + lda.z i + asl + // [15] *((const signed word*) SCREEN#0 + (byte~) main::$4) ← (signed word) main::k#0 -- pwsc1_derefidx_vbuaa=vwsz1 + tay + lda.z k + sta SCREEN,y + lda.z k+1 + sta SCREEN+1,y + // [16] (byte) main::i#2 ← ++ (byte) main::i#1 -- vbuz1=_inc_vbuz1 + inc.z i + // [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + b1_from_b2: + // [5] phi (signed word) main::j#2 = (signed word) main::j#1 [phi:main::@2->main::@1#0] -- register_copy + // [5] phi (byte) main::i#3 = (byte) main::i#2 [phi:main::@2->main::@1#1] -- register_copy + jmp b1 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #>0 +Removing instruction lda #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction b1_from_bbegin: +Removing instruction b1: +Removing instruction main_from_b1: +Removing instruction bend_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction breturn: +Removing instruction b1_from_b2: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(signed word*) SCREEN +(const signed word*) SCREEN#0 SCREEN = (signed word*) 1024 +(void()) main() +(signed word~) main::$1 $1 zp ZP_WORD:6 22.0 +(byte~) main::$3 reg byte a 22.0 +(byte~) main::$4 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i !zp ZP_BYTE:2 +(byte) main::i#1 i !zp ZP_BYTE:2 5.5 +(byte) main::i#2 i !zp ZP_BYTE:2 22.0 +(byte) main::i#3 i !zp ZP_BYTE:2 11.0 +(signed word) main::j !zp ZP_WORD:4 +(signed word) main::j#1 j !zp ZP_WORD:4 3.6666666666666665 +(signed word) main::j#2 j !zp ZP_WORD:4 6.6000000000000005 +(signed word) main::k +(signed word) main::k#0 k zp ZP_WORD:6 11.0 + +zp ZP_BYTE:2 [ main::i#3 main::i#2 main::i#1 ] +zp ZP_WORD:4 [ main::j#2 main::j#1 ] +reg byte a [ main::$3 ] +zp ZP_WORD:6 [ main::$1 main::k#0 ] +reg byte a [ main::$4 ] + + +FINAL ASSEMBLER +Score: 1116 + + // File Comments +// Test declaring a variable as register on a specific ZP address + // Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + // Global Constants & labels + .label SCREEN = $400 + // @begin + // [1] phi from @begin to @1 [phi:@begin->@1] + // @1 + // [2] call main + // [4] phi from @1 to main [phi:@1->main] + // [3] phi from @1 to @end [phi:@1->@end] + // @end + // main +main: { + .label _1 = 6 + .label i = 2 + .label j = 4 + .label k = 6 + // [5] phi from main to main::@1 [phi:main->main::@1] + // [5] phi (signed word) main::j#2 = (signed byte) 0 [phi:main->main::@1#0] -- vwsz1=vbsc1 + lda #<0 + sta.z j + sta.z j+1 + // [5] phi (byte) main::i#3 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + sta.z i + // main::@1 + b1: + // while(i<4) + // [6] if((byte) main::i#3<(byte) 4) goto main::@2 -- vbuz1_lt_vbuc1_then_la1 + lda.z i + cmp #4 + bcc b2 + // main::@return + // } + // [7] return + rts + // main::@2 + b2: + // SCREEN[i++] = j++ + // [8] (byte~) main::$3 ← (byte) main::i#3 << (byte) 1 -- vbuaa=vbuz1_rol_1 + lda.z i + asl + // [9] *((const signed word*) SCREEN#0 + (byte~) main::$3) ← (signed word) main::j#2 -- pwsc1_derefidx_vbuaa=vwsz1 + tay + lda.z j + sta SCREEN,y + lda.z j+1 + sta SCREEN+1,y + // SCREEN[i++] = j++; + // [10] (byte) main::i#1 ← ++ (byte) main::i#3 -- vbuz1=_inc_vbuz1 + inc.z i + // [11] (signed word) main::j#1 ← ++ (signed word) main::j#2 -- vwsz1=_inc_vwsz1 + inc.z j + bne !+ + inc.z j+1 + !: + // (int)i + // [12] (signed word~) main::$1 ← (signed word)(byte) main::i#1 -- vwsz1=_sword_vbuz2 + lda.z i + sta.z _1 + lda #0 + sta.z _1+1 + // k = (int)i*2 + // [13] (signed word) main::k#0 ← (signed word~) main::$1 << (byte) 1 -- vwsz1=vwsz1_rol_1 + asl.z k + rol.z k+1 + // SCREEN[i++] = k + // [14] (byte~) main::$4 ← (byte) main::i#1 << (byte) 1 -- vbuaa=vbuz1_rol_1 + lda.z i + asl + // [15] *((const signed word*) SCREEN#0 + (byte~) main::$4) ← (signed word) main::k#0 -- pwsc1_derefidx_vbuaa=vwsz1 + tay + lda.z k + sta SCREEN,y + lda.z k+1 + sta SCREEN+1,y + // SCREEN[i++] = k; + // [16] (byte) main::i#2 ← ++ (byte) main::i#1 -- vbuz1=_inc_vbuz1 + inc.z i + // [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + // [5] phi (signed word) main::j#2 = (signed word) main::j#1 [phi:main::@2->main::@1#0] -- register_copy + // [5] phi (byte) main::i#3 = (byte) main::i#2 [phi:main::@2->main::@1#1] -- register_copy + jmp b1 +} + // File Data + diff --git a/src/test/ref/var-register-zp.sym b/src/test/ref/var-register-zp.sym new file mode 100644 index 000000000..bb54e835b --- /dev/null +++ b/src/test/ref/var-register-zp.sym @@ -0,0 +1,27 @@ +(label) @1 +(label) @begin +(label) @end +(signed word*) SCREEN +(const signed word*) SCREEN#0 SCREEN = (signed word*) 1024 +(void()) main() +(signed word~) main::$1 $1 zp ZP_WORD:6 22.0 +(byte~) main::$3 reg byte a 22.0 +(byte~) main::$4 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::i !zp ZP_BYTE:2 +(byte) main::i#1 i !zp ZP_BYTE:2 5.5 +(byte) main::i#2 i !zp ZP_BYTE:2 22.0 +(byte) main::i#3 i !zp ZP_BYTE:2 11.0 +(signed word) main::j !zp ZP_WORD:4 +(signed word) main::j#1 j !zp ZP_WORD:4 3.6666666666666665 +(signed word) main::j#2 j !zp ZP_WORD:4 6.6000000000000005 +(signed word) main::k +(signed word) main::k#0 k zp ZP_WORD:6 11.0 + +zp ZP_BYTE:2 [ main::i#3 main::i#2 main::i#1 ] +zp ZP_WORD:4 [ main::j#2 main::j#1 ] +reg byte a [ main::$3 ] +zp ZP_WORD:6 [ main::$1 main::k#0 ] +reg byte a [ main::$4 ] diff --git a/src/test/ref/var-register.cfg b/src/test/ref/var-register.cfg index 8547f20c6..40f434dbe 100644 --- a/src/test/ref/var-register.cfg +++ b/src/test/ref/var-register.cfg @@ -15,10 +15,12 @@ main::@1: scope:[main] from main main::@5 to:main::@2 main::@2: scope:[main] from main::@1 main::@4 [6] (byte) main::y#4 ← phi( main::@1/(byte) 0 main::@4/(byte) main::y#1 ) + [6] (byte) main::x#4 ← phi( main::@1/(byte) main::x#7 main::@4/(byte) main::x#2 ) to:main::@3 main::@3: scope:[main] from main::@2 main::@6 + [7] (byte) main::x#2 ← phi( main::@2/(byte) main::x#4 main::@6/(byte) main::x#2 ) [7] (byte) main::a#2 ← phi( main::@2/(byte) 0 main::@6/(byte) main::a#1 ) - [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#7 + [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#2 [9] (byte) print::idx#0 ← (byte) main::y#4 [10] (byte) print::val#0 ← (byte) main::val1#0 [11] call print @@ -32,15 +34,16 @@ main::@4: scope:[main] from main::@6 [15] if((byte) main::y#1!=(byte) $65) goto main::@2 to:main::@5 main::@5: scope:[main] from main::@4 - [16] (byte) main::x#1 ← ++ (byte) main::x#7 + [16] (byte) main::x#1 ← ++ (byte) main::x#2 [17] if((byte) main::x#1!=(byte) $65) goto main::@1 to:main::@return main::@return: scope:[main] from main::@5 [18] return to:@return print: scope:[print] from main::@3 - [19] *((const byte*) print::SCREEN#0 + (byte) print::idx#0) ← (byte) print::val#0 + [19] (byte) print::idx#1 ← phi( main::@3/(byte) print::idx#0 ) + [20] *((const byte*) print::SCREEN#0 + (byte) print::idx#1) ← (byte) print::val#0 to:print::@return print::@return: scope:[print] from print - [20] return + [21] return to:@return diff --git a/src/test/ref/var-register.log b/src/test/ref/var-register.log index 8994755f6..a2a336316 100644 --- a/src/test/ref/var-register.log +++ b/src/test/ref/var-register.log @@ -127,12 +127,8 @@ Alias (byte) main::a#2 = (byte) main::a#3 Alias (byte) main::x#2 = (byte) main::x#5 (byte) main::x#6 (byte) main::x#3 Alias (byte) main::y#2 = (byte) main::y#5 (byte) main::y#3 Successful SSA optimization Pass2AliasElimination -Identical Phi Values (byte) main::x#2 (byte) main::x#4 Identical Phi Values (byte) main::y#2 (byte) main::y#4 Identical Phi Values (byte) print::val#1 (byte) print::val#0 -Identical Phi Values (byte) print::idx#1 (byte) print::idx#0 -Successful SSA optimization Pass2IdenticalPhiElimination -Identical Phi Values (byte) main::x#4 (byte) main::x#7 Successful SSA optimization Pass2IdenticalPhiElimination Simple Condition (bool~) main::$2 [14] if((byte) main::a#1!=rangelast(0,$64)) goto main::@3 Simple Condition (bool~) main::$3 [18] if((byte) main::y#1!=rangelast(0,$64)) goto main::@2 @@ -147,7 +143,7 @@ Resolved ranged next value [12] main::a#1 ← ++ main::a#2 to ++ Resolved ranged comparison value [14] if(main::a#1!=rangelast(0,$64)) goto main::@3 to (number) $65 Resolved ranged next value [16] main::y#1 ← ++ main::y#4 to ++ Resolved ranged comparison value [18] if(main::y#1!=rangelast(0,$64)) goto main::@2 to (number) $65 -Resolved ranged next value [20] main::x#1 ← ++ main::x#7 to ++ +Resolved ranged next value [20] main::x#1 ← ++ main::x#2 to ++ Resolved ranged comparison value [22] if(main::x#1!=rangelast(0,$64)) goto main::@1 to (number) $65 Adding number conversion cast (unumber) $65 in if((byte) main::a#1!=(number) $65) goto main::@3 Adding number conversion cast (unumber) $65 in if((byte) main::y#1!=(number) $65) goto main::@2 @@ -178,13 +174,18 @@ Adding NOP phi() at start of @end Adding NOP phi() at start of main CALL GRAPH Calls in [] to main:2 -Calls in [main] to print:12 +Calls in [main] to print:15 -Created 3 initial phi equivalence classes -Coalesced [20] main::x#8 ← main::x#1 -Coalesced [21] main::y#6 ← main::y#1 -Coalesced [22] main::a#4 ← main::a#1 -Coalesced down to 3 phi equivalence classes +Created 6 initial phi equivalence classes +Coalesced [7] main::x#9 ← main::x#7 +Coalesced [9] main::x#11 ← main::x#4 +Coalesced [14] print::idx#2 ← print::idx#0 +Coalesced [23] main::x#8 ← main::x#1 +Coalesced (already) [24] main::x#10 ← main::x#2 +Coalesced [25] main::y#6 ← main::y#1 +Coalesced [26] main::a#4 ← main::a#1 +Coalesced (already) [27] main::x#12 ← main::x#2 +Coalesced down to 4 phi equivalence classes Culled Empty Block (label) @3 Culled Empty Block (label) main::@8 Culled Empty Block (label) main::@9 @@ -214,10 +215,12 @@ main::@1: scope:[main] from main main::@5 to:main::@2 main::@2: scope:[main] from main::@1 main::@4 [6] (byte) main::y#4 ← phi( main::@1/(byte) 0 main::@4/(byte) main::y#1 ) + [6] (byte) main::x#4 ← phi( main::@1/(byte) main::x#7 main::@4/(byte) main::x#2 ) to:main::@3 main::@3: scope:[main] from main::@2 main::@6 + [7] (byte) main::x#2 ← phi( main::@2/(byte) main::x#4 main::@6/(byte) main::x#2 ) [7] (byte) main::a#2 ← phi( main::@2/(byte) 0 main::@6/(byte) main::a#1 ) - [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#7 + [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#2 [9] (byte) print::idx#0 ← (byte) main::y#4 [10] (byte) print::val#0 ← (byte) main::val1#0 [11] call print @@ -231,17 +234,18 @@ main::@4: scope:[main] from main::@6 [15] if((byte) main::y#1!=(byte) $65) goto main::@2 to:main::@5 main::@5: scope:[main] from main::@4 - [16] (byte) main::x#1 ← ++ (byte) main::x#7 + [16] (byte) main::x#1 ← ++ (byte) main::x#2 [17] if((byte) main::x#1!=(byte) $65) goto main::@1 to:main::@return main::@return: scope:[main] from main::@5 [18] return to:@return print: scope:[print] from main::@3 - [19] *((const byte*) print::SCREEN#0 + (byte) print::idx#0) ← (byte) print::val#0 + [19] (byte) print::idx#1 ← phi( main::@3/(byte) print::idx#0 ) + [20] *((const byte*) print::SCREEN#0 + (byte) print::idx#1) ← (byte) print::val#0 to:print::@return print::@return: scope:[print] from print - [20] return + [21] return to:@return @@ -254,30 +258,33 @@ VARIABLE REGISTER WEIGHTS (byte) main::val1#0 !reg byte a 1001.0 (byte) main::x !reg byte y (byte) main::x#1 !reg byte y 16.5 -(byte) main::x#7 !reg byte y 93.0 +(byte) main::x#2 !reg byte y 357.33333333333337 +(byte) main::x#4 !reg byte y 213.0 +(byte) main::x#7 !reg byte y 22.0 (byte) main::y (byte) main::y#1 151.5 (byte) main::y#4 150.375 (void()) print((byte) print::idx , (byte) print::val) (byte*) print::SCREEN (byte) print::idx !reg byte x -(byte) print::idx#0 !reg byte x 501.5 +(byte) print::idx#0 !reg byte x 1001.0 +(byte) print::idx#1 !reg byte x 1003.0 (byte) print::val -(byte) print::val#0 1003.0 +(byte) print::val#0 501.5 Initial phi equivalence classes -[ main::x#7 main::x#1 ] +[ main::x#4 main::x#7 main::x#1 main::x#2 ] [ main::y#4 main::y#1 ] [ main::a#2 main::a#1 ] +[ print::idx#1 print::idx#0 ] Added variable main::val1#0 to zero page equivalence class [ main::val1#0 ] -Added variable print::idx#0 to zero page equivalence class [ print::idx#0 ] Added variable print::val#0 to zero page equivalence class [ print::val#0 ] Complete equivalence classes -[ main::x#7 main::x#1 ] +[ main::x#4 main::x#7 main::x#1 main::x#2 ] [ main::y#4 main::y#1 ] [ main::a#2 main::a#1 ] +[ print::idx#1 print::idx#0 ] [ main::val1#0 ] -[ print::idx#0 ] [ print::val#0 ] Allocated zp ZP_BYTE:2 [ main::y#4 main::y#1 ] Allocated zp ZP_BYTE:3 [ main::a#2 main::a#1 ] @@ -327,26 +334,30 @@ main: { // [6] phi (byte) main::y#4 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 lda #0 sta.z y + // [6] phi (byte) main::x#4 = (byte) main::x#7 [phi:main::@1->main::@2#1] -- register_copy jmp b2 // [6] phi from main::@4 to main::@2 [phi:main::@4->main::@2] b2_from_b4: // [6] phi (byte) main::y#4 = (byte) main::y#1 [phi:main::@4->main::@2#0] -- register_copy + // [6] phi (byte) main::x#4 = (byte) main::x#2 [phi:main::@4->main::@2#1] -- register_copy jmp b2 // main::@2 b2: // [7] phi from main::@2 to main::@3 [phi:main::@2->main::@3] b3_from_b2: - // [7] phi (byte) main::a#2 = (byte) 0 [phi:main::@2->main::@3#0] -- vbuz1=vbuc1 + // [7] phi (byte) main::x#2 = (byte) main::x#4 [phi:main::@2->main::@3#0] -- register_copy + // [7] phi (byte) main::a#2 = (byte) 0 [phi:main::@2->main::@3#1] -- vbuz1=vbuc1 lda #0 sta.z a jmp b3 // [7] phi from main::@6 to main::@3 [phi:main::@6->main::@3] b3_from_b6: - // [7] phi (byte) main::a#2 = (byte) main::a#1 [phi:main::@6->main::@3#0] -- register_copy + // [7] phi (byte) main::x#2 = (byte) main::x#2 [phi:main::@6->main::@3#0] -- register_copy + // [7] phi (byte) main::a#2 = (byte) main::a#1 [phi:main::@6->main::@3#1] -- register_copy jmp b3 // main::@3 b3: - // [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#7 -- vbuaa=vbuz1_plus_vbuyy + // [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#2 -- vbuaa=vbuz1_plus_vbuyy tya clc adc.z a @@ -355,6 +366,9 @@ main: { // [10] (byte) print::val#0 ← (byte) main::val1#0 -- vbuz1=vbuaa sta.z print.val // [11] call print + // [19] phi from main::@3 to print [phi:main::@3->print] + print_from_b3: + // [19] phi (byte) print::idx#1 = (byte) print::idx#0 [phi:main::@3->print#0] -- register_copy jsr print jmp b6 // main::@6 @@ -377,7 +391,7 @@ main: { jmp b5 // main::@5 b5: - // [16] (byte) main::x#1 ← ++ (byte) main::x#7 -- vbuyy=_inc_vbuyy + // [16] (byte) main::x#1 ← ++ (byte) main::x#2 -- vbuyy=_inc_vbuyy iny // [17] if((byte) main::x#1!=(byte) $65) goto main::@1 -- vbuyy_neq_vbuc1_then_la1 cpy #$65 @@ -393,41 +407,41 @@ main: { print: { .label SCREEN = $400 .label val = 4 - // [19] *((const byte*) print::SCREEN#0 + (byte) print::idx#0) ← (byte) print::val#0 -- pbuc1_derefidx_vbuxx=vbuz1 + // [20] *((const byte*) print::SCREEN#0 + (byte) print::idx#1) ← (byte) print::val#0 -- pbuc1_derefidx_vbuxx=vbuz1 lda.z val sta SCREEN,x jmp breturn // print::@return breturn: - // [20] return + // [21] return rts } // File Data REGISTER UPLIFT POTENTIAL REGISTERS -Statement [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#7 [ main::x#7 main::y#4 main::a#2 main::val1#0 ] ( main:2 [ main::x#7 main::y#4 main::a#2 main::val1#0 ] ) always clobbers reg byte a +Statement [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#2 [ main::y#4 main::x#2 main::a#2 main::val1#0 ] ( main:2 [ main::y#4 main::x#2 main::a#2 main::val1#0 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::y#4 main::y#1 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::a#2 main::a#1 ] -Statement [16] (byte) main::x#1 ← ++ (byte) main::x#7 [ main::x#1 ] ( main:2 [ main::x#1 ] ) always clobbers reg byte y -Statement [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#7 [ main::x#7 main::y#4 main::a#2 main::val1#0 ] ( main:2 [ main::x#7 main::y#4 main::a#2 main::val1#0 ] ) always clobbers reg byte a -Statement [16] (byte) main::x#1 ← ++ (byte) main::x#7 [ main::x#1 ] ( main:2 [ main::x#1 ] ) always clobbers reg byte y -Potential registers reg byte y [ main::x#7 main::x#1 ] : reg byte y , +Statement [16] (byte) main::x#1 ← ++ (byte) main::x#2 [ main::x#1 ] ( main:2 [ main::x#1 ] ) always clobbers reg byte y +Statement [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#2 [ main::y#4 main::x#2 main::a#2 main::val1#0 ] ( main:2 [ main::y#4 main::x#2 main::a#2 main::val1#0 ] ) always clobbers reg byte a +Statement [16] (byte) main::x#1 ← ++ (byte) main::x#2 [ main::x#1 ] ( main:2 [ main::x#1 ] ) always clobbers reg byte y +Potential registers reg byte y [ main::x#4 main::x#7 main::x#1 main::x#2 ] : reg byte y , Potential registers zp ZP_BYTE:2 [ main::y#4 main::y#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , Potential registers zp ZP_BYTE:3 [ main::a#2 main::a#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Potential registers reg byte x [ print::idx#1 print::idx#0 ] : reg byte x , Potential registers reg byte a [ main::val1#0 ] : reg byte a , -Potential registers reg byte x [ print::idx#0 ] : reg byte x , Potential registers zp ZP_BYTE:4 [ print::val#0 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , REGISTER UPLIFT SCOPES -Uplift Scope [main] 2,102.1: zp ZP_BYTE:3 [ main::a#2 main::a#1 ] 1,001: reg byte a [ main::val1#0 ] 301.88: zp ZP_BYTE:2 [ main::y#4 main::y#1 ] 109.5: reg byte y [ main::x#7 main::x#1 ] -Uplift Scope [print] 1,003: zp ZP_BYTE:4 [ print::val#0 ] 501.5: reg byte x [ print::idx#0 ] +Uplift Scope [main] 2,102.1: zp ZP_BYTE:3 [ main::a#2 main::a#1 ] 1,001: reg byte a [ main::val1#0 ] 608.83: reg byte y [ main::x#4 main::x#7 main::x#1 main::x#2 ] 301.88: zp ZP_BYTE:2 [ main::y#4 main::y#1 ] +Uplift Scope [print] 2,004: reg byte x [ print::idx#1 print::idx#0 ] 501.5: zp ZP_BYTE:4 [ print::val#0 ] Uplift Scope [] -Uplifting [main] best 47460 combination zp ZP_BYTE:3 [ main::a#2 main::a#1 ] reg byte a [ main::val1#0 ] reg byte x [ main::y#4 main::y#1 ] reg byte y [ main::x#7 main::x#1 ] -Uplifting [print] best 44457 combination reg byte a [ print::val#0 ] reg byte x [ print::idx#0 ] -Uplifting [] best 44457 combination +Uplifting [main] best 38469 combination zp ZP_BYTE:3 [ main::a#2 main::a#1 ] reg byte a [ main::val1#0 ] reg byte y [ main::x#4 main::x#7 main::x#1 main::x#2 ] reg byte x [ main::y#4 main::y#1 ] +Uplifting [print] best 35466 combination reg byte x [ print::idx#1 print::idx#0 ] reg byte a [ print::val#0 ] +Uplifting [] best 35466 combination Attempting to uplift remaining variables inzp ZP_BYTE:3 [ main::a#2 main::a#1 ] -Uplifting [main] best 44457 combination zp ZP_BYTE:3 [ main::a#2 main::a#1 ] +Uplifting [main] best 35466 combination zp ZP_BYTE:3 [ main::a#2 main::a#1 ] Allocated (was zp ZP_BYTE:3) zp ZP_BYTE:2 [ main::a#2 main::a#1 ] ASSEMBLER BEFORE OPTIMIZATION @@ -471,32 +485,39 @@ main: { b2_from_b1: // [6] phi (byte) main::y#4 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 ldx #0 + // [6] phi (byte) main::x#4 = (byte) main::x#7 [phi:main::@1->main::@2#1] -- register_copy jmp b2 // [6] phi from main::@4 to main::@2 [phi:main::@4->main::@2] b2_from_b4: // [6] phi (byte) main::y#4 = (byte) main::y#1 [phi:main::@4->main::@2#0] -- register_copy + // [6] phi (byte) main::x#4 = (byte) main::x#2 [phi:main::@4->main::@2#1] -- register_copy jmp b2 // main::@2 b2: // [7] phi from main::@2 to main::@3 [phi:main::@2->main::@3] b3_from_b2: - // [7] phi (byte) main::a#2 = (byte) 0 [phi:main::@2->main::@3#0] -- vbuz1=vbuc1 + // [7] phi (byte) main::x#2 = (byte) main::x#4 [phi:main::@2->main::@3#0] -- register_copy + // [7] phi (byte) main::a#2 = (byte) 0 [phi:main::@2->main::@3#1] -- vbuz1=vbuc1 lda #0 sta.z a jmp b3 // [7] phi from main::@6 to main::@3 [phi:main::@6->main::@3] b3_from_b6: - // [7] phi (byte) main::a#2 = (byte) main::a#1 [phi:main::@6->main::@3#0] -- register_copy + // [7] phi (byte) main::x#2 = (byte) main::x#2 [phi:main::@6->main::@3#0] -- register_copy + // [7] phi (byte) main::a#2 = (byte) main::a#1 [phi:main::@6->main::@3#1] -- register_copy jmp b3 // main::@3 b3: - // [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#7 -- vbuaa=vbuz1_plus_vbuyy + // [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#2 -- vbuaa=vbuz1_plus_vbuyy tya clc adc.z a // [9] (byte) print::idx#0 ← (byte) main::y#4 // [10] (byte) print::val#0 ← (byte) main::val1#0 // [11] call print + // [19] phi from main::@3 to print [phi:main::@3->print] + print_from_b3: + // [19] phi (byte) print::idx#1 = (byte) print::idx#0 [phi:main::@3->print#0] -- register_copy jsr print jmp b6 // main::@6 @@ -518,7 +539,7 @@ main: { jmp b5 // main::@5 b5: - // [16] (byte) main::x#1 ← ++ (byte) main::x#7 -- vbuyy=_inc_vbuyy + // [16] (byte) main::x#1 ← ++ (byte) main::x#2 -- vbuyy=_inc_vbuyy iny // [17] if((byte) main::x#1!=(byte) $65) goto main::@1 -- vbuyy_neq_vbuc1_then_la1 cpy #$65 @@ -533,12 +554,12 @@ main: { // print(byte register(X) idx, byte register(A) val) print: { .label SCREEN = $400 - // [19] *((const byte*) print::SCREEN#0 + (byte) print::idx#0) ← (byte) print::val#0 -- pbuc1_derefidx_vbuxx=vbuaa + // [20] *((const byte*) print::SCREEN#0 + (byte) print::idx#1) ← (byte) print::val#0 -- pbuc1_derefidx_vbuxx=vbuaa sta SCREEN,x jmp breturn // print::@return breturn: - // [20] return + // [21] return rts } // File Data @@ -570,6 +591,7 @@ Removing instruction b3_from_b6: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: Removing instruction b1_from_main: +Removing instruction print_from_b3: Removing instruction b6: Removing instruction b4: Removing instruction b5: @@ -605,7 +627,9 @@ FINAL SYMBOL TABLE (byte) main::val1#0 !reg byte a 1001.0 (byte) main::x !reg byte y (byte) main::x#1 !reg byte y 16.5 -(byte) main::x#7 !reg byte y 93.0 +(byte) main::x#2 !reg byte y 357.33333333333337 +(byte) main::x#4 !reg byte y 213.0 +(byte) main::x#7 !reg byte y 22.0 (byte) main::y (byte) main::y#1 reg byte x 151.5 (byte) main::y#4 reg byte x 150.375 @@ -614,20 +638,21 @@ FINAL SYMBOL TABLE (byte*) print::SCREEN (const byte*) print::SCREEN#0 SCREEN = (byte*) 1024 (byte) print::idx !reg byte x -(byte) print::idx#0 !reg byte x 501.5 +(byte) print::idx#0 !reg byte x 1001.0 +(byte) print::idx#1 !reg byte x 1003.0 (byte) print::val -(byte) print::val#0 reg byte a 1003.0 +(byte) print::val#0 reg byte a 501.5 -reg byte y [ main::x#7 main::x#1 ] +reg byte y [ main::x#4 main::x#7 main::x#1 main::x#2 ] reg byte x [ main::y#4 main::y#1 ] zp ZP_BYTE:2 [ main::a#2 main::a#1 ] +reg byte x [ print::idx#1 print::idx#0 ] reg byte a [ main::val1#0 ] -reg byte x [ print::idx#0 ] reg byte a [ print::val#0 ] FINAL ASSEMBLER -Score: 31452 +Score: 25458 // File Comments // Upstart @@ -655,20 +680,24 @@ main: { // [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] // [6] phi (byte) main::y#4 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1 ldx #0 + // [6] phi (byte) main::x#4 = (byte) main::x#7 [phi:main::@1->main::@2#1] -- register_copy // [6] phi from main::@4 to main::@2 [phi:main::@4->main::@2] // [6] phi (byte) main::y#4 = (byte) main::y#1 [phi:main::@4->main::@2#0] -- register_copy + // [6] phi (byte) main::x#4 = (byte) main::x#2 [phi:main::@4->main::@2#1] -- register_copy // main::@2 b2: // [7] phi from main::@2 to main::@3 [phi:main::@2->main::@3] - // [7] phi (byte) main::a#2 = (byte) 0 [phi:main::@2->main::@3#0] -- vbuz1=vbuc1 + // [7] phi (byte) main::x#2 = (byte) main::x#4 [phi:main::@2->main::@3#0] -- register_copy + // [7] phi (byte) main::a#2 = (byte) 0 [phi:main::@2->main::@3#1] -- vbuz1=vbuc1 lda #0 sta.z a // [7] phi from main::@6 to main::@3 [phi:main::@6->main::@3] - // [7] phi (byte) main::a#2 = (byte) main::a#1 [phi:main::@6->main::@3#0] -- register_copy + // [7] phi (byte) main::x#2 = (byte) main::x#2 [phi:main::@6->main::@3#0] -- register_copy + // [7] phi (byte) main::a#2 = (byte) main::a#1 [phi:main::@6->main::@3#1] -- register_copy // main::@3 b3: // val1 = a+x - // [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#7 -- vbuaa=vbuz1_plus_vbuyy + // [8] (byte) main::val1#0 ← (byte) main::a#2 + (byte) main::x#2 -- vbuaa=vbuz1_plus_vbuyy tya clc adc.z a @@ -676,6 +705,8 @@ main: { // [9] (byte) print::idx#0 ← (byte) main::y#4 // [10] (byte) print::val#0 ← (byte) main::val1#0 // [11] call print + // [19] phi from main::@3 to print [phi:main::@3->print] + // [19] phi (byte) print::idx#1 = (byte) print::idx#0 [phi:main::@3->print#0] -- register_copy jsr print // main::@6 // for( byte a: 0..100 ) @@ -694,7 +725,7 @@ main: { bne b2 // main::@5 // for( register(Y) byte x: 0..100 ) - // [16] (byte) main::x#1 ← ++ (byte) main::x#7 -- vbuyy=_inc_vbuyy + // [16] (byte) main::x#1 ← ++ (byte) main::x#2 -- vbuyy=_inc_vbuyy iny // [17] if((byte) main::x#1!=(byte) $65) goto main::@1 -- vbuyy_neq_vbuc1_then_la1 cpy #$65 @@ -709,11 +740,11 @@ main: { print: { .label SCREEN = $400 // SCREEN[idx] = val - // [19] *((const byte*) print::SCREEN#0 + (byte) print::idx#0) ← (byte) print::val#0 -- pbuc1_derefidx_vbuxx=vbuaa + // [20] *((const byte*) print::SCREEN#0 + (byte) print::idx#1) ← (byte) print::val#0 -- pbuc1_derefidx_vbuxx=vbuaa sta SCREEN,x // print::@return // } - // [20] return + // [21] return rts } // File Data diff --git a/src/test/ref/var-register.sym b/src/test/ref/var-register.sym index cfcaa5b5c..57d3a084f 100644 --- a/src/test/ref/var-register.sym +++ b/src/test/ref/var-register.sym @@ -16,7 +16,9 @@ (byte) main::val1#0 !reg byte a 1001.0 (byte) main::x !reg byte y (byte) main::x#1 !reg byte y 16.5 -(byte) main::x#7 !reg byte y 93.0 +(byte) main::x#2 !reg byte y 357.33333333333337 +(byte) main::x#4 !reg byte y 213.0 +(byte) main::x#7 !reg byte y 22.0 (byte) main::y (byte) main::y#1 reg byte x 151.5 (byte) main::y#4 reg byte x 150.375 @@ -25,13 +27,14 @@ (byte*) print::SCREEN (const byte*) print::SCREEN#0 SCREEN = (byte*) 1024 (byte) print::idx !reg byte x -(byte) print::idx#0 !reg byte x 501.5 +(byte) print::idx#0 !reg byte x 1001.0 +(byte) print::idx#1 !reg byte x 1003.0 (byte) print::val -(byte) print::val#0 reg byte a 1003.0 +(byte) print::val#0 reg byte a 501.5 -reg byte y [ main::x#7 main::x#1 ] +reg byte y [ main::x#4 main::x#7 main::x#1 main::x#2 ] reg byte x [ main::y#4 main::y#1 ] zp ZP_BYTE:2 [ main::a#2 main::a#1 ] +reg byte x [ print::idx#1 print::idx#0 ] reg byte a [ main::val1#0 ] -reg byte x [ print::idx#0 ] reg byte a [ print::val#0 ]