From ae167736d42a4ed17846d7020935dfb9bfda7610 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 26 Nov 2017 21:27:00 +0100 Subject: [PATCH] Fixed wordexpr problem. Improved type inference of binary/unary constants. Added sby->by fragment synthesis. --- .../camelot64/kickc/fragment/AsmFragment.java | 40 +- .../kickc/fragment/AsmFragmentManager.java | 14 + .../kickc/fragment/AsmFragmentSignature.java | 14 +- .../fragment/asm/zpwo1=zpwo1_plus_cowo1.asm | 8 + .../camelot64/kickc/model/ConstantUnary.java | 2 - .../kickc/model/ConstantValueCalculator.java | 3 + .../kickc/model/SymbolTypeInference.java | 7 +- .../passes/Pass2ConstantIdentification.java | 4 + .../dk/camelot64/kickc/test/TestErrors.java | 13 +- .../dk/camelot64/kickc/test/TestPrograms.java | 4 + .../java/dk/camelot64/kickc/test/casting.kc | 4 +- .../java/dk/camelot64/kickc/test/constants.kc | 45 + .../java/dk/camelot64/kickc/test/print.kc | 33 + .../dk/camelot64/kickc/test/ref/casting.asm | 46 + .../dk/camelot64/kickc/test/ref/casting.cfg | 40 + .../dk/camelot64/kickc/test/ref/casting.log | 2133 +++++++++++++++++ .../dk/camelot64/kickc/test/ref/casting.sym | 46 + .../camelot64/kickc/test/ref/signed-bytes.log | 10 +- .../dk/camelot64/kickc/test/ref/wordexpr.asm | 23 + .../dk/camelot64/kickc/test/ref/wordexpr.cfg | 19 + .../dk/camelot64/kickc/test/ref/wordexpr.log | 883 +++++++ .../dk/camelot64/kickc/test/ref/wordexpr.sym | 15 + .../java/dk/camelot64/kickc/test/wordexpr.kc | 3 +- 23 files changed, 3377 insertions(+), 32 deletions(-) create mode 100644 src/main/java/dk/camelot64/kickc/fragment/asm/zpwo1=zpwo1_plus_cowo1.asm create mode 100644 src/main/java/dk/camelot64/kickc/test/constants.kc create mode 100644 src/main/java/dk/camelot64/kickc/test/print.kc create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/casting.asm create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/casting.cfg create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/casting.log create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/casting.sym create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/wordexpr.asm create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/wordexpr.cfg create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/wordexpr.log create mode 100644 src/main/java/dk/camelot64/kickc/test/ref/wordexpr.sym diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragment.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragment.java index 639504617..0a098c8cf 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragment.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragment.java @@ -115,11 +115,9 @@ public class AsmFragment { ConstantUnary unary = (ConstantUnary) value; Operator operator = unary.getOperator(); boolean parenthesis = operator.getPrecedence() > precedence; - return - (parenthesis ? "(" : "") + - operator.getOperator() + - getAsmConstant(program, unary.getOperand(), operator.getPrecedence(), codeScope) + - (parenthesis ? ")" : ""); + return (parenthesis ? "(" : "") + + getAsmConstantUnary(program, codeScope, operator, unary.getOperand(), precedence) + + (parenthesis ? ")" : ""); } else if (value instanceof ConstantBinary) { ConstantBinary binary = (ConstantBinary) value; Operator operator = binary.getOperator(); @@ -135,6 +133,38 @@ public class AsmFragment { } } + /** + * Get ASM code for a constant unary expression + * + * @param program The program + * @param codeScope The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope). + * @param operator The unary operator + * @param operand The operand of the unary expression + * @return The ASM string representing the constant value + */ + private static String getAsmConstantUnary(Program program, ScopeRef codeScope, Operator operator, ConstantValue operand, int outerPrecedence) { + if (Operator.CAST_BYTE.equals(operator) || Operator.CAST_SBYTE.equals(operator)) { + SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand); + if(SymbolType.isByte(operandType) || SymbolType.isSByte(operandType)) { + // No cast needed + return getAsmConstant(program, operand, outerPrecedence, codeScope); + } else { + return "$ff & " + getAsmConstant(program, operand, Operator.BOOL_AND.getPrecedence(), codeScope); + } + } else if (Operator.CAST_WORD.equals(operator) || Operator.CAST_SWORD.equals(operator)) { + SymbolType operandType = SymbolTypeInference.inferType(program.getScope(), operand); + if(SymbolType.isWord(operandType) || SymbolType.isSWord(operandType)) { + // No cast needed + return getAsmConstant(program, operand, outerPrecedence, codeScope); + } else { + return "$ffff & " + getAsmConstant(program, operand, Operator.BOOL_AND.getPrecedence(), codeScope); + } + } else { + return operator.getOperator() + + getAsmConstant(program, operand, operator.getPrecedence(), codeScope); + } + } + public static String getAsmNumber(Number number) { if (number instanceof Integer) { if (number.intValue() >= 0 && number.intValue() <= 9) { diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentManager.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentManager.java index ea74ee737..73bca15f0 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentManager.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentManager.java @@ -111,6 +111,16 @@ public class AsmFragmentManager { mapZpptrToWord3.put("zpwo1", "zpwo3"); mapZpptrToWord3.put("zpptrby1", "zpwo1"); mapZpptrToWord3.put("zpptrby2", "zpwo2"); + Map mapSbyToBy = new LinkedHashMap<>(); + mapSbyToBy.put("zpsby1", "zpby1"); + mapSbyToBy.put("zpsby2", "zpby2"); + mapSbyToBy.put("zpsby3", "zpby3"); + mapSbyToBy.put("cosby1", "coby1"); + mapSbyToBy.put("cosby2", "coby2"); + mapSbyToBy.put("cosby3", "coby3"); + mapSbyToBy.put("asby", "aby"); + mapSbyToBy.put("xsby", "xby"); + mapSbyToBy.put("ysby", "yby"); List synths = new ArrayList<>(); @@ -178,6 +188,10 @@ public class AsmFragmentManager { synths.add(new FragmentSynthesis("zpptrby1=zpptrby1_(sethi|setlo|plus|minus)_zpwo1", null, null, "zpptrby1=zpptrby1_$1_zpwo1", null, mapZpptrToWord2)); synths.add(new FragmentSynthesis("zpptrby1=zpptrby2_(sethi|setlo|plus|minus)_zpwo1", null, null, "zpptrby1=zpptrby2_$1_zpwo1", null, mapZpptrToWord3)); + synths.add(new FragmentSynthesis("(zpsby.|asby|xsby|ysby)_(eq|neq)_(zpsby.|csoby.|asby|xsby|ysby)_then_(.*)", null, null, "$1_$2_$3_then_$4", null, mapSbyToBy)); + synths.add(new FragmentSynthesis("(zpsby.|asby|xsby|ysby)=(zpsby.|cosby.|asby|xsby|ysby)", null, null, "$1=$2", null, mapSbyToBy)); + synths.add(new FragmentSynthesis("(zpsby.|asby|xsby|ysby)=(zpsby.|csoby.|asby|xsby|ysby)_(plus|band|bxor|bor)_(zpsby.|csoby.|asby|xsby|ysby)", null, null, "$1=$2_$3_$4", null, mapSbyToBy)); + for (FragmentSynthesis synth : synths) { CharStream synthesized = synth.synthesize(signature, log); if (synthesized != null) { diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSignature.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSignature.java index aa0a9682f..147b2842d 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSignature.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentSignature.java @@ -292,19 +292,19 @@ public class AsmFragmentSignature { } else { throw new RuntimeException("Unhandled constant type " + value); } - if (SymbolType.BYTE.equals(constType) || (constType instanceof SymbolTypeInline && ((SymbolTypeInline) constType).isByte())) { + if (SymbolType.isByte(constType)) { String name = "coby" + nextConstByteIdx++; bindings.put(name, value); return name; - } else if (SymbolType.WORD.equals(constType) || (constType instanceof SymbolTypeInline && ((SymbolTypeInline) constType).isWord())) { - String name = "cowo" + nextConstByteIdx++; - bindings.put(name, value); - return name; - } else if (SymbolType.SBYTE.equals(constType) || (constType instanceof SymbolTypeInline && ((SymbolTypeInline) constType).isSByte())) { + } else if (SymbolType.isSByte(constType)) { String name = "cosby" + nextConstByteIdx++; bindings.put(name, value); return name; - } else if (SymbolType.SWORD.equals(constType) || (constType instanceof SymbolTypeInline && ((SymbolTypeInline) constType).isSWord())) { + } else if (SymbolType.isWord(constType)) { + String name = "cowo" + nextConstByteIdx++; + bindings.put(name, value); + return name; + } else if (SymbolType.isSWord(constType)) { String name = "coswo" + nextConstByteIdx++; bindings.put(name, value); return name; diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/zpwo1=zpwo1_plus_cowo1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/zpwo1=zpwo1_plus_cowo1.asm new file mode 100644 index 000000000..af0c17323 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/zpwo1=zpwo1_plus_cowo1.asm @@ -0,0 +1,8 @@ +lda {zpwo1} +clc +adc #<{cowo1} +sta {zpwo1} +lda {zpwo1}+1 +adc #>{cowo1} +sta {zpwo1}+1 + diff --git a/src/main/java/dk/camelot64/kickc/model/ConstantUnary.java b/src/main/java/dk/camelot64/kickc/model/ConstantUnary.java index dacdf5755..5c2be5d34 100644 --- a/src/main/java/dk/camelot64/kickc/model/ConstantUnary.java +++ b/src/main/java/dk/camelot64/kickc/model/ConstantUnary.java @@ -35,9 +35,7 @@ public class ConstantUnary implements ConstantValue { if (o == null || getClass() != o.getClass()) { return false; } - ConstantUnary that = (ConstantUnary) o; - if (!operator.equals(that.operator)) { return false; } diff --git a/src/main/java/dk/camelot64/kickc/model/ConstantValueCalculator.java b/src/main/java/dk/camelot64/kickc/model/ConstantValueCalculator.java index 7b62dd4cb..cfd3fc3d5 100644 --- a/src/main/java/dk/camelot64/kickc/model/ConstantValueCalculator.java +++ b/src/main/java/dk/camelot64/kickc/model/ConstantValueCalculator.java @@ -22,6 +22,9 @@ public class ConstantValueCalculator { } else if(value instanceof ConstantBinary) { ConstantBinary binary = (ConstantBinary) value; return calcValue(programScope, binary.getLeft(), binary.getOperator(), binary.getRight()); + } else if(value instanceof ConstantArray) { + // Cannot calculate value of inline array + return null; } else { throw new RuntimeException("Unknown constant value "+value); } diff --git a/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java b/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java index 6c6b4ad8a..f9648c664 100644 --- a/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java +++ b/src/main/java/dk/camelot64/kickc/model/SymbolTypeInference.java @@ -265,13 +265,10 @@ public class SymbolTypeInference { type = SymbolType.BOOLEAN; } else if (rValue instanceof ConstantUnary) { ConstantUnary constUnary = (ConstantUnary) rValue; - SymbolType subType = inferType(programScope, constUnary.getOperand()); - return inferType(constUnary.getOperator(), subType); + return inferType(programScope, constUnary.getOperator(), constUnary.getOperand()); } else if (rValue instanceof ConstantBinary) { ConstantBinary constBin = (ConstantBinary) rValue; - SymbolType leftType = inferType(programScope, constBin.getLeft()); - SymbolType rightType = inferType(programScope, constBin.getRight()); - return inferType(leftType, constBin.getOperator(), rightType); + return inferType(programScope, constBin.getLeft(), constBin.getOperator(), constBin.getRight()); } else if (rValue instanceof PointerDereferenceSimple) { SymbolType pointerType = inferType(programScope, ((PointerDereferenceSimple) rValue).getPointer()); if (pointerType instanceof SymbolTypePointer) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java index af4f99ab5..0e07828ca 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantIdentification.java @@ -179,6 +179,10 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization { case "--": case "<": case ">": + case "_byte_": + case "_sbyte_": + case "_word_": + case "_sword_": return new ConstantUnary(operator, c); case "*": { // pointer dereference - not constant return null; diff --git a/src/main/java/dk/camelot64/kickc/test/TestErrors.java b/src/main/java/dk/camelot64/kickc/test/TestErrors.java index 5edcf7b6b..0cc42c690 100644 --- a/src/main/java/dk/camelot64/kickc/test/TestErrors.java +++ b/src/main/java/dk/camelot64/kickc/test/TestErrors.java @@ -24,6 +24,14 @@ public class TestErrors extends TestCase { helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/"); } + public void testPrint() throws IOException, URISyntaxException { + compileAndCompare("print"); + } + + public void testConstants() throws IOException, URISyntaxException { + compileAndCompare("constants"); + } + public void testInlineAsmParam() throws IOException, URISyntaxException { compileAndCompare("inline-asm-param"); } @@ -33,11 +41,6 @@ public class TestErrors extends TestCase { compileAndCompare(filename); } - public void testWordExpr() throws IOException, URISyntaxException { - String filename = "wordexpr"; - compileAndCompare(filename); - } - public void testForRangeSymbolic() throws IOException, URISyntaxException { String filename = "forrangesymbolic"; compileAndCompare(filename); diff --git a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java index e95219a40..0ab65ce92 100644 --- a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java @@ -24,6 +24,10 @@ public class TestPrograms extends TestCase { helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/"); } + public void testWordExpr() throws IOException, URISyntaxException { + compileAndCompare("wordexpr"); + } + public void testZpptr() throws IOException, URISyntaxException { compileAndCompare("zpptr"); } diff --git a/src/main/java/dk/camelot64/kickc/test/casting.kc b/src/main/java/dk/camelot64/kickc/test/casting.kc index 73103964d..365947843 100644 --- a/src/main/java/dk/camelot64/kickc/test/casting.kc +++ b/src/main/java/dk/camelot64/kickc/test/casting.kc @@ -1,6 +1,7 @@ byte* SCREEN = $0400; byte* SCREEN2 = SCREEN+40*3; byte* SCREEN3 = SCREEN+40*6; +byte* SCREEN4 = SCREEN+40*9; void main() { for( byte b: 0..100) { @@ -21,6 +22,7 @@ void w() { word w2 = 1250; byte b = (byte)(w1-w2); byte b2 = 1400-1350+i; - SCREEN3[i] = b2; + SCREEN3[i] = b; + SCREEN4[i] = b2; } } diff --git a/src/main/java/dk/camelot64/kickc/test/constants.kc b/src/main/java/dk/camelot64/kickc/test/constants.kc new file mode 100644 index 000000000..b694e2853 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/constants.kc @@ -0,0 +1,45 @@ +const byte* BGCOL = $d021; +const byte GREEN = 5; +const byte RED = 2 ; + +void main() { + *BGCOL = GREEN; + test_bytes(); + test_sbytes(); +} + +// Test different byte constants +void test_bytes() { + byte bb=0; + assert_byte(bb, 0); + byte bc=bb+2; + assert_byte(bc, 2); + byte bd=bc-4; + assert_byte(bd, 254); +} + +void assert_byte(byte b, byte c) { + if(b!=c) { + *BGCOL = RED; + } +} + +// Test different signed byte constants +void test_sbytes() { + signed byte bb=0; + assert_sbyte(bb, 0); + signed byte bc=bb+2; + assert_sbyte(bc, 2); + signed byte bd=bc-4; + assert_sbyte(bd, -2); + signed byte be=-bd; + assert_sbyte(be, 2); + signed byte bf=-127-127; + assert_sbyte(bf, 2); +} + +void assert_sbyte(signed byte b, signed byte c) { + if(b!=c) { + *BGCOL = RED; + } +} diff --git a/src/main/java/dk/camelot64/kickc/test/print.kc b/src/main/java/dk/camelot64/kickc/test/print.kc new file mode 100644 index 000000000..24650d7e1 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/print.kc @@ -0,0 +1,33 @@ + +byte[] msg = "hello world!@"; +byte[] msg2 = "hello c64!@"; + +void main() { + print_str(msg); + print_ln(); + print_str(msg2); + print_ln(); +} + +byte* line_cursor = $0400; +byte* char_cursor = line_cursor; + +// Print a zero-terminated string +void print_str(byte* str) { + while(*str!='@') { + *(char_cursor++) = *str; + } +} + +// Print a newline +void print_ln() { + do { + line_cursor = line_cursor + $28; + } while (line_cursormain] +main_from_b2: + jsr main + jmp bend +//SEG6 @end +bend: +//SEG7 main +main: { + .label _1 = 5 + .label _3 = 7 + .label b2 = 4 + .label sb = 6 + .label b = 2 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG9 [2] phi (byte) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- zpby1=coby1 + lda #0 + sta b + jmp b1 + //SEG10 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG11 [2] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@1->main::@1#0] -- register_copy + jmp b1 + //SEG12 main::@1 + b1: + //SEG13 [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) -- zpby1=coby1_minus_zpby2 + lda b + eor #$ff + clc + adc #$c8+1 + sta b2 + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::b#2) ← (byte) main::b2#0 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_zpby1=zpby2 + lda b2 + ldx b + sta SCREEN,x + //SEG15 [5] (signed byte~) main::$1 ← _sbyte_ (byte) main::b#2 [ main::b#2 main::$1 ] ( main:0 [ main::b#2 main::$1 ] ) -- zpsby1=_sbyte_zpby1 + lda b + sta _1 + //SEG16 [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) -- zpsby1=_neg_zpsby2 + lda _1 + eor #$ff + clc + adc #1 + sta sb + //SEG17 [7] (byte~) main::$3 ← _byte_ (signed byte) main::sb#0 [ main::b#2 main::$3 ] ( main:0 [ main::b#2 main::$3 ] ) -- zpby1=_byte_zpsby1 + lda sb + sta _3 + //SEG18 [8] *((const byte*) SCREEN2#0 + (byte) main::b#2) ← (byte~) main::$3 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_zpby1=zpby2 + lda _3 + ldx b + sta SCREEN2,x + //SEG19 [9] (byte) main::b#1 ← ++ (byte) main::b#2 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- zpby1=_inc_zpby1 + inc b + //SEG20 [10] if((byte) main::b#1!=(byte/signed byte/word/signed word) 101) goto main::@1 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- zpby1_neq_coby1_then_la1 + lda b + cmp #$65 + bne b1_from_b1 + jmp b2 + //SEG21 main::@2 + b2: + //SEG22 [11] call w param-assignment [ ] ( main:0 [ ] ) + //SEG23 [13] phi from main::@2 to w [phi:main::@2->w] + w_from_b2: + jsr w + jmp breturn + //SEG24 main::@return + breturn: + //SEG25 [12] return [ ] ( main:0 [ ] ) + rts +} +//SEG26 w +w: { + .const w1 = $514 + .const w2 = $4e2 + .const b = w1-w2 + .label b2 = 8 + .label i = 3 + //SEG27 [14] phi from w to w::@1 [phi:w->w::@1] + b1_from_w: + //SEG28 [14] phi (byte) w::i#2 = (byte/signed byte/word/signed word) 0 [phi:w->w::@1#0] -- zpby1=coby1 + lda #0 + sta i + jmp b1 + //SEG29 [14] phi from w::@1 to w::@1 [phi:w::@1->w::@1] + b1_from_b1: + //SEG30 [14] phi (byte) w::i#2 = (byte) w::i#1 [phi:w::@1->w::@1#0] -- register_copy + jmp b1 + //SEG31 w::@1 + b1: + //SEG32 [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- zpby1=coby1_plus_zpby2 + lda i + clc + adc #$578-$546 + sta b2 + //SEG33 [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- cowo1_derefidx_zpby1=coby2 + lda #b + ldx i + sta SCREEN3,x + //SEG34 [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) -- cowo1_derefidx_zpby1=zpby2 + lda b2 + ldx i + sta SCREEN4,x + //SEG35 [18] (byte) w::i#1 ← ++ (byte) w::i#2 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- zpby1=_inc_zpby1 + inc i + //SEG36 [19] if((byte) w::i#1!=(byte/signed byte/word/signed word) 11) goto w::@1 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- zpby1_neq_coby1_then_la1 + lda i + cmp #$b + bne b1_from_b1 + jmp breturn + //SEG37 w::@return + breturn: + //SEG38 [20] return [ ] ( main:0::w:11 [ ] ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::b#2 main::b#1 ] +Statement [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) always clobbers reg byte a +Statement [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ w::i#2 w::i#1 ] +Statement [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ w::b2#0 ] +Statement [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) always clobbers reg byte a +Statement [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) always clobbers reg byte a +Statement [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) always clobbers reg byte a +Statement [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) always clobbers reg byte a +Statement [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) always clobbers reg byte a +Statement [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) always clobbers reg byte a +Potential registers zp ZP_BYTE:2 [ main::b#2 main::b#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:3 [ w::i#2 w::i#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:4 [ main::b2#0 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_SBYTE:5 [ main::$1 ] : zp ZP_SBYTE:5 , reg sbyte a , reg sbyte x , reg sbyte y , +Potential registers zp ZP_SBYTE:6 [ main::sb#0 ] : zp ZP_SBYTE:6 , reg sbyte a , reg sbyte x , reg sbyte y , +Potential registers zp ZP_BYTE:7 [ main::$3 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , +Potential registers zp ZP_BYTE:8 [ w::b2#0 ] : zp ZP_BYTE:8 , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 25.93: zp ZP_BYTE:2 [ main::b#2 main::b#1 ] 22: zp ZP_BYTE:4 [ main::b2#0 ] 22: zp ZP_SBYTE:5 [ main::$1 ] 22: zp ZP_SBYTE:6 [ main::sb#0 ] 22: zp ZP_BYTE:7 [ main::$3 ] +Uplift Scope [w] 30.25: zp ZP_BYTE:3 [ w::i#2 w::i#1 ] 11: zp ZP_BYTE:8 [ w::b2#0 ] +Uplift Scope [] + +Uplifting [main] best 1110 combination reg byte x [ main::b#2 main::b#1 ] reg byte a [ main::b2#0 ] reg sbyte a [ main::$1 ] reg sbyte a [ main::sb#0 ] reg byte a [ main::$3 ] +Uplifting [w] best 930 combination reg byte y [ w::i#2 w::i#1 ] reg byte x [ w::b2#0 ] +Uplifting [] best 930 combination +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp breturn +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 + .const SCREEN2 = SCREEN+$28*3 + .const SCREEN3 = SCREEN+$28*6 + .const SCREEN4 = SCREEN+$28*9 +//SEG2 @begin +bbegin: +//SEG3 @2 +b2: +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @2 to main [phi:@2->main] +main_from_b2: + jsr main +//SEG6 @end +bend: +//SEG7 main +main: { + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG9 [2] phi (byte) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + jmp b1 + //SEG10 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG11 [2] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) -- aby=coby1_minus_xby + stx $ff + lda #$c8 + sec + sbc $ff + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::b#2) ← (byte) main::b2#0 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG15 [5] (signed byte~) main::$1 ← _sbyte_ (byte) main::b#2 [ main::b#2 main::$1 ] ( main:0 [ main::b#2 main::$1 ] ) -- asby=_sbyte_xby + txa + //SEG16 [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) -- asby=_neg_asby + eor #$ff + clc + adc #1 + //SEG17 [7] (byte~) main::$3 ← _byte_ (signed byte) main::sb#0 [ main::b#2 main::$3 ] ( main:0 [ main::b#2 main::$3 ] ) -- aby=_byte_asby + //SEG18 [8] *((const byte*) SCREEN2#0 + (byte) main::b#2) ← (byte~) main::$3 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG19 [9] (byte) main::b#1 ← ++ (byte) main::b#2 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby=_inc_xby + inx + //SEG20 [10] if((byte) main::b#1!=(byte/signed byte/word/signed word) 101) goto main::@1 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1_from_b1 + //SEG21 main::@2 + b2: + //SEG22 [11] call w param-assignment [ ] ( main:0 [ ] ) + //SEG23 [13] phi from main::@2 to w [phi:main::@2->w] + w_from_b2: + jsr w + //SEG24 main::@return + breturn: + //SEG25 [12] return [ ] ( main:0 [ ] ) + rts +} +//SEG26 w +w: { + .const w1 = $514 + .const w2 = $4e2 + .const b = w1-w2 + //SEG27 [14] phi from w to w::@1 [phi:w->w::@1] + b1_from_w: + //SEG28 [14] phi (byte) w::i#2 = (byte/signed byte/word/signed word) 0 [phi:w->w::@1#0] -- yby=coby1 + ldy #0 + jmp b1 + //SEG29 [14] phi from w::@1 to w::@1 [phi:w::@1->w::@1] + b1_from_b1: + //SEG30 [14] phi (byte) w::i#2 = (byte) w::i#1 [phi:w::@1->w::@1#0] -- register_copy + //SEG31 w::@1 + b1: + //SEG32 [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- xby=coby1_plus_yby + tya + clc + adc #$578-$546 + tax + //SEG33 [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- cowo1_derefidx_yby=coby2 + lda #b + sta SCREEN3,y + //SEG34 [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) -- cowo1_derefidx_yby=xby + txa + sta SCREEN4,y + //SEG35 [18] (byte) w::i#1 ← ++ (byte) w::i#2 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby=_inc_yby + iny + //SEG36 [19] if((byte) w::i#1!=(byte/signed byte/word/signed word) 11) goto w::@1 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby_neq_coby1_then_la1 + cpy #$b + bne b1_from_b1 + //SEG37 w::@return + breturn: + //SEG38 [20] return [ ] ( main:0::w:11 [ ] ) + rts +} + +Replacing label b1_from_b1 with b1 +Replacing label b1_from_b1 with b1 +Removing instruction bbegin: +Removing instruction main_from_b2: +Removing instruction b1_from_b1: +Removing instruction w_from_b2: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 + .const SCREEN2 = SCREEN+$28*3 + .const SCREEN3 = SCREEN+$28*6 + .const SCREEN4 = SCREEN+$28*9 +//SEG2 @begin +//SEG3 @2 +b2: +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @2 to main [phi:@2->main] + jsr main +//SEG6 @end +bend: +//SEG7 main +main: { + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG9 [2] phi (byte) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + jmp b1 + //SEG10 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG11 [2] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) -- aby=coby1_minus_xby + stx $ff + lda #$c8 + sec + sbc $ff + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::b#2) ← (byte) main::b2#0 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG15 [5] (signed byte~) main::$1 ← _sbyte_ (byte) main::b#2 [ main::b#2 main::$1 ] ( main:0 [ main::b#2 main::$1 ] ) -- asby=_sbyte_xby + txa + //SEG16 [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) -- asby=_neg_asby + eor #$ff + clc + adc #1 + //SEG17 [7] (byte~) main::$3 ← _byte_ (signed byte) main::sb#0 [ main::b#2 main::$3 ] ( main:0 [ main::b#2 main::$3 ] ) -- aby=_byte_asby + //SEG18 [8] *((const byte*) SCREEN2#0 + (byte) main::b#2) ← (byte~) main::$3 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG19 [9] (byte) main::b#1 ← ++ (byte) main::b#2 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby=_inc_xby + inx + //SEG20 [10] if((byte) main::b#1!=(byte/signed byte/word/signed word) 101) goto main::@1 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG21 main::@2 + b2: + //SEG22 [11] call w param-assignment [ ] ( main:0 [ ] ) + //SEG23 [13] phi from main::@2 to w [phi:main::@2->w] + jsr w + //SEG24 main::@return + breturn: + //SEG25 [12] return [ ] ( main:0 [ ] ) + rts +} +//SEG26 w +w: { + .const w1 = $514 + .const w2 = $4e2 + .const b = w1-w2 + //SEG27 [14] phi from w to w::@1 [phi:w->w::@1] + b1_from_w: + //SEG28 [14] phi (byte) w::i#2 = (byte/signed byte/word/signed word) 0 [phi:w->w::@1#0] -- yby=coby1 + ldy #0 + jmp b1 + //SEG29 [14] phi from w::@1 to w::@1 [phi:w::@1->w::@1] + //SEG30 [14] phi (byte) w::i#2 = (byte) w::i#1 [phi:w::@1->w::@1#0] -- register_copy + //SEG31 w::@1 + b1: + //SEG32 [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- xby=coby1_plus_yby + tya + clc + adc #$578-$546 + tax + //SEG33 [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- cowo1_derefidx_yby=coby2 + lda #b + sta SCREEN3,y + //SEG34 [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) -- cowo1_derefidx_yby=xby + txa + sta SCREEN4,y + //SEG35 [18] (byte) w::i#1 ← ++ (byte) w::i#2 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby=_inc_yby + iny + //SEG36 [19] if((byte) w::i#1!=(byte/signed byte/word/signed word) 11) goto w::@1 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby_neq_coby1_then_la1 + cpy #$b + bne b1 + //SEG37 w::@return + breturn: + //SEG38 [20] return [ ] ( main:0::w:11 [ ] ) + rts +} + +Removing instruction b2: +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction b2: +Removing instruction breturn: +Removing instruction b1_from_w: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 + .const SCREEN2 = SCREEN+$28*3 + .const SCREEN3 = SCREEN+$28*6 + .const SCREEN4 = SCREEN+$28*9 +//SEG2 @begin +//SEG3 @2 +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @2 to main [phi:@2->main] + jsr main +//SEG6 @end +//SEG7 main +main: { + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + //SEG9 [2] phi (byte) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + jmp b1 + //SEG10 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG11 [2] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) -- aby=coby1_minus_xby + stx $ff + lda #$c8 + sec + sbc $ff + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::b#2) ← (byte) main::b2#0 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG15 [5] (signed byte~) main::$1 ← _sbyte_ (byte) main::b#2 [ main::b#2 main::$1 ] ( main:0 [ main::b#2 main::$1 ] ) -- asby=_sbyte_xby + txa + //SEG16 [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) -- asby=_neg_asby + eor #$ff + clc + adc #1 + //SEG17 [7] (byte~) main::$3 ← _byte_ (signed byte) main::sb#0 [ main::b#2 main::$3 ] ( main:0 [ main::b#2 main::$3 ] ) -- aby=_byte_asby + //SEG18 [8] *((const byte*) SCREEN2#0 + (byte) main::b#2) ← (byte~) main::$3 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG19 [9] (byte) main::b#1 ← ++ (byte) main::b#2 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby=_inc_xby + inx + //SEG20 [10] if((byte) main::b#1!=(byte/signed byte/word/signed word) 101) goto main::@1 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG21 main::@2 + //SEG22 [11] call w param-assignment [ ] ( main:0 [ ] ) + //SEG23 [13] phi from main::@2 to w [phi:main::@2->w] + jsr w + //SEG24 main::@return + //SEG25 [12] return [ ] ( main:0 [ ] ) + rts +} +//SEG26 w +w: { + .const w1 = $514 + .const w2 = $4e2 + .const b = w1-w2 + //SEG27 [14] phi from w to w::@1 [phi:w->w::@1] + //SEG28 [14] phi (byte) w::i#2 = (byte/signed byte/word/signed word) 0 [phi:w->w::@1#0] -- yby=coby1 + ldy #0 + jmp b1 + //SEG29 [14] phi from w::@1 to w::@1 [phi:w::@1->w::@1] + //SEG30 [14] phi (byte) w::i#2 = (byte) w::i#1 [phi:w::@1->w::@1#0] -- register_copy + //SEG31 w::@1 + b1: + //SEG32 [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- xby=coby1_plus_yby + tya + clc + adc #$578-$546 + tax + //SEG33 [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- cowo1_derefidx_yby=coby2 + lda #b + sta SCREEN3,y + //SEG34 [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) -- cowo1_derefidx_yby=xby + txa + sta SCREEN4,y + //SEG35 [18] (byte) w::i#1 ← ++ (byte) w::i#2 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby=_inc_yby + iny + //SEG36 [19] if((byte) w::i#1!=(byte/signed byte/word/signed word) 11) goto w::@1 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby_neq_coby1_then_la1 + cpy #$b + bne b1 + //SEG37 w::@return + //SEG38 [20] return [ ] ( main:0::w:11 [ ] ) + rts +} + +Removing instruction jmp b1 +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 + .const SCREEN2 = SCREEN+$28*3 + .const SCREEN3 = SCREEN+$28*6 + .const SCREEN4 = SCREEN+$28*9 +//SEG2 @begin +//SEG3 @2 +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @2 to main [phi:@2->main] + jsr main +//SEG6 @end +//SEG7 main +main: { + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + //SEG9 [2] phi (byte) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG11 [2] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) -- aby=coby1_minus_xby + stx $ff + lda #$c8 + sec + sbc $ff + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::b#2) ← (byte) main::b2#0 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG15 [5] (signed byte~) main::$1 ← _sbyte_ (byte) main::b#2 [ main::b#2 main::$1 ] ( main:0 [ main::b#2 main::$1 ] ) -- asby=_sbyte_xby + txa + //SEG16 [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) -- asby=_neg_asby + eor #$ff + clc + adc #1 + //SEG17 [7] (byte~) main::$3 ← _byte_ (signed byte) main::sb#0 [ main::b#2 main::$3 ] ( main:0 [ main::b#2 main::$3 ] ) -- aby=_byte_asby + //SEG18 [8] *((const byte*) SCREEN2#0 + (byte) main::b#2) ← (byte~) main::$3 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG19 [9] (byte) main::b#1 ← ++ (byte) main::b#2 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby=_inc_xby + inx + //SEG20 [10] if((byte) main::b#1!=(byte/signed byte/word/signed word) 101) goto main::@1 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG21 main::@2 + //SEG22 [11] call w param-assignment [ ] ( main:0 [ ] ) + //SEG23 [13] phi from main::@2 to w [phi:main::@2->w] + jsr w + //SEG24 main::@return + //SEG25 [12] return [ ] ( main:0 [ ] ) + rts +} +//SEG26 w +w: { + .const w1 = $514 + .const w2 = $4e2 + .const b = w1-w2 + //SEG27 [14] phi from w to w::@1 [phi:w->w::@1] + //SEG28 [14] phi (byte) w::i#2 = (byte/signed byte/word/signed word) 0 [phi:w->w::@1#0] -- yby=coby1 + ldy #0 + //SEG29 [14] phi from w::@1 to w::@1 [phi:w::@1->w::@1] + //SEG30 [14] phi (byte) w::i#2 = (byte) w::i#1 [phi:w::@1->w::@1#0] -- register_copy + //SEG31 w::@1 + b1: + //SEG32 [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- xby=coby1_plus_yby + tya + clc + adc #$578-$546 + tax + //SEG33 [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- cowo1_derefidx_yby=coby2 + lda #b + sta SCREEN3,y + //SEG34 [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) -- cowo1_derefidx_yby=xby + txa + sta SCREEN4,y + //SEG35 [18] (byte) w::i#1 ← ++ (byte) w::i#2 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby=_inc_yby + iny + //SEG36 [19] if((byte) w::i#1!=(byte/signed byte/word/signed word) 11) goto w::@1 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby_neq_coby1_then_la1 + cpy #$b + bne b1 + //SEG37 w::@return + //SEG38 [20] return [ ] ( main:0::w:11 [ ] ) + rts +} + +FINAL SYMBOL TABLE +(label) @2 +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (word/signed word) 1024 +(byte*) SCREEN2 +(const byte*) SCREEN2#0 SCREEN2 = (const byte*) SCREEN#0+(byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 3 +(byte*) SCREEN3 +(const byte*) SCREEN3#0 SCREEN3 = (const byte*) SCREEN#0+(byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 6 +(byte*) SCREEN4 +(const byte*) SCREEN4#0 SCREEN4 = (const byte*) SCREEN#0+(byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 9 +(void()) main() +(signed byte~) main::$1 reg sbyte a 22.0 +(byte~) main::$3 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::b +(byte) main::b#1 reg byte x 16.5 +(byte) main::b#2 reg byte x 9.428571428571429 +(byte) main::b2 +(byte) main::b2#0 reg byte a 22.0 +(signed byte) main::sb +(signed byte) main::sb#0 reg sbyte a 22.0 +(void()) w() +(label) w::@1 +(label) w::@return +(byte) w::b +(const byte) w::b#0 b = _byte_(const word) w::w1#0-(const word) w::w2#0 +(byte) w::b2 +(byte) w::b2#0 reg byte x 11.0 +(byte) w::i +(byte) w::i#1 reg byte y 16.5 +(byte) w::i#2 reg byte y 13.75 +(word) w::w1 +(const word) w::w1#0 w1 = (word/signed word) 1300 +(word) w::w2 +(const word) w::w2#0 w2 = (word/signed word) 1250 + +reg byte x [ main::b#2 main::b#1 ] +reg byte y [ w::i#2 w::i#1 ] +reg byte a [ main::b2#0 ] +reg sbyte a [ main::$1 ] +reg sbyte a [ main::sb#0 ] +reg byte a [ main::$3 ] +reg byte x [ w::b2#0 ] + +FINAL CODE +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .const SCREEN = $400 + .const SCREEN2 = SCREEN+$28*3 + .const SCREEN3 = SCREEN+$28*6 + .const SCREEN4 = SCREEN+$28*9 +//SEG2 @begin +//SEG3 @2 +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @2 to main [phi:@2->main] + jsr main +//SEG6 @end +//SEG7 main +main: { + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + //SEG9 [2] phi (byte) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG11 [2] phi (byte) main::b#2 = (byte) main::b#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG12 main::@1 + b1: + //SEG13 [3] (byte) main::b2#0 ← (byte/word/signed word) 200 - (byte) main::b#2 [ main::b#2 main::b2#0 ] ( main:0 [ main::b#2 main::b2#0 ] ) -- aby=coby1_minus_xby + stx $ff + lda #$c8 + sec + sbc $ff + //SEG14 [4] *((const byte*) SCREEN#0 + (byte) main::b#2) ← (byte) main::b2#0 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN,x + //SEG15 [5] (signed byte~) main::$1 ← _sbyte_ (byte) main::b#2 [ main::b#2 main::$1 ] ( main:0 [ main::b#2 main::$1 ] ) -- asby=_sbyte_xby + txa + //SEG16 [6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] ) -- asby=_neg_asby + eor #$ff + clc + adc #1 + //SEG17 [7] (byte~) main::$3 ← _byte_ (signed byte) main::sb#0 [ main::b#2 main::$3 ] ( main:0 [ main::b#2 main::$3 ] ) -- aby=_byte_asby + //SEG18 [8] *((const byte*) SCREEN2#0 + (byte) main::b#2) ← (byte~) main::$3 [ main::b#2 ] ( main:0 [ main::b#2 ] ) -- cowo1_derefidx_xby=aby + sta SCREEN2,x + //SEG19 [9] (byte) main::b#1 ← ++ (byte) main::b#2 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby=_inc_xby + inx + //SEG20 [10] if((byte) main::b#1!=(byte/signed byte/word/signed word) 101) goto main::@1 [ main::b#1 ] ( main:0 [ main::b#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$65 + bne b1 + //SEG21 main::@2 + //SEG22 [11] call w param-assignment [ ] ( main:0 [ ] ) + //SEG23 [13] phi from main::@2 to w [phi:main::@2->w] + jsr w + //SEG24 main::@return + //SEG25 [12] return [ ] ( main:0 [ ] ) + rts +} +//SEG26 w +w: { + .const w1 = $514 + .const w2 = $4e2 + .const b = w1-w2 + //SEG27 [14] phi from w to w::@1 [phi:w->w::@1] + //SEG28 [14] phi (byte) w::i#2 = (byte/signed byte/word/signed word) 0 [phi:w->w::@1#0] -- yby=coby1 + ldy #0 + //SEG29 [14] phi from w::@1 to w::@1 [phi:w::@1->w::@1] + //SEG30 [14] phi (byte) w::i#2 = (byte) w::i#1 [phi:w::@1->w::@1#0] -- register_copy + //SEG31 w::@1 + b1: + //SEG32 [15] (byte) w::b2#0 ← (word/signed word) 1400-(word/signed word) 1350 + (byte) w::i#2 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- xby=coby1_plus_yby + tya + clc + adc #$578-$546 + tax + //SEG33 [16] *((const byte*) SCREEN3#0 + (byte) w::i#2) ← (const byte) w::b#0 [ w::i#2 w::b2#0 ] ( main:0::w:11 [ w::i#2 w::b2#0 ] ) -- cowo1_derefidx_yby=coby2 + lda #b + sta SCREEN3,y + //SEG34 [17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] ) -- cowo1_derefidx_yby=xby + txa + sta SCREEN4,y + //SEG35 [18] (byte) w::i#1 ← ++ (byte) w::i#2 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby=_inc_yby + iny + //SEG36 [19] if((byte) w::i#1!=(byte/signed byte/word/signed word) 11) goto w::@1 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] ) -- yby_neq_coby1_then_la1 + cpy #$b + bne b1 + //SEG37 w::@return + //SEG38 [20] return [ ] ( main:0::w:11 [ ] ) + rts +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/casting.sym b/src/main/java/dk/camelot64/kickc/test/ref/casting.sym new file mode 100644 index 000000000..a72dddb77 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/casting.sym @@ -0,0 +1,46 @@ +(label) @2 +(label) @begin +(label) @end +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (word/signed word) 1024 +(byte*) SCREEN2 +(const byte*) SCREEN2#0 SCREEN2 = (const byte*) SCREEN#0+(byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 3 +(byte*) SCREEN3 +(const byte*) SCREEN3#0 SCREEN3 = (const byte*) SCREEN#0+(byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 6 +(byte*) SCREEN4 +(const byte*) SCREEN4#0 SCREEN4 = (const byte*) SCREEN#0+(byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 9 +(void()) main() +(signed byte~) main::$1 reg sbyte a 22.0 +(byte~) main::$3 reg byte a 22.0 +(label) main::@1 +(label) main::@2 +(label) main::@return +(byte) main::b +(byte) main::b#1 reg byte x 16.5 +(byte) main::b#2 reg byte x 9.428571428571429 +(byte) main::b2 +(byte) main::b2#0 reg byte a 22.0 +(signed byte) main::sb +(signed byte) main::sb#0 reg sbyte a 22.0 +(void()) w() +(label) w::@1 +(label) w::@return +(byte) w::b +(const byte) w::b#0 b = _byte_(const word) w::w1#0-(const word) w::w2#0 +(byte) w::b2 +(byte) w::b2#0 reg byte x 11.0 +(byte) w::i +(byte) w::i#1 reg byte y 16.5 +(byte) w::i#2 reg byte y 13.75 +(word) w::w1 +(const word) w::w1#0 w1 = (word/signed word) 1300 +(word) w::w2 +(const word) w::w2#0 w2 = (word/signed word) 1250 + +reg byte x [ main::b#2 main::b#1 ] +reg byte y [ w::i#2 w::i#1 ] +reg byte a [ main::b2#0 ] +reg sbyte a [ main::$1 ] +reg sbyte a [ main::sb#0 ] +reg byte a [ main::$3 ] +reg byte x [ w::b2#0 ] diff --git a/src/main/java/dk/camelot64/kickc/test/ref/signed-bytes.log b/src/main/java/dk/camelot64/kickc/test/ref/signed-bytes.log index 9c44dc74f..962915439 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/signed-bytes.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/signed-bytes.log @@ -647,7 +647,7 @@ main: { //SEG9 [2] phi (byte) main::j#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- zpby1=coby1 lda #0 sta j - //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=coby1 + //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=cosby1 lda #-$7f sta i jmp b1 @@ -741,7 +741,7 @@ main: { b1_from_main: //SEG9 [2] phi (byte) main::j#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 ldx #0 - //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=coby1 + //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=cosby1 lda #-$7f sta i //SEG11 main::@1 @@ -799,7 +799,7 @@ main: { b1_from_main: //SEG9 [2] phi (byte) main::j#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 ldx #0 - //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=coby1 + //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=cosby1 lda #-$7f sta i //SEG11 main::@1 @@ -857,7 +857,7 @@ main: { //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] //SEG9 [2] phi (byte) main::j#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 ldx #0 - //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=coby1 + //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=cosby1 lda #-$7f sta i //SEG11 main::@1 @@ -927,7 +927,7 @@ main: { //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] //SEG9 [2] phi (byte) main::j#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 ldx #0 - //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=coby1 + //SEG10 [2] phi (signed byte) main::i#2 = -(byte/signed byte/word/signed word) 127 [phi:main->main::@1#1] -- zpsby1=cosby1 lda #-$7f sta i //SEG11 main::@1 diff --git a/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.asm b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.asm new file mode 100644 index 000000000..43a510d9e --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.asm @@ -0,0 +1,23 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + jsr main +main: { + .label b = 2 + ldx #0 + txa + sta b + sta b+1 + b1: + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + inx + cpx #$b + bne b1 + rts +} diff --git a/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.cfg b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.cfg new file mode 100644 index 000000000..c0bc1cd2f --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.cfg @@ -0,0 +1,19 @@ +@begin: scope:[] from + to:@1 +@1: scope:[] from @begin + [0] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 +main: scope:[main] from @1 + [1] phi() [ ] ( main:0 [ ] ) + to:main::@1 +main::@1: scope:[main] from main main::@1 + [2] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(byte) main::i#1 ) [ main::b#2 main::i#2 ] ( main:0 [ main::b#2 main::i#2 ] ) + [2] (word) main::b#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(word) main::b#1 ) [ main::b#2 main::i#2 ] ( main:0 [ main::b#2 main::i#2 ] ) + [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) + [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) + [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) + to:main::@return +main::@return: scope:[main] from main::@1 + [6] return [ ] ( main:0 [ ] ) + to:@return diff --git a/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.log b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.log new file mode 100644 index 000000000..9aaed9ef5 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.log @@ -0,0 +1,883 @@ +// Expressions based on bytes but resulting in words are as words - eg. b = b + 40*8; +void main() { + word b = 0; + for(byte i : 0..10) { + b = b + 40*8; + } +} + + +PROGRAM +proc (void()) main() + (word) main::b ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 +main::@1: + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word~) main::$1 ← (word) main::b + (word/signed word~) main::$0 + (word) main::b ← (word~) main::$1 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$2 ← (byte) main::i != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 +main::@return: + return +endproc // main() + call main + +SYMBOLS +(void()) main() +(word/signed word~) main::$0 +(word~) main::$1 +(boolean~) main::$2 +(label) main::@1 +(label) main::@return +(word) main::b +(byte) main::i + +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + (word) main::b ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word~) main::$1 ← (word) main::b + (word/signed word~) main::$0 + (word) main::b ← (word~) main::$1 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$2 ← (byte) main::i != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 + to:main::@2 +main::@2: scope:[main] from main::@1 + to:main::@return +main::@return: scope:[main] from main::@2 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +Removing empty block main::@2 +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from + (word) main::b ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word~) main::$1 ← (word) main::b + (word/signed word~) main::$0 + (word) main::b ← (word~) main::$1 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$2 ← (byte) main::i != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main + to:@end +@end: scope:[] from @1 + +PROCEDURE MODIFY VARIABLE ANALYSIS + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::b ← (byte/signed byte/word/signed word) 0 + (byte) main::i ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word~) main::$1 ← (word) main::b + (word/signed word~) main::$0 + (word) main::b ← (word~) main::$1 + (byte) main::i ← ++ (byte) main::i + (boolean~) main::$2 ← (byte) main::i != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +Completing Phi functions... +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::b#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + (word) main::b#2 ← phi( main/(word) main::b#0 main::@1/(word) main::b#1 ) + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word~) main::$1 ← (word) main::b#2 + (word/signed word~) main::$0 + (word) main::b#1 ← (word~) main::$1 + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$2 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +CONTROL FLOW GRAPH WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::b#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + (word) main::b#2 ← phi( main/(word) main::b#0 main::@1/(word) main::b#1 ) + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word~) main::$1 ← (word) main::b#2 + (word/signed word~) main::$0 + (word) main::b#1 ← (word~) main::$1 + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$2 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@2 +@2: scope:[] from @1 + to:@end +@end: scope:[] from @2 + +INITIAL SSA SYMBOL TABLE +(label) @1 +(label) @2 +(label) @begin +(label) @end +(void()) main() +(word/signed word~) main::$0 +(word~) main::$1 +(boolean~) main::$2 +(label) main::@1 +(label) main::@return +(word) main::b +(word) main::b#0 +(word) main::b#1 +(word) main::b#2 +(byte) main::i +(byte) main::i#0 +(byte) main::i#1 +(byte) main::i#2 + +Culled Empty Block (label) @2 +Succesful SSA optimization Pass2CullEmptyBlocks +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::b#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + (word) main::b#2 ← phi( main/(word) main::b#0 main::@1/(word) main::b#1 ) + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word~) main::$1 ← (word) main::b#2 + (word/signed word~) main::$0 + (word) main::b#1 ← (word~) main::$1 + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$2 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Alias (word) main::b#1 = (word~) main::$1 +Succesful SSA optimization Pass2AliasElimination +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::b#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + (word) main::b#2 ← phi( main/(word) main::b#0 main::@1/(word) main::b#1 ) + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word) main::b#1 ← (word) main::b#2 + (word/signed word~) main::$0 + (byte) main::i#1 ← ++ (byte) main::i#2 + (boolean~) main::$2 ← (byte) main::i#1 != (byte/signed byte/word/signed word) 11 + if((boolean~) main::$2) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Simple Condition (boolean~) main::$2 if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 +Succesful SSA optimization Pass2ConditionalJumpSimplification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + (word) main::b#0 ← (byte/signed byte/word/signed word) 0 + (byte) main::i#0 ← (byte/signed byte/word/signed word) 0 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 ) + (word) main::b#2 ← phi( main/(word) main::b#0 main::@1/(word) main::b#1 ) + (word/signed word~) main::$0 ← (byte/signed byte/word/signed word) 40 * (byte/signed byte/word/signed word) 8 + (word) main::b#1 ← (word) main::b#2 + (word/signed word~) main::$0 + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Constant (const word) main::b#0 = 0 +Constant (const byte) main::i#0 = 0 +Constant (const word/signed word) main::$0 = 40*8 +Succesful SSA optimization Pass2ConstantIdentification +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(const byte) main::i#0 main::@1/(byte) main::i#1 ) + (word) main::b#2 ← phi( main/(const word) main::b#0 main::@1/(word) main::b#1 ) + (word) main::b#1 ← (word) main::b#2 + (const word/signed word) main::$0 + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +Inlining constant with var siblings (const word) main::b#0 +Inlining constant with var siblings (const word) main::b#0 +Inlining constant with var siblings (const byte) main::i#0 +Inlining constant with var siblings (const byte) main::i#0 +Constant inlined main::i#0 = (byte/signed byte/word/signed word) 0 +Constant inlined main::$0 = (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 +Constant inlined main::b#0 = (byte/signed byte/word/signed word) 0 +Succesful SSA optimization Pass2ConstantInlining +CONTROL FLOW GRAPH +@begin: scope:[] from + to:@1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@1 + (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(byte) main::i#1 ) + (word) main::b#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(word) main::b#1 ) + (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@return +(word) main::b +(word) main::b#1 +(word) main::b#2 +(byte) main::i +(byte) main::i#1 +(byte) main::i#2 + +Block Sequence Planned @begin @1 @end main main::@1 main::@return +Added new block during phi lifting main::@3(between main::@1 and main::@1) +Block Sequence Planned @begin @1 @end main main::@1 main::@return main::@3 +CONTROL FLOW GRAPH - PHI LIFTED +@begin: scope:[] from + to:@1 +@1: scope:[] from @begin + call main param-assignment + to:@end +@end: scope:[] from @1 +main: scope:[main] from @1 + to:main::@1 +main::@1: scope:[main] from main main::@3 + (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@3/(byte~) main::i#3 ) + (word) main::b#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@3/(word~) main::b#3 ) + (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 + (byte) main::i#1 ← ++ (byte) main::i#2 + if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@3 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return +main::@3: scope:[main] from main::@1 + (word~) main::b#3 ← (word) main::b#1 + (byte~) main::i#3 ← (byte) main::i#1 + to:main::@1 + +Adding NOP phi() at start of main +CALL GRAPH +Calls in [] to main:0 + +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - LIVE RANGES FOUND +@begin: scope:[] from + to:@1 +@1: scope:[] from @begin + [0] call main param-assignment [ ] + to:@end +@end: scope:[] from @1 +main: scope:[main] from @1 + [1] phi() [ ] + to:main::@1 +main::@1: scope:[main] from main main::@3 + [2] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@3/(byte~) main::i#3 ) [ main::b#2 main::i#2 ] + [2] (word) main::b#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@3/(word~) main::b#3 ) [ main::b#2 main::i#2 ] + [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] + [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] + [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@3 [ main::b#1 main::i#1 ] + to:main::@return +main::@return: scope:[main] from main::@1 + [6] return [ ] + to:@return +main::@3: scope:[main] from main::@1 + [7] (word~) main::b#3 ← (word) main::b#1 [ main::b#3 main::i#1 ] + [8] (byte~) main::i#3 ← (byte) main::i#1 [ main::b#3 main::i#3 ] + to:main::@1 + +Created 2 initial phi equivalence classes +Coalesced [7] main::b#3 ← main::b#1 +Coalesced [8] main::i#3 ← main::i#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block (label) main::@3 +Block Sequence Planned @begin @1 @end main main::@1 main::@return +Adding NOP phi() at start of main +Propagating live ranges... +Propagating live ranges... +Propagating live ranges... +CONTROL FLOW GRAPH - BEFORE EFFECTIVE LIVE RANGES +@begin: scope:[] from + to:@1 +@1: scope:[] from @begin + [0] call main param-assignment [ ] + to:@end +@end: scope:[] from @1 +main: scope:[main] from @1 + [1] phi() [ ] + to:main::@1 +main::@1: scope:[main] from main main::@1 + [2] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(byte) main::i#1 ) [ main::b#2 main::i#2 ] + [2] (word) main::b#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(word) main::b#1 ) [ main::b#2 main::i#2 ] + [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] + [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] + [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] + to:main::@return +main::@return: scope:[main] from main::@1 + [6] return [ ] + to:@return + +CONTROL FLOW GRAPH - PHI MEM COALESCED +@begin: scope:[] from + to:@1 +@1: scope:[] from @begin + [0] call main param-assignment [ ] ( ) + to:@end +@end: scope:[] from @1 +main: scope:[main] from @1 + [1] phi() [ ] ( main:0 [ ] ) + to:main::@1 +main::@1: scope:[main] from main main::@1 + [2] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(byte) main::i#1 ) [ main::b#2 main::i#2 ] ( main:0 [ main::b#2 main::i#2 ] ) + [2] (word) main::b#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(word) main::b#1 ) [ main::b#2 main::i#2 ] ( main:0 [ main::b#2 main::i#2 ] ) + [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) + [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) + [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) + to:main::@return +main::@return: scope:[main] from main::@1 + [6] return [ ] ( main:0 [ ] ) + to:@return + +DOMINATORS +@begin dominated by @begin +@1 dominated by @1 @begin +@end dominated by @1 @begin @end +main dominated by @1 @begin main +main::@1 dominated by @1 @begin main::@1 main +main::@return dominated by main::@return @1 @begin main::@1 main + +Found back edge: Loop head: main::@1 tails: main::@1 blocks: null +Populated: Loop head: main::@1 tails: main::@1 blocks: main::@1 +NATURAL LOOPS +Loop head: main::@1 tails: main::@1 blocks: main::@1 + +Found 0 loops in scope [] +Found 1 loops in scope [main] + Loop head: main::@1 tails: main::@1 blocks: main::@1 +NATURAL LOOPS WITH DEPTH +Loop head: main::@1 tails: main::@1 blocks: main::@1 depth: 1 + + +VARIABLE REGISTER WEIGHTS +(void()) main() +(word) main::b +(word) main::b#1 7.333333333333333 +(word) main::b#2 22.0 +(byte) main::i +(byte) main::i#1 16.5 +(byte) main::i#2 11.0 + +Initial phi equivalence classes +[ main::b#2 main::b#1 ] +[ main::i#2 main::i#1 ] +Complete equivalence classes +[ main::b#2 main::b#1 ] +[ main::i#2 main::i#1 ] +Allocated zp ZP_WORD:2 [ main::b#2 main::b#1 ] +Allocated zp ZP_BYTE:4 [ main::i#2 main::i#1 ] +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: + jmp b1 +//SEG3 @1 +b1: +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main + jmp bend +//SEG6 @end +bend: +//SEG7 main +main: { + .label b = 2 + .label i = 4 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG9 [2] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- zpby1=coby1 + lda #0 + sta i + //SEG10 [2] phi (word) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- zpwo1=coby1 + lda #0 + sta b + lda #0 + sta b+1 + jmp b1 + //SEG11 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG12 [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG13 [2] phi (word) main::b#2 = (word) main::b#1 [phi:main::@1->main::@1#1] -- register_copy + jmp b1 + //SEG14 main::@1 + b1: + //SEG15 [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) -- zpwo1=zpwo1_plus_cowo1 + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + //SEG16 [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- zpby1=_inc_zpby1 + inc i + //SEG17 [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- zpby1_neq_coby1_then_la1 + lda i + cmp #$b + bne b1_from_b1 + jmp breturn + //SEG18 main::@return + breturn: + //SEG19 [6] return [ ] ( main:0 [ ] ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::i#2 main::i#1 ] +Statement [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ main::b#2 main::b#1 ] : zp ZP_WORD:2 , +Potential registers zp ZP_BYTE:4 [ main::i#2 main::i#1 ] : zp ZP_BYTE:4 , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 29.33: zp ZP_WORD:2 [ main::b#2 main::b#1 ] 27.5: zp ZP_BYTE:4 [ main::i#2 main::i#1 ] +Uplift Scope [] + +Uplifting [main] best 530 combination zp ZP_WORD:2 [ main::b#2 main::b#1 ] reg byte x [ main::i#2 main::i#1 ] +Uplifting [] best 530 combination +Removing instruction jmp b1 +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 @1 +b1: +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG6 @end +bend: +//SEG7 main +main: { + .label b = 2 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG9 [2] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi (word) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- zpwo1=coby1 + lda #0 + sta b + lda #0 + sta b+1 + jmp b1 + //SEG11 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG12 [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG13 [2] phi (word) main::b#2 = (word) main::b#1 [phi:main::@1->main::@1#1] -- register_copy + //SEG14 main::@1 + b1: + //SEG15 [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) -- zpwo1=zpwo1_plus_cowo1 + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + //SEG16 [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby=_inc_xby + inx + //SEG17 [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$b + bne b1_from_b1 + //SEG18 main::@return + breturn: + //SEG19 [6] return [ ] ( main:0 [ ] ) + rts +} + +Replacing instruction lda #0 with TXA +Removing instruction lda #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +bbegin: +//SEG3 @1 +b1: +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @1 to main [phi:@1->main] +main_from_b1: + jsr main +//SEG6 @end +bend: +//SEG7 main +main: { + .label b = 2 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG9 [2] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi (word) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- zpwo1=coby1 + txa + sta b + sta b+1 + jmp b1 + //SEG11 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + b1_from_b1: + //SEG12 [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG13 [2] phi (word) main::b#2 = (word) main::b#1 [phi:main::@1->main::@1#1] -- register_copy + //SEG14 main::@1 + b1: + //SEG15 [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) -- zpwo1=zpwo1_plus_cowo1 + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + //SEG16 [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby=_inc_xby + inx + //SEG17 [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$b + bne b1_from_b1 + //SEG18 main::@return + breturn: + //SEG19 [6] return [ ] ( main:0 [ ] ) + rts +} + +Replacing label b1_from_b1 with b1 +Removing instruction bbegin: +Removing instruction main_from_b1: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 @1 +b1: +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @1 to main [phi:@1->main] + jsr main +//SEG6 @end +bend: +//SEG7 main +main: { + .label b = 2 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + b1_from_main: + //SEG9 [2] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi (word) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- zpwo1=coby1 + txa + sta b + sta b+1 + jmp b1 + //SEG11 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG12 [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG13 [2] phi (word) main::b#2 = (word) main::b#1 [phi:main::@1->main::@1#1] -- register_copy + //SEG14 main::@1 + b1: + //SEG15 [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) -- zpwo1=zpwo1_plus_cowo1 + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + //SEG16 [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby=_inc_xby + inx + //SEG17 [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$b + bne b1 + //SEG18 main::@return + breturn: + //SEG19 [6] return [ ] ( main:0 [ ] ) + rts +} + +Removing instruction b1: +Removing instruction bend: +Removing instruction b1_from_main: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 @1 +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @1 to main [phi:@1->main] + jsr main +//SEG6 @end +//SEG7 main +main: { + .label b = 2 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + //SEG9 [2] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi (word) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- zpwo1=coby1 + txa + sta b + sta b+1 + jmp b1 + //SEG11 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG12 [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG13 [2] phi (word) main::b#2 = (word) main::b#1 [phi:main::@1->main::@1#1] -- register_copy + //SEG14 main::@1 + b1: + //SEG15 [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) -- zpwo1=zpwo1_plus_cowo1 + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + //SEG16 [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby=_inc_xby + inx + //SEG17 [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$b + bne b1 + //SEG18 main::@return + //SEG19 [6] return [ ] ( main:0 [ ] ) + rts +} + +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 @1 +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @1 to main [phi:@1->main] + jsr main +//SEG6 @end +//SEG7 main +main: { + .label b = 2 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + //SEG9 [2] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi (word) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- zpwo1=coby1 + txa + sta b + sta b+1 + //SEG11 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG12 [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG13 [2] phi (word) main::b#2 = (word) main::b#1 [phi:main::@1->main::@1#1] -- register_copy + //SEG14 main::@1 + b1: + //SEG15 [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) -- zpwo1=zpwo1_plus_cowo1 + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + //SEG16 [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby=_inc_xby + inx + //SEG17 [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$b + bne b1 + //SEG18 main::@return + //SEG19 [6] return [ ] ( main:0 [ ] ) + rts +} + +FINAL SYMBOL TABLE +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@return +(word) main::b +(word) main::b#1 b zp ZP_WORD:2 7.333333333333333 +(word) main::b#2 b zp ZP_WORD:2 22.0 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 11.0 + +zp ZP_WORD:2 [ main::b#2 main::b#1 ] +reg byte x [ main::i#2 main::i#1 ] + +FINAL CODE +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels +//SEG2 @begin +//SEG3 @1 +//SEG4 [0] call main param-assignment [ ] ( ) +//SEG5 [1] phi from @1 to main [phi:@1->main] + jsr main +//SEG6 @end +//SEG7 main +main: { + .label b = 2 + //SEG8 [2] phi from main to main::@1 [phi:main->main::@1] + //SEG9 [2] phi (byte) main::i#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#0] -- xby=coby1 + ldx #0 + //SEG10 [2] phi (word) main::b#2 = (byte/signed byte/word/signed word) 0 [phi:main->main::@1#1] -- zpwo1=coby1 + txa + sta b + sta b+1 + //SEG11 [2] phi from main::@1 to main::@1 [phi:main::@1->main::@1] + //SEG12 [2] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy + //SEG13 [2] phi (word) main::b#2 = (word) main::b#1 [phi:main::@1->main::@1#1] -- register_copy + //SEG14 main::@1 + b1: + //SEG15 [3] (word) main::b#1 ← (word) main::b#2 + (byte/signed byte/word/signed word) 40*(byte/signed byte/word/signed word) 8 [ main::i#2 main::b#1 ] ( main:0 [ main::i#2 main::b#1 ] ) -- zpwo1=zpwo1_plus_cowo1 + lda b + clc + adc #<$28*8 + sta b + lda b+1 + adc #>$28*8 + sta b+1 + //SEG16 [4] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby=_inc_xby + inx + //SEG17 [5] if((byte) main::i#1!=(byte/signed byte/word/signed word) 11) goto main::@1 [ main::b#1 main::i#1 ] ( main:0 [ main::b#1 main::i#1 ] ) -- xby_neq_coby1_then_la1 + cpx #$b + bne b1 + //SEG18 main::@return + //SEG19 [6] return [ ] ( main:0 [ ] ) + rts +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.sym b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.sym new file mode 100644 index 000000000..5caacaff6 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/wordexpr.sym @@ -0,0 +1,15 @@ +(label) @1 +(label) @begin +(label) @end +(void()) main() +(label) main::@1 +(label) main::@return +(word) main::b +(word) main::b#1 b zp ZP_WORD:2 7.333333333333333 +(word) main::b#2 b zp ZP_WORD:2 22.0 +(byte) main::i +(byte) main::i#1 reg byte x 16.5 +(byte) main::i#2 reg byte x 11.0 + +zp ZP_WORD:2 [ main::b#2 main::b#1 ] +reg byte x [ main::i#2 main::i#1 ] diff --git a/src/main/java/dk/camelot64/kickc/test/wordexpr.kc b/src/main/java/dk/camelot64/kickc/test/wordexpr.kc index 294fd80ca..510c7c7ee 100644 --- a/src/main/java/dk/camelot64/kickc/test/wordexpr.kc +++ b/src/main/java/dk/camelot64/kickc/test/wordexpr.kc @@ -1,5 +1,4 @@ -// Expressions based on bytes but resulting in words are erroneously type infered as bytes - eg. b = b + 40*8; - +// Expressions based on bytes but resulting in words are as words - eg. b = b + 40*8; void main() { word b = 0; for(byte i : 0..10) {