1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Fixed wordexpr problem. Improved type inference of binary/unary constants. Added sby->by fragment synthesis.

This commit is contained in:
jespergravgaard 2017-11-26 21:27:00 +01:00
parent ebb71b4130
commit ae167736d4
23 changed files with 3377 additions and 32 deletions

View File

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

View File

@ -111,6 +111,16 @@ public class AsmFragmentManager {
mapZpptrToWord3.put("zpwo1", "zpwo3");
mapZpptrToWord3.put("zpptrby1", "zpwo1");
mapZpptrToWord3.put("zpptrby2", "zpwo2");
Map<String, String> 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<FragmentSynthesis> 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) {

View File

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

View File

@ -0,0 +1,8 @@
lda {zpwo1}
clc
adc #<{cowo1}
sta {zpwo1}
lda {zpwo1}+1
adc #>{cowo1}
sta {zpwo1}+1

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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_cursor<char_cursor);
char_cursor = line_cursor;
}

View File

@ -0,0 +1,46 @@
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SCREEN = $400
.const SCREEN2 = SCREEN+$28*3
.const SCREEN3 = SCREEN+$28*6
.const SCREEN4 = SCREEN+$28*9
jsr main
main: {
ldx #0
b1:
stx $ff
lda #$c8
sec
sbc $ff
sta SCREEN,x
txa
eor #$ff
clc
adc #1
sta SCREEN2,x
inx
cpx #$65
bne b1
jsr w
rts
}
w: {
.const w1 = $514
.const w2 = $4e2
.const b = w1-w2
ldy #0
b1:
tya
clc
adc #$578-$546
tax
lda #b
sta SCREEN3,y
txa
sta SCREEN4,y
iny
cpy #$b
bne b1
rts
}

View File

@ -0,0 +1,40 @@
@begin: scope:[] from
to:@2
@2: scope:[] from @begin
[0] call main param-assignment [ ] ( )
to:@end
@end: scope:[] from @2
main: scope:[main] from @2
[1] phi() [ ] ( main:0 [ ] )
to:main::@1
main::@1: scope:[main] from main main::@1
[2] (byte) main::b#2 ← phi( main/(byte/signed byte/word/signed word) 0 main::@1/(byte) main::b#1 ) [ main::b#2 ] ( main:0 [ main::b#2 ] )
[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 ] )
[4] *((const byte*) SCREEN#0 + (byte) main::b#2) ← (byte) main::b2#0 [ main::b#2 ] ( main:0 [ main::b#2 ] )
[5] (signed byte~) main::$1 ← _sbyte_ (byte) main::b#2 [ main::b#2 main::$1 ] ( main:0 [ main::b#2 main::$1 ] )
[6] (signed byte) main::sb#0 ← - (signed byte~) main::$1 [ main::b#2 main::sb#0 ] ( main:0 [ main::b#2 main::sb#0 ] )
[7] (byte~) main::$3 ← _byte_ (signed byte) main::sb#0 [ main::b#2 main::$3 ] ( main:0 [ main::b#2 main::$3 ] )
[8] *((const byte*) SCREEN2#0 + (byte) main::b#2) ← (byte~) main::$3 [ main::b#2 ] ( main:0 [ main::b#2 ] )
[9] (byte) main::b#1 ← ++ (byte) main::b#2 [ main::b#1 ] ( main:0 [ main::b#1 ] )
[10] if((byte) main::b#1!=(byte/signed byte/word/signed word) 101) goto main::@1 [ main::b#1 ] ( main:0 [ main::b#1 ] )
to:main::@2
main::@2: scope:[main] from main::@1
[11] call w param-assignment [ ] ( main:0 [ ] )
to:main::@return
main::@return: scope:[main] from main::@2
[12] return [ ] ( main:0 [ ] )
to:@return
w: scope:[w] from main::@2
[13] phi() [ ] ( main:0::w:11 [ ] )
to:w::@1
w::@1: scope:[w] from w w::@1
[14] (byte) w::i#2 ← phi( w/(byte/signed byte/word/signed word) 0 w::@1/(byte) w::i#1 ) [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] )
[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 ] )
[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 ] )
[17] *((const byte*) SCREEN4#0 + (byte) w::i#2) ← (byte) w::b2#0 [ w::i#2 ] ( main:0::w:11 [ w::i#2 ] )
[18] (byte) w::i#1 ← ++ (byte) w::i#2 [ w::i#1 ] ( main:0::w:11 [ w::i#1 ] )
[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 ] )
to:w::@return
w::@return: scope:[w] from w::@1
[20] return [ ] ( main:0::w:11 [ ] )
to:@return

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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