1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-01 02:29:30 +00:00

Added support for allocating specific zeropage addresses for variables using the register(0x12) directive. This also includes function parameters making it possible to the calling convention pretty well. Closes #287

This commit is contained in:
jespergravgaard 2019-08-29 22:52:58 +02:00
parent 67157f0a70
commit 8c56181554
23 changed files with 2207 additions and 350 deletions

View File

@ -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<Number> reservedZps;
private List<Integer> reservedZps;
/** Resource files that should be copied to the output folder to be compiled with the generated ASM. PASS 0-5 (STATIC) */
private List<Path> 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<Number> reservedZp) {
for(Number zp : reservedZp) {
public void addReservedZps(List<Integer> reservedZp) {
for(Integer zp : reservedZp) {
if(!this.reservedZps.contains(zp)) {
this.reservedZps.add(zp);
}
}
}
public List<Number> getReservedZps() {
public List<Integer> getReservedZps() {
return reservedZps;
}

View File

@ -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 {

View File

@ -24,7 +24,7 @@ public class Procedure extends Scope {
/** Comments preceding the procedure in the source code. */
private List<Comment> comments;
/** Reserved zeropage addresses. */
private List<Number> reservedZps;
private List<Integer> 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<Number> getReservedZps() {
public List<Integer> 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<Number> reservedZps) {
public void setReservedZps(List<Integer> reservedZps) {
this.reservedZps = reservedZps;
}

View File

@ -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

View File

@ -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 {

View File

@ -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<Objec
@Override
public Object visitGlobalDirectiveReserve(KickCParser.GlobalDirectiveReserveContext ctx) {
List<Number> reservedZps = new ArrayList<>();
List<Integer> 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 KickCParserBaseVisitor<Objec
throw new CompileError("Error! Unknown register " + directiveRegister.getName(), source);
}
lValue.setDeclaredRegister(register);
} else if(directiveRegister.getAddress() != null) {
// Allocate to specific address
Long address = ((DirectiveRegister) directive).address;
if(address>255) {
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<Objec
@Override
public Directive visitDirectiveRegister(KickCParser.DirectiveRegisterContext ctx) {
String name = null;
if(ctx.NAME() != null) {
name = ctx.NAME().getText();
return new DirectiveRegister(ctx.NAME().getText());
} else if(ctx.NUMBER() != null) {
try {
ConstantInteger registerAddress = NumberParser.parseIntegerLiteral(ctx.NUMBER().getText());
return new DirectiveRegister(registerAddress.getInteger());
} catch(NumberFormatException e) {
throw new CompileError(e.getMessage(), new StatementSource(ctx));
}
} else {
return new DirectiveRegister(null);
}
return new DirectiveRegister(name);
}
@Override
@ -772,9 +792,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
@Override
public Directive visitDirectiveReserveZp(KickCParser.DirectiveReserveZpContext ctx) {
List<Number> reservedZps = new ArrayList<>();
List<Integer> 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<Objec
Label continueLabel;
if(currentLoop.isSwitch) {
continueLabel = currentLoop.getContinueLabel();
if(continueLabel==null) {
if(continueLabel == null) {
throw new CompileError("Continue not inside a loop! ", new StatementSource(ctx));
}
} else {
} else {
continueLabel = currentLoop.getOrCreateContinueLabel();
}
Statement continueJmpStmt = new StatementJump(continueLabel.getRef(), new StatementSource(ctx), Comment.NO_COMMENTS);
@ -1545,11 +1565,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
/** RValues that have not yet been output as part of a statement.
/**
* RValues that have not yet been output as part of a statement.
* The expression visitor methods updates this so that the surrounding
* statement can make sure to output any rValue that has not been output.
* Null if we are not currently monitoring this.
* */
*/
public Set<RValue> exprNotConsumed = null;
/**
@ -1569,24 +1590,27 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
/**
* Consumes an RValue by outputting it as part of a statement.
* This helps ensure that all expression RValues are output in statements
*
* @param rValue The RValue being consume
*/
void consumeExpr(RValue rValue) {
if(exprNotConsumed!=null)
if(exprNotConsumed != null)
exprNotConsumed.remove(rValue);
}
/**
* Marks an expression that has been produced which has not been output as part of a statement.
* When the RValue is output in a statement it will be consumed using {@link #consumeExpr(RValue)}.
*
* @param rValue The RValue that has been produced but not consumed
*/
void addExprToConsume(RValue rValue) {
if(exprNotConsumed!=null)
if(exprNotConsumed != null)
exprNotConsumed.add(rValue);
}
/** Examines whether an RValue is in the list of non-consumed RValues.
/**
* Examines whether an RValue is in the list of non-consumed RValues.
*
* @return true if the RValue is in the list
*/
@ -2133,32 +2157,39 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
}
/** Variable memory alignment. */
/** Variable register allocation. */
private static class DirectiveRegister implements Directive {
/** Name of register to use for the variable */
private String name;
/** Address to use as register for the variable */
private Long address;
public DirectiveRegister(String name) {
this.name = name;
}
public DirectiveRegister(long address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
public Long getAddress() {
return address;
}
}
/** Reservation of zero-page addresses */
private static class DirectiveReserveZp implements Directive {
List<Number> reservedZp;
List<Integer> reservedZp;
public DirectiveReserveZp(List<Number> reservedZp) {
public DirectiveReserveZp(List<Integer> reservedZp) {
this.reservedZp = reservedZp;
}
public List<Number> getReservedZp() {
public List<Integer> getReservedZp() {
return reservedZp;
}

View File

@ -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;
}
}
}

View File

@ -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<Number> reservedZp;
private List<Integer> 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<Number> procedureReservedZps = procedure.getReservedZps();
List<Integer> 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;i<sizeBytes; i++) {
if(!reservedZp.contains(zp+i))
this.reservedZp.add(zp+i);
}
}
}
}
public void allocate(boolean reallocateZp) {
@ -43,15 +56,25 @@ public class Pass4RegistersFinalize extends Pass2Base {
for(LiveRangeEquivalenceClass equivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
for(VariableRef variableRef : equivalenceClass.getVariables()) {
Variable variable = getProgram().getScope().getVariable(variableRef);
if(variable.getDeclaredRegister()!=null) {
if(equivalenceClass.getRegister()!=null && !variable.getDeclaredRegister().equals(equivalenceClass.getRegister())) {
Registers.Register declaredRegister = variable.getDeclaredRegister();
if(declaredRegister !=null) {
if(declaredRegister instanceof Registers.RegisterZpDeclared) {
if(declaredRegister.getType().equals(Registers.RegisterType.ZP_VAR)) {
Registers.RegisterType registerType = getRegisterType(variable);
((Registers.RegisterZpDeclared) declaredRegister).setType(registerType);
getLog().append("Setting declared register type "+variable.toString(getProgram())+" to "+registerType);
}
}
if(equivalenceClass.getRegister()!=null && !declaredRegister.equals(equivalenceClass.getRegister())) {
throw new CompileError("Equivalence class has variables with different declared registers \n" +
" - equivalence class: " + equivalenceClass.toString(true) + "\n" +
" - one register: " + equivalenceClass.getRegister().toString() + "\n" +
" - other register: " + variable.getDeclaredRegister().toString()
" - other register: " + declaredRegister.toString()
);
}
equivalenceClass.setRegister(variable.getDeclaredRegister());
equivalenceClass.setRegister(declaredRegister);
}
}
}
@ -148,7 +171,17 @@ public class Pass4RegistersFinalize extends Pass2Base {
private void reallocateZpRegisters(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet) {
for(LiveRangeEquivalenceClass equivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
Registers.Register register = equivalenceClass.getRegister();
if(register == null || register.isZp()) {
boolean reallocate = true;
if(register!=null) {
if(!register.isZp()) {
// Do not allocate non-ZP registers
reallocate = false;
} else if(register instanceof Registers.RegisterZpDeclared) {
// Do not allocate declared ZP registers
reallocate = false;
}
}
if(reallocate) {
String before = register == null ? null : register.toString();
VariableRef variableRef = equivalenceClass.getVariables().get(0);
Variable variable = getProgram().getSymbolInfos().getVariable(variableRef);
@ -174,7 +207,7 @@ public class Pass4RegistersFinalize extends Pass2Base {
reserved = false;
int candidateZp = currentZp;
for(int i=0;i<size;i++) {
if(reservedZp.contains(new Long(candidateZp+i))) {
if(reservedZp.contains(new Integer(candidateZp+i))) {
reserved = true;
currentZp++;
break;
@ -234,5 +267,41 @@ public class Pass4RegistersFinalize extends Pass2Base {
}
}
/**
* Get the register type for a specific variable type.
*
* @param variable The variable to create a register for.
* The register type based on the variable type
* @return The zeropage register type
*/
private Registers.RegisterType getRegisterType(Variable variable) {
SymbolType varType = variable.getType();
if(SymbolType.BYTE.equals(varType)) {
return Registers.RegisterType.ZP_BYTE;
} else if(SymbolType.SBYTE.equals(varType)) {
return Registers.RegisterType.ZP_BYTE;
} else if(SymbolType.WORD.equals(varType)) {
return Registers.RegisterType.ZP_WORD;
} else if(SymbolType.SWORD.equals(varType)) {
return Registers.RegisterType.ZP_WORD;
} else if(SymbolType.DWORD.equals(varType)) {
return Registers.RegisterType.ZP_DWORD;
} else if(SymbolType.SDWORD.equals(varType)) {
return Registers.RegisterType.ZP_DWORD;
} else if(varType.equals(SymbolType.BOOLEAN)) {
return Registers.RegisterType.ZP_BOOL;
} else if(varType.equals(SymbolType.VOID)) {
// No need to register for VOID value
return null;
} else if(varType instanceof SymbolTypePointer) {
return Registers.RegisterType.ZP_WORD;
} else if(varType instanceof SymbolTypeStruct) {
return Registers.RegisterType.ZP_STRUCT;
} else {
throw new RuntimeException("Unhandled variable type " + varType);
}
}
}

View File

@ -2487,6 +2487,21 @@ public class TestPrograms {
compileAndCompare("var-register-noarg");
}
@Test
public void testVarRegisterZp() throws IOException, URISyntaxException {
compileAndCompare("var-register-zp");
}
@Test
public void testVarRegisterZp2() throws IOException, URISyntaxException {
assertError("var-register-zp-2", "Error! Register not on zeropage");
}
@Test
public void testVarRegisterZp3() throws IOException, URISyntaxException {
compileAndCompare("var-register-zp-3");
}
@Test
public void testDword() throws IOException, URISyntaxException {
compileAndCompare("dword");

View File

@ -0,0 +1,7 @@
// Test declaring a variable as register on a specific ZP address
int* SCREEN = 0x0400;
void main() {
register(257) char i=0;
}

View File

@ -0,0 +1,20 @@
// Test declaring a variable as register on a specific ZP address
char* screen = $400;
void main() {
print2(screen, "hello");
//print2(screen+80, "hello");
}
void print2(char* register(250) at, char* register(252) msg) {
byte j=0;
for(byte i=0; msg[i]; i++) {
print_char(at, j, msg[i]);
j += 2;
}
}
void print_char(char* register(250) at, char register(X) idx, char register(A) ch) {
at[idx] = ch;
}

View File

@ -0,0 +1,13 @@
// Test declaring a variable as register on a specific ZP address
int* SCREEN = 0x0400;
void main() {
register(0x2) char i=0;
register(0x4) int j=0;
while(i<4) {
SCREEN[i++] = j++;
int k = (int)i*2;
SCREEN[i++] = k;
}
}

View File

@ -0,0 +1,50 @@
// Test declaring a variable as register on a specific ZP address
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label screen = $400
main: {
jsr print2
rts
msg: .text "hello"
.byte 0
}
// print2(byte* zeropage($fa) at, byte* zeropage($fc) msg)
print2: {
.label i = 2
.label msg = $fc
.label at = $fa
ldx #0
lda #<screen
sta.z at
lda #>screen
sta.z at+1
txa
sta.z i
lda #<main.msg
sta.z msg
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
}

View File

@ -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

View File

@ -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
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
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
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
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
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
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

View File

@ -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 ]

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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 ]

View File

@ -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

View File

@ -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

View File

@ -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 ]