1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-25 20:32:25 +00:00

Now supports \xnn syntax for all values - even those without a proper encoding. Closes #383

This commit is contained in:
jespergravgaard 2020-04-11 09:13:22 +02:00
parent e506732779
commit f42a921d2b
14 changed files with 744 additions and 175 deletions

View File

@ -34,8 +34,12 @@ public class AsmFormat {
return getAsmBool(((ConstantBool) value).getBool());
} else if(value instanceof ConstantChar) {
ConstantChar constantChar = (ConstantChar) value;
if(!constantChar.getEncoding().hasEncoding(constantChar.getChar()))
return getAsmNumber(constantChar.getInteger());
else {
String escapedChar = constantChar.getCharEscaped();
return "'" + escapedChar + "'";
}
} else if(value instanceof ConstantString) {
String stringValue = ((ConstantString) value).getValue();
String escapedString = ((ConstantString) value).getStringEscaped();

View File

@ -14,6 +14,14 @@ public enum StringEncoding {
SCREENCODE_MIXED("screencode_mixed", "sm", CharToPetsciiConverter.charToScreenCode_mixed),
SCREENCODE_UPPER("screencode_upper", "su", CharToPetsciiConverter.charToScreenCode_upper);
/** Char value used to encode \xnn chars without a value within the chosen encoding. A char C is encoded as CHAR_SPECIAL_VAL+C */
public static final char CHAR_SPECIAL_VAL = 64000;
/** The minimal value of a specially encoded char. */
public static final char CHAR_SPECIAL_MIN = CHAR_SPECIAL_VAL + Byte.MIN_VALUE;
/** The maximal value of a specially encoded char. */
public static final char CHAR_SPECIAL_MAX = CHAR_SPECIAL_VAL + Byte.MAX_VALUE;
/** The encoding name. */
public final String name;
@ -72,9 +80,24 @@ public enum StringEncoding {
*/
public Long encodedFromChar(Character aChar) {
Byte encodedValue = mapping.get(aChar);
if(encodedValue != null)
return encodedValue.longValue();
else
// Char is not in encoding - it must be made up!
return (long) aChar - CHAR_SPECIAL_VAL;
}
/**
* Determine if a character has en encoding within the specific encoding
* @param aChar The char to examine
* @return true if the char has a proper encoding. False if it does not.
*/
public boolean hasEncoding(Character aChar) {
Byte encodedValue = mapping.get(aChar);
return encodedValue != null;
}
/**
* Get UNICODE/ASCII character for a specific encoded integer value using the specific encoding
*
@ -86,7 +109,8 @@ public enum StringEncoding {
if(mapEntry.getValue() == encodedValue.byteValue())
return mapEntry.getKey();
}
return null;
// If the mapping does not handle the Char - make one up
return (char) (CHAR_SPECIAL_VAL + encodedValue);
}
/**
@ -171,9 +195,12 @@ public enum StringEncoding {
return Character.toString(aChar);
case '\\':
return "\\\\";
default:
return Character.toString(aChar);
}
if(aChar >= CHAR_SPECIAL_MIN && aChar <= CHAR_SPECIAL_MAX) {
final byte charValue = (byte) (aChar - CHAR_SPECIAL_VAL);
return String.format("\\$%x", charValue);
} else
return Character.toString(aChar);
}
/**
@ -188,5 +215,4 @@ public enum StringEncoding {
return escaped.toString();
}
}

View File

@ -641,11 +641,6 @@ public class TestPrograms {
compileAndCompare("code-after-return");
}
@Test
public void testStringEscapesErr2() throws IOException, URISyntaxException {
assertError("string-escapes-err-2", "No character 0xff in encoding petscii_mixed");
}
@Test
public void testStringEscapesErr1() throws IOException, URISyntaxException {
assertError("string-escapes-err-1", "Illegal string escape sequence");
@ -656,6 +651,11 @@ public class TestPrograms {
assertError("string-escapes-err-0", "Unfinished string escape sequence at end of string");
}
@Test
public void testStringEscapes5() throws IOException, URISyntaxException {
compileAndCompare("string-escapes-5");
}
@Test
public void testStringEscapes4() throws IOException, URISyntaxException {
compileAndCompare("string-escapes-4");

View File

@ -4,6 +4,8 @@
#pragma encoding(petscii_mixed)
char MESSAGE[] = "hello\nworld";
char CH = '\n';
char* SCREEN = 0x0400;
void main() {
@ -23,4 +25,6 @@ void main() {
msg++;
}
SCREEN[0x50] = CH;
}

View File

@ -0,0 +1,16 @@
// Test using some simple supported string escape
// Uses \xnn to add chars by hex-code that do not exist with the encoding.
#pragma encoding(petscii_mixed)
char MESSAGE[] = "qwe\xffasd\xferty";
char CH = '\xff';
char * const SCREEN = 0x0400;
void main() {
char i=0;
while(MESSAGE[i])
SCREEN[i] = MESSAGE[i++];
SCREEN[0x28] = CH;
}

View File

@ -1,8 +0,0 @@
// Test errors using string escape sequences
// Unsupported hex character sequence
#pragma encoding(petscii_mixed)
char MESSAGE[] = "qwe\xff";
void main() {
}

View File

@ -3,6 +3,9 @@
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.encoding "petscii_mixed"
.const CH = '\n'
.label SCREEN = $400
main: {
.label cursor = 6
.label msg = 2
@ -25,6 +28,9 @@ main: {
lda (msg),y
cmp #0
bne __b2
// SCREEN[0x50] = CH
lda #CH
sta SCREEN+$50
// }
rts
__b2:
@ -32,11 +38,10 @@ main: {
// line += 0x28;
// cursor = line;
// break;
.encoding "petscii_mixed"
lda #'\n'
ldy #0
cmp (msg),y
beq __b3
beq __b4
// *msg & 0x3f
lda #$3f
and (msg),y
@ -47,14 +52,14 @@ main: {
bne !+
inc.z cursor+1
!:
__b5:
__b6:
// msg++;
inc.z msg
bne !+
inc.z msg+1
!:
jmp __b1
__b3:
__b4:
// line += 0x28
lda #$28
clc
@ -67,7 +72,7 @@ main: {
sta.z line
lda.z cursor+1
sta.z line+1
jmp __b5
jmp __b6
}
MESSAGE: .text @"hello\nworld"
.byte 0

View File

@ -12,30 +12,33 @@
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@5
[5] (byte*) main::cursor#3 ← phi( main/(byte*) 1024 main::@5/(byte*) main::cursor#6 )
[5] (byte*) main::line#2 ← phi( main/(byte*) 1024 main::@5/(byte*) main::line#5 )
[5] (byte*) main::msg#2 ← phi( main/(const byte*) MESSAGE main::@5/(byte*) main::msg#1 )
main::@1: scope:[main] from main main::@6
[5] (byte*) main::cursor#3 ← phi( main/(byte*) 1024 main::@6/(byte*) main::cursor#6 )
[5] (byte*) main::line#2 ← phi( main/(byte*) 1024 main::@6/(byte*) main::line#5 )
[5] (byte*) main::msg#2 ← phi( main/(const byte*) MESSAGE main::@6/(byte*) main::msg#1 )
[6] if((byte) 0!=*((byte*) main::msg#2)) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] *((const byte*) SCREEN+(byte) $50) ← (const byte) CH
to:main::@return
main::@return: scope:[main] from main::@1
[7] return
main::@return: scope:[main] from main::@3
[8] return
to:@return
main::@2: scope:[main] from main::@1
[8] if(*((byte*) main::msg#2)==(byte) '
'pm) goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[9] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f
[10] *((byte*) main::cursor#3) ← (byte~) main::$0
[11] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3
[9] if(*((byte*) main::msg#2)==(byte) '
'pm) goto main::@4
to:main::@5
main::@5: scope:[main] from main::@3 main::@4
[12] (byte*) main::cursor#6 ← phi( main::@3/(byte*) main::cursor#1 main::@4/(byte*) main::cursor#2 )
[12] (byte*) main::line#5 ← phi( main::@3/(byte*) main::line#8 main::@4/(byte*) main::line#2 )
[13] (byte*) main::msg#1 ← ++ (byte*) main::msg#2
main::@5: scope:[main] from main::@2
[10] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f
[11] *((byte*) main::cursor#3) ← (byte~) main::$0
[12] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3
to:main::@6
main::@6: scope:[main] from main::@4 main::@5
[13] (byte*) main::cursor#6 ← phi( main::@4/(byte*) main::cursor#1 main::@5/(byte*) main::cursor#2 )
[13] (byte*) main::line#5 ← phi( main::@4/(byte*) main::line#8 main::@5/(byte*) main::line#2 )
[14] (byte*) main::msg#1 ← ++ (byte*) main::msg#2
to:main::@1
main::@3: scope:[main] from main::@2
[14] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28
[15] (byte*) main::line#8 ← (byte*) main::cursor#1
to:main::@5
main::@4: scope:[main] from main::@2
[15] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28
[16] (byte*) main::line#8 ← (byte*) main::cursor#1
to:main::@6

View File

@ -1,7 +1,7 @@
Warning! Adding boolean cast to non-boolean condition *((byte*) main::msg)
Identified constant variable (byte) CH
Identified constant variable (byte*) SCREEN
Culled Empty Block (label) main::@9
Culled Empty Block (label) main::@3
Culled Empty Block (label) main::@10
Culled Empty Block (label) main::@11
Culled Empty Block (label) main::@12
@ -24,7 +24,7 @@ main::@1: scope:[main] from main main::@6
(byte*) main::msg#2 ← phi( main/(byte*) main::msg#0 main::@6/(byte*) main::msg#1 )
(bool~) main::$1 ← (number) 0 != *((byte*) main::msg#2)
if((bool~) main::$1) goto main::@2
to:main::@return
to:main::@3
main::@2: scope:[main] from main::@1
(byte*) main::cursor#4 ← phi( main::@1/(byte*) main::cursor#5 )
(byte*) main::line#3 ← phi( main::@1/(byte*) main::line#4 )
@ -32,6 +32,9 @@ main::@2: scope:[main] from main::@1
if(*((byte*) main::msg#3)==(byte) '
'pm) goto main::@4
to:main::@5
main::@3: scope:[main] from main::@1
*((const byte*) SCREEN + (number) $50) ← (const byte) CH
to:main::@return
main::@4: scope:[main] from main::@2
(byte*) main::msg#6 ← phi( main::@2/(byte*) main::msg#3 )
(byte*) main::line#2 ← phi( main::@2/(byte*) main::line#3 )
@ -52,7 +55,7 @@ main::@6: scope:[main] from main::@4 main::@5
(byte*) main::msg#5 ← phi( main::@4/(byte*) main::msg#6 main::@5/(byte*) main::msg#4 )
(byte*) main::msg#1 ← ++ (byte*) main::msg#5
to:main::@1
main::@return: scope:[main] from main::@1
main::@return: scope:[main] from main::@3
return
to:@return
@1: scope:[] from @begin
@ -67,13 +70,17 @@ SYMBOL TABLE SSA
(label) @2
(label) @begin
(label) @end
(const byte) CH = (byte) '
'pm
(const byte*) MESSAGE[] = (byte*) "hello
world"pm
(const byte*) SCREEN = (byte*)(number) $400
(void()) main()
(number~) main::$0
(bool~) main::$1
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@6
@ -104,16 +111,20 @@ world"pm
(byte*) main::msg#6
Adding number conversion cast (unumber) 0 in (bool~) main::$1 ← (number) 0 != *((byte*) main::msg#2)
Adding number conversion cast (unumber) $50 in *((const byte*) SCREEN + (number) $50) ← (const byte) CH
Adding number conversion cast (unumber) $28 in (byte*) main::line#1 ← (byte*) main::line#2 + (number) $28
Adding number conversion cast (unumber) $3f in (number~) main::$0 ← *((byte*) main::msg#4) & (number) $3f
Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← *((byte*) main::msg#4) & (unumber)(number) $3f
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast $50
Simplifying constant integer cast $28
Simplifying constant integer cast $3f
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) $50
Finalized unsigned number type (byte) $28
Finalized unsigned number type (byte) $3f
Successful SSA optimization PassNFinalizeNumberTypeConversions
@ -136,6 +147,8 @@ Inlining constant with var siblings (const byte*) main::msg#0
Constant inlined main::cursor#0 = (byte*) 1024
Constant inlined main::msg#0 = (const byte*) MESSAGE
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(SCREEN+$50)
Successful SSA optimization Pass2ConstantAdditionElimination
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
@ -145,18 +158,15 @@ CALL GRAPH
Calls in [] to main:2
Created 5 initial phi equivalence classes
Coalesced [13] main::line#9 ← main::line#2
Coalesced [14] main::cursor#9 ← main::cursor#2
Coalesced [17] main::msg#7 ← main::msg#1
Coalesced (already) [18] main::line#7 ← main::line#5
Coalesced [19] main::cursor#7 ← main::cursor#6
Not coalescing [21] main::line#8 ← main::cursor#1
Coalesced [22] main::cursor#8 ← main::cursor#1
Coalesced [14] main::line#9 ← main::line#2
Coalesced [15] main::cursor#9 ← main::cursor#2
Coalesced [18] main::msg#7 ← main::msg#1
Coalesced (already) [19] main::line#7 ← main::line#5
Coalesced [20] main::cursor#7 ← main::cursor#6
Not coalescing [22] main::line#8 ← main::cursor#1
Coalesced [23] main::cursor#8 ← main::cursor#1
Coalesced down to 3 phi equivalence classes
Culled Empty Block (label) @2
Renumbering block main::@4 to main::@3
Renumbering block main::@5 to main::@4
Renumbering block main::@6 to main::@5
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
@ -177,33 +187,36 @@ FINAL CONTROL FLOW GRAPH
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@5
[5] (byte*) main::cursor#3 ← phi( main/(byte*) 1024 main::@5/(byte*) main::cursor#6 )
[5] (byte*) main::line#2 ← phi( main/(byte*) 1024 main::@5/(byte*) main::line#5 )
[5] (byte*) main::msg#2 ← phi( main/(const byte*) MESSAGE main::@5/(byte*) main::msg#1 )
main::@1: scope:[main] from main main::@6
[5] (byte*) main::cursor#3 ← phi( main/(byte*) 1024 main::@6/(byte*) main::cursor#6 )
[5] (byte*) main::line#2 ← phi( main/(byte*) 1024 main::@6/(byte*) main::line#5 )
[5] (byte*) main::msg#2 ← phi( main/(const byte*) MESSAGE main::@6/(byte*) main::msg#1 )
[6] if((byte) 0!=*((byte*) main::msg#2)) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] *((const byte*) SCREEN+(byte) $50) ← (const byte) CH
to:main::@return
main::@return: scope:[main] from main::@1
[7] return
main::@return: scope:[main] from main::@3
[8] return
to:@return
main::@2: scope:[main] from main::@1
[8] if(*((byte*) main::msg#2)==(byte) '
'pm) goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[9] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f
[10] *((byte*) main::cursor#3) ← (byte~) main::$0
[11] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3
[9] if(*((byte*) main::msg#2)==(byte) '
'pm) goto main::@4
to:main::@5
main::@5: scope:[main] from main::@3 main::@4
[12] (byte*) main::cursor#6 ← phi( main::@3/(byte*) main::cursor#1 main::@4/(byte*) main::cursor#2 )
[12] (byte*) main::line#5 ← phi( main::@3/(byte*) main::line#8 main::@4/(byte*) main::line#2 )
[13] (byte*) main::msg#1 ← ++ (byte*) main::msg#2
main::@5: scope:[main] from main::@2
[10] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f
[11] *((byte*) main::cursor#3) ← (byte~) main::$0
[12] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3
to:main::@6
main::@6: scope:[main] from main::@4 main::@5
[13] (byte*) main::cursor#6 ← phi( main::@4/(byte*) main::cursor#1 main::@5/(byte*) main::cursor#2 )
[13] (byte*) main::line#5 ← phi( main::@4/(byte*) main::line#8 main::@5/(byte*) main::line#2 )
[14] (byte*) main::msg#1 ← ++ (byte*) main::msg#2
to:main::@1
main::@3: scope:[main] from main::@2
[14] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28
[15] (byte*) main::line#8 ← (byte*) main::cursor#1
to:main::@5
main::@4: scope:[main] from main::@2
[15] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28
[16] (byte*) main::line#8 ← (byte*) main::cursor#1
to:main::@6
VARIABLE REGISTER WEIGHTS
@ -247,6 +260,9 @@ Target platform is c64basic / MOS6502X
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.encoding "petscii_mixed"
.const CH = '\n'
.label SCREEN = $400
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
@ -294,58 +310,63 @@ main: {
lda (msg),y
cmp #0
bne __b2
jmp __b3
// main::@3
__b3:
// [7] *((const byte*) SCREEN+(byte) $50) ← (const byte) CH -- _deref_pbuc1=vbuc2
lda #CH
sta SCREEN+$50
jmp __breturn
// main::@return
__breturn:
// [7] return
// [8] return
rts
// main::@2
__b2:
// [8] if(*((byte*) main::msg#2)==(byte) ' 'pm) goto main::@3 -- _deref_pbuz1_eq_vbuc1_then_la1
.encoding "petscii_mixed"
// [9] if(*((byte*) main::msg#2)==(byte) ' 'pm) goto main::@4 -- _deref_pbuz1_eq_vbuc1_then_la1
lda #'\n'
ldy #0
cmp (msg),y
beq __b3
jmp __b4
// main::@4
__b4:
// [9] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f -- vbuz1=_deref_pbuz2_band_vbuc1
beq __b4
jmp __b5
// main::@5
__b5:
// [10] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f -- vbuz1=_deref_pbuz2_band_vbuc1
lda #$3f
ldy #0
and (msg),y
sta.z __0
// [10] *((byte*) main::cursor#3) ← (byte~) main::$0 -- _deref_pbuz1=vbuz2
// [11] *((byte*) main::cursor#3) ← (byte~) main::$0 -- _deref_pbuz1=vbuz2
lda.z __0
ldy #0
sta (cursor),y
// [11] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3 -- pbuz1=_inc_pbuz1
// [12] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3 -- pbuz1=_inc_pbuz1
inc.z cursor
bne !+
inc.z cursor+1
!:
// [12] phi from main::@3 main::@4 to main::@5 [phi:main::@3/main::@4->main::@5]
__b5_from___b3:
__b5_from___b4:
// [12] phi (byte*) main::cursor#6 = (byte*) main::cursor#1 [phi:main::@3/main::@4->main::@5#0] -- register_copy
// [12] phi (byte*) main::line#5 = (byte*) main::line#8 [phi:main::@3/main::@4->main::@5#1] -- register_copy
jmp __b5
// main::@5
__b5:
// [13] (byte*) main::msg#1 ← ++ (byte*) main::msg#2 -- pbuz1=_inc_pbuz1
// [13] phi from main::@4 main::@5 to main::@6 [phi:main::@4/main::@5->main::@6]
__b6_from___b4:
__b6_from___b5:
// [13] phi (byte*) main::cursor#6 = (byte*) main::cursor#1 [phi:main::@4/main::@5->main::@6#0] -- register_copy
// [13] phi (byte*) main::line#5 = (byte*) main::line#8 [phi:main::@4/main::@5->main::@6#1] -- register_copy
jmp __b6
// main::@6
__b6:
// [14] (byte*) main::msg#1 ← ++ (byte*) main::msg#2 -- pbuz1=_inc_pbuz1
inc.z msg
bne !+
inc.z msg+1
!:
// [5] phi from main::@5 to main::@1 [phi:main::@5->main::@1]
__b1_from___b5:
// [5] phi (byte*) main::cursor#3 = (byte*) main::cursor#6 [phi:main::@5->main::@1#0] -- register_copy
// [5] phi (byte*) main::line#2 = (byte*) main::line#5 [phi:main::@5->main::@1#1] -- register_copy
// [5] phi (byte*) main::msg#2 = (byte*) main::msg#1 [phi:main::@5->main::@1#2] -- register_copy
// [5] phi from main::@6 to main::@1 [phi:main::@6->main::@1]
__b1_from___b6:
// [5] phi (byte*) main::cursor#3 = (byte*) main::cursor#6 [phi:main::@6->main::@1#0] -- register_copy
// [5] phi (byte*) main::line#2 = (byte*) main::line#5 [phi:main::@6->main::@1#1] -- register_copy
// [5] phi (byte*) main::msg#2 = (byte*) main::msg#1 [phi:main::@6->main::@1#2] -- register_copy
jmp __b1
// main::@3
__b3:
// [14] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 -- pbuz1=pbuz2_plus_vbuc1
// main::@4
__b4:
// [15] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 -- pbuz1=pbuz2_plus_vbuc1
lda #$28
clc
adc.z line
@ -353,12 +374,12 @@ main: {
lda #0
adc.z line+1
sta.z cursor+1
// [15] (byte*) main::line#8 ← (byte*) main::cursor#1 -- pbuz1=pbuz2
// [16] (byte*) main::line#8 ← (byte*) main::cursor#1 -- pbuz1=pbuz2
lda.z cursor
sta.z line
lda.z cursor+1
sta.z line+1
jmp __b5_from___b3
jmp __b6_from___b4
}
// File Data
MESSAGE: .text @"hello\nworld"
@ -366,12 +387,13 @@ main: {
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] if((byte) 0!=*((byte*) main::msg#2)) goto main::@2 [ main::msg#2 main::line#2 main::cursor#3 ] ( main:2 [ main::msg#2 main::line#2 main::cursor#3 ] { } ) always clobbers reg byte a reg byte y
Statement [8] if(*((byte*) main::msg#2)==(byte) '
'pm) goto main::@3 [ main::msg#2 main::line#2 main::cursor#3 ] ( main:2 [ main::msg#2 main::line#2 main::cursor#3 ] { } ) always clobbers reg byte a reg byte y
Statement [9] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f [ main::msg#2 main::line#2 main::cursor#3 main::$0 ] ( main:2 [ main::msg#2 main::line#2 main::cursor#3 main::$0 ] { } ) always clobbers reg byte a reg byte y
Statement [10] *((byte*) main::cursor#3) ← (byte~) main::$0 [ main::msg#2 main::line#2 main::cursor#3 ] ( main:2 [ main::msg#2 main::line#2 main::cursor#3 ] { } ) always clobbers reg byte y
Statement [14] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 [ main::msg#2 main::cursor#1 ] ( main:2 [ main::msg#2 main::cursor#1 ] { } ) always clobbers reg byte a
Statement [15] (byte*) main::line#8 ← (byte*) main::cursor#1 [ main::msg#2 main::line#8 main::cursor#1 ] ( main:2 [ main::msg#2 main::line#8 main::cursor#1 ] { } ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN+(byte) $50) ← (const byte) CH [ ] ( main:2 [ ] { } ) always clobbers reg byte a
Statement [9] if(*((byte*) main::msg#2)==(byte) '
'pm) goto main::@4 [ main::msg#2 main::line#2 main::cursor#3 ] ( main:2 [ main::msg#2 main::line#2 main::cursor#3 ] { } ) always clobbers reg byte a reg byte y
Statement [10] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f [ main::msg#2 main::line#2 main::cursor#3 main::$0 ] ( main:2 [ main::msg#2 main::line#2 main::cursor#3 main::$0 ] { } ) always clobbers reg byte a reg byte y
Statement [11] *((byte*) main::cursor#3) ← (byte~) main::$0 [ main::msg#2 main::line#2 main::cursor#3 ] ( main:2 [ main::msg#2 main::line#2 main::cursor#3 ] { } ) always clobbers reg byte y
Statement [15] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 [ main::msg#2 main::cursor#1 ] ( main:2 [ main::msg#2 main::cursor#1 ] { } ) always clobbers reg byte a
Statement [16] (byte*) main::line#8 ← (byte*) main::cursor#1 [ main::msg#2 main::line#8 main::cursor#1 ] ( main:2 [ main::msg#2 main::line#8 main::cursor#1 ] { } ) always clobbers reg byte a
Potential registers zp[2]:2 [ main::msg#2 main::msg#1 ] : zp[2]:2 ,
Potential registers zp[2]:4 [ main::line#2 main::line#5 main::line#8 ] : zp[2]:4 ,
Potential registers zp[2]:6 [ main::cursor#3 main::cursor#6 main::cursor#1 main::cursor#2 ] : zp[2]:6 ,
@ -381,8 +403,8 @@ REGISTER UPLIFT SCOPES
Uplift Scope [main] 565.6: zp[2]:6 [ main::cursor#3 main::cursor#6 main::cursor#1 main::cursor#2 ] 404: zp[2]:4 [ main::line#2 main::line#5 main::line#8 ] 258.11: zp[2]:2 [ main::msg#2 main::msg#1 ] 202: zp[1]:8 [ main::$0 ]
Uplift Scope []
Uplifting [main] best 1463 combination zp[2]:6 [ main::cursor#3 main::cursor#6 main::cursor#1 main::cursor#2 ] zp[2]:4 [ main::line#2 main::line#5 main::line#8 ] zp[2]:2 [ main::msg#2 main::msg#1 ] reg byte a [ main::$0 ]
Uplifting [] best 1463 combination
Uplifting [main] best 1472 combination zp[2]:6 [ main::cursor#3 main::cursor#6 main::cursor#1 main::cursor#2 ] zp[2]:4 [ main::line#2 main::line#5 main::line#8 ] zp[2]:2 [ main::msg#2 main::msg#1 ] reg byte a [ main::$0 ]
Uplifting [] best 1472 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@ -393,6 +415,9 @@ ASSEMBLER BEFORE OPTIMIZATION
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.encoding "petscii_mixed"
.const CH = '\n'
.label SCREEN = $400
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
@ -439,56 +464,61 @@ main: {
lda (msg),y
cmp #0
bne __b2
jmp __b3
// main::@3
__b3:
// [7] *((const byte*) SCREEN+(byte) $50) ← (const byte) CH -- _deref_pbuc1=vbuc2
lda #CH
sta SCREEN+$50
jmp __breturn
// main::@return
__breturn:
// [7] return
// [8] return
rts
// main::@2
__b2:
// [8] if(*((byte*) main::msg#2)==(byte) ' 'pm) goto main::@3 -- _deref_pbuz1_eq_vbuc1_then_la1
.encoding "petscii_mixed"
// [9] if(*((byte*) main::msg#2)==(byte) ' 'pm) goto main::@4 -- _deref_pbuz1_eq_vbuc1_then_la1
lda #'\n'
ldy #0
cmp (msg),y
beq __b3
jmp __b4
// main::@4
__b4:
// [9] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f -- vbuaa=_deref_pbuz1_band_vbuc1
beq __b4
jmp __b5
// main::@5
__b5:
// [10] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f -- vbuaa=_deref_pbuz1_band_vbuc1
lda #$3f
ldy #0
and (msg),y
// [10] *((byte*) main::cursor#3) ← (byte~) main::$0 -- _deref_pbuz1=vbuaa
// [11] *((byte*) main::cursor#3) ← (byte~) main::$0 -- _deref_pbuz1=vbuaa
ldy #0
sta (cursor),y
// [11] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3 -- pbuz1=_inc_pbuz1
// [12] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3 -- pbuz1=_inc_pbuz1
inc.z cursor
bne !+
inc.z cursor+1
!:
// [12] phi from main::@3 main::@4 to main::@5 [phi:main::@3/main::@4->main::@5]
__b5_from___b3:
__b5_from___b4:
// [12] phi (byte*) main::cursor#6 = (byte*) main::cursor#1 [phi:main::@3/main::@4->main::@5#0] -- register_copy
// [12] phi (byte*) main::line#5 = (byte*) main::line#8 [phi:main::@3/main::@4->main::@5#1] -- register_copy
jmp __b5
// main::@5
__b5:
// [13] (byte*) main::msg#1 ← ++ (byte*) main::msg#2 -- pbuz1=_inc_pbuz1
// [13] phi from main::@4 main::@5 to main::@6 [phi:main::@4/main::@5->main::@6]
__b6_from___b4:
__b6_from___b5:
// [13] phi (byte*) main::cursor#6 = (byte*) main::cursor#1 [phi:main::@4/main::@5->main::@6#0] -- register_copy
// [13] phi (byte*) main::line#5 = (byte*) main::line#8 [phi:main::@4/main::@5->main::@6#1] -- register_copy
jmp __b6
// main::@6
__b6:
// [14] (byte*) main::msg#1 ← ++ (byte*) main::msg#2 -- pbuz1=_inc_pbuz1
inc.z msg
bne !+
inc.z msg+1
!:
// [5] phi from main::@5 to main::@1 [phi:main::@5->main::@1]
__b1_from___b5:
// [5] phi (byte*) main::cursor#3 = (byte*) main::cursor#6 [phi:main::@5->main::@1#0] -- register_copy
// [5] phi (byte*) main::line#2 = (byte*) main::line#5 [phi:main::@5->main::@1#1] -- register_copy
// [5] phi (byte*) main::msg#2 = (byte*) main::msg#1 [phi:main::@5->main::@1#2] -- register_copy
// [5] phi from main::@6 to main::@1 [phi:main::@6->main::@1]
__b1_from___b6:
// [5] phi (byte*) main::cursor#3 = (byte*) main::cursor#6 [phi:main::@6->main::@1#0] -- register_copy
// [5] phi (byte*) main::line#2 = (byte*) main::line#5 [phi:main::@6->main::@1#1] -- register_copy
// [5] phi (byte*) main::msg#2 = (byte*) main::msg#1 [phi:main::@6->main::@1#2] -- register_copy
jmp __b1
// main::@3
__b3:
// [14] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 -- pbuz1=pbuz2_plus_vbuc1
// main::@4
__b4:
// [15] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 -- pbuz1=pbuz2_plus_vbuc1
lda #$28
clc
adc.z line
@ -496,12 +526,12 @@ main: {
lda #0
adc.z line+1
sta.z cursor+1
// [15] (byte*) main::line#8 ← (byte*) main::cursor#1 -- pbuz1=pbuz2
// [16] (byte*) main::line#8 ← (byte*) main::cursor#1 -- pbuz1=pbuz2
lda.z cursor
sta.z line
lda.z cursor+1
sta.z line+1
jmp __b5_from___b3
jmp __b6_from___b4
}
// File Data
MESSAGE: .text @"hello\nworld"
@ -511,25 +541,27 @@ ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __b3
Removing instruction jmp __breturn
Removing instruction jmp __b4
Removing instruction jmp __b5
Removing instruction jmp __b6
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction ldy #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label __b5_from___b3 with __b5
Replacing label __b6_from___b4 with __b6
Removing instruction __b1_from___bbegin:
Removing instruction __b1:
Removing instruction main_from___b1:
Removing instruction __bend_from___b1:
Removing instruction __b5_from___b3:
Removing instruction __b5_from___b4:
Removing instruction __b6_from___b4:
Removing instruction __b6_from___b5:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __bend:
Removing instruction __b1_from_main:
Removing instruction __b3:
Removing instruction __breturn:
Removing instruction __b4:
Removing instruction __b1_from___b5:
Removing instruction __b5:
Removing instruction __b1_from___b6:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
@ -543,8 +575,11 @@ FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) CH = (byte) '
'pm
(const byte*) MESSAGE[] = (byte*) "hello
world"pm
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(byte~) main::$0 reg byte a 202.0
(label) main::@1
@ -552,6 +587,7 @@ world"pm
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@6
(label) main::@return
(byte*) main::cursor
(byte*) main::cursor#1 cursor zp[2]:6 151.5
@ -573,7 +609,7 @@ reg byte a [ main::$0 ]
FINAL ASSEMBLER
Score: 1291
Score: 1297
// File Comments
// Test using some simple supported string escape \n in both string and char
@ -583,6 +619,9 @@ Score: 1291
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.encoding "petscii_mixed"
.const CH = '\n'
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
@ -619,9 +658,14 @@ main: {
lda (msg),y
cmp #0
bne __b2
// main::@3
// SCREEN[0x50] = CH
// [7] *((const byte*) SCREEN+(byte) $50) ← (const byte) CH -- _deref_pbuc1=vbuc2
lda #CH
sta SCREEN+$50
// main::@return
// }
// [7] return
// [8] return
rts
// main::@2
__b2:
@ -629,46 +673,45 @@ main: {
// line += 0x28;
// cursor = line;
// break;
// [8] if(*((byte*) main::msg#2)==(byte) ' 'pm) goto main::@3 -- _deref_pbuz1_eq_vbuc1_then_la1
.encoding "petscii_mixed"
// [9] if(*((byte*) main::msg#2)==(byte) ' 'pm) goto main::@4 -- _deref_pbuz1_eq_vbuc1_then_la1
lda #'\n'
ldy #0
cmp (msg),y
beq __b3
// main::@4
beq __b4
// main::@5
// *msg & 0x3f
// [9] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f -- vbuaa=_deref_pbuz1_band_vbuc1
// [10] (byte~) main::$0 ← *((byte*) main::msg#2) & (byte) $3f -- vbuaa=_deref_pbuz1_band_vbuc1
lda #$3f
and (msg),y
// *cursor++ = *msg & 0x3f
// [10] *((byte*) main::cursor#3) ← (byte~) main::$0 -- _deref_pbuz1=vbuaa
// [11] *((byte*) main::cursor#3) ← (byte~) main::$0 -- _deref_pbuz1=vbuaa
sta (cursor),y
// *cursor++ = *msg & 0x3f;
// [11] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3 -- pbuz1=_inc_pbuz1
// [12] (byte*) main::cursor#2 ← ++ (byte*) main::cursor#3 -- pbuz1=_inc_pbuz1
inc.z cursor
bne !+
inc.z cursor+1
!:
// [12] phi from main::@3 main::@4 to main::@5 [phi:main::@3/main::@4->main::@5]
// [12] phi (byte*) main::cursor#6 = (byte*) main::cursor#1 [phi:main::@3/main::@4->main::@5#0] -- register_copy
// [12] phi (byte*) main::line#5 = (byte*) main::line#8 [phi:main::@3/main::@4->main::@5#1] -- register_copy
// main::@5
__b5:
// [13] phi from main::@4 main::@5 to main::@6 [phi:main::@4/main::@5->main::@6]
// [13] phi (byte*) main::cursor#6 = (byte*) main::cursor#1 [phi:main::@4/main::@5->main::@6#0] -- register_copy
// [13] phi (byte*) main::line#5 = (byte*) main::line#8 [phi:main::@4/main::@5->main::@6#1] -- register_copy
// main::@6
__b6:
// msg++;
// [13] (byte*) main::msg#1 ← ++ (byte*) main::msg#2 -- pbuz1=_inc_pbuz1
// [14] (byte*) main::msg#1 ← ++ (byte*) main::msg#2 -- pbuz1=_inc_pbuz1
inc.z msg
bne !+
inc.z msg+1
!:
// [5] phi from main::@5 to main::@1 [phi:main::@5->main::@1]
// [5] phi (byte*) main::cursor#3 = (byte*) main::cursor#6 [phi:main::@5->main::@1#0] -- register_copy
// [5] phi (byte*) main::line#2 = (byte*) main::line#5 [phi:main::@5->main::@1#1] -- register_copy
// [5] phi (byte*) main::msg#2 = (byte*) main::msg#1 [phi:main::@5->main::@1#2] -- register_copy
// [5] phi from main::@6 to main::@1 [phi:main::@6->main::@1]
// [5] phi (byte*) main::cursor#3 = (byte*) main::cursor#6 [phi:main::@6->main::@1#0] -- register_copy
// [5] phi (byte*) main::line#2 = (byte*) main::line#5 [phi:main::@6->main::@1#1] -- register_copy
// [5] phi (byte*) main::msg#2 = (byte*) main::msg#1 [phi:main::@6->main::@1#2] -- register_copy
jmp __b1
// main::@3
__b3:
// main::@4
__b4:
// line += 0x28
// [14] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 -- pbuz1=pbuz2_plus_vbuc1
// [15] (byte*) main::cursor#1 ← (byte*) main::line#2 + (byte) $28 -- pbuz1=pbuz2_plus_vbuc1
lda #$28
clc
adc.z line
@ -676,12 +719,12 @@ main: {
lda #0
adc.z line+1
sta.z cursor+1
// [15] (byte*) main::line#8 ← (byte*) main::cursor#1 -- pbuz1=pbuz2
// [16] (byte*) main::line#8 ← (byte*) main::cursor#1 -- pbuz1=pbuz2
lda.z cursor
sta.z line
lda.z cursor+1
sta.z line+1
jmp __b5
jmp __b6
}
// File Data
MESSAGE: .text @"hello\nworld"

View File

@ -1,8 +1,11 @@
(label) @1
(label) @begin
(label) @end
(const byte) CH = (byte) '
'pm
(const byte*) MESSAGE[] = (byte*) "hello
world"pm
(const byte*) SCREEN = (byte*) 1024
(void()) main()
(byte~) main::$0 reg byte a 202.0
(label) main::@1
@ -10,6 +13,7 @@ world"pm
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@6
(label) main::@return
(byte*) main::cursor
(byte*) main::cursor#1 cursor zp[2]:6 151.5

View File

@ -0,0 +1,30 @@
// Test using some simple supported string escape
// Uses \xnn to add chars by hex-code that do not exist with the encoding.
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
.encoding "petscii_mixed"
.const CH = -1
main: {
ldx #0
__b1:
// while(MESSAGE[i])
lda MESSAGE,x
cmp #0
bne __b2
// SCREEN[0x28] = CH
lda #CH
sta SCREEN+$28
// }
rts
__b2:
// SCREEN[i] = MESSAGE[i++]
lda MESSAGE,x
sta SCREEN,x
// SCREEN[i] = MESSAGE[i++];
inx
jmp __b1
}
MESSAGE: .text @"qwe\$ffasd\$ferty"
.byte 0

View File

@ -0,0 +1,28 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] *((const nomodify byte*) SCREEN+(byte) $28) ← (const byte) CH
to:main::@return
main::@return: scope:[main] from main::@3
[8] return
to:@return
main::@2: scope:[main] from main::@1
[9] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← *((const byte*) MESSAGE + (byte) main::i#2)
[10] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1

View File

@ -0,0 +1,398 @@
Warning! Adding boolean cast to non-boolean condition *((const byte*) MESSAGE + (byte) main::i)
Identified constant variable (byte) CH
Culled Empty Block (label) main::@4
Culled Empty Block (label) main::@5
Culled Empty Block (label) main::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
(void()) main()
main: scope:[main] from @1
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@2
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
(bool~) main::$0 ← (number) 0 != *((const byte*) MESSAGE + (byte) main::i#2)
if((bool~) main::$0) goto main::@2
to:main::@3
main::@2: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
*((const nomodify byte*) SCREEN + (byte) main::i#3) ← *((const byte*) MESSAGE + (byte) main::i#3)
(byte) main::i#1 ← ++ (byte) main::i#3
to:main::@1
main::@3: scope:[main] from main::@1
*((const nomodify byte*) SCREEN + (number) $28) ← (const byte) CH
to:main::@return
main::@return: scope:[main] from main::@3
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) CH = (byte) '刺'pm
(const byte*) MESSAGE[] = (byte*) "qwe刺asd茶rty"pm
(const nomodify byte*) SCREEN = (byte*)(number) $400
(void()) main()
(bool~) main::$0
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
Adding number conversion cast (unumber) 0 in (bool~) main::$0 ← (number) 0 != *((const byte*) MESSAGE + (byte) main::i#2)
Adding number conversion cast (unumber) $28 in *((const nomodify byte*) SCREEN + (number) $28) ← (const byte) CH
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast $28
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) $28
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::i#2 = main::i#3
Successful SSA optimization Pass2AliasElimination
Simple Condition (bool~) main::$0 [3] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte) main::i#0
Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(SCREEN+$28)
Successful SSA optimization Pass2ConstantAdditionElimination
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [12] main::i#4 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2
to:main::@3
main::@3: scope:[main] from main::@1
[7] *((const nomodify byte*) SCREEN+(byte) $28) ← (const byte) CH
to:main::@return
main::@return: scope:[main] from main::@3
[8] return
to:@return
main::@2: scope:[main] from main::@1
[9] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← *((const byte*) MESSAGE + (byte) main::i#2)
[10] (byte) main::i#1 ← ++ (byte) main::i#2
to:main::@1
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte) main::i
(byte) main::i#1 202.0
(byte) main::i#2 168.33333333333331
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
Allocated zp[1]:2 [ main::i#2 main::i#1 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test using some simple supported string escape
// Uses \xnn to add chars by hex-code that do not exist with the encoding.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.encoding "petscii_mixed"
.const CH = -1
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label i = 2
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// main::@1
__b1:
// [6] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2 -- vbuc1_neq_pbuc2_derefidx_vbuz1_then_la1
lda #0
ldy.z i
cmp MESSAGE,y
bne __b2
jmp __b3
// main::@3
__b3:
// [7] *((const nomodify byte*) SCREEN+(byte) $28) ← (const byte) CH -- _deref_pbuc1=vbuc2
lda #CH
sta SCREEN+$28
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
// main::@2
__b2:
// [9] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← *((const byte*) MESSAGE + (byte) main::i#2) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz1
ldy.z i
lda MESSAGE,y
sta SCREEN,y
// [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
MESSAGE: .text @"qwe\$ffasd\$ferty"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2 [ main::i#2 ] ( main:2 [ main::i#2 ] { } ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
Statement [7] *((const nomodify byte*) SCREEN+(byte) $28) ← (const byte) CH [ ] ( main:2 [ ] { } ) always clobbers reg byte a
Statement [9] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← *((const byte*) MESSAGE + (byte) main::i#2) [ main::i#2 ] ( main:2 [ main::i#2 ] { } ) always clobbers reg byte a
Statement [6] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2 [ main::i#2 ] ( main:2 [ main::i#2 ] { } ) always clobbers reg byte a
Statement [7] *((const nomodify byte*) SCREEN+(byte) $28) ← (const byte) CH [ ] ( main:2 [ ] { } ) always clobbers reg byte a
Statement [9] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← *((const byte*) MESSAGE + (byte) main::i#2) [ main::i#2 ] ( main:2 [ main::i#2 ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 370.33: zp[1]:2 [ main::i#2 main::i#1 ]
Uplift Scope []
Uplifting [main] best 342 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 342 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test using some simple supported string escape
// Uses \xnn to add chars by hex-code that do not exist with the encoding.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.encoding "petscii_mixed"
.const CH = -1
// @begin
__bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// main::@1
__b1:
// [6] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2 -- vbuc1_neq_pbuc2_derefidx_vbuxx_then_la1
lda MESSAGE,x
cmp #0
bne __b2
jmp __b3
// main::@3
__b3:
// [7] *((const nomodify byte*) SCREEN+(byte) $28) ← (const byte) CH -- _deref_pbuc1=vbuc2
lda #CH
sta SCREEN+$28
jmp __breturn
// main::@return
__breturn:
// [8] return
rts
// main::@2
__b2:
// [9] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← *((const byte*) MESSAGE + (byte) main::i#2) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuxx
lda MESSAGE,x
sta SCREEN,x
// [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
__b1_from___b2:
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
MESSAGE: .text @"qwe\$ffasd\$ferty"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __b3
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from___bbegin:
Removing instruction __b1:
Removing instruction main_from___b1:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __bend:
Removing instruction __b1_from_main:
Removing instruction __b3:
Removing instruction __breturn:
Removing instruction __b1_from___b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction __bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) CH = (byte) '刺'pm
(const byte*) MESSAGE[] = (byte*) "qwe刺asd茶rty"pm
(const nomodify byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 202.0
(byte) main::i#2 reg byte x 168.33333333333331
reg byte x [ main::i#2 main::i#1 ]
FINAL ASSEMBLER
Score: 267
// File Comments
// Test using some simple supported string escape
// Uses \xnn to add chars by hex-code that do not exist with the encoding.
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.encoding "petscii_mixed"
.const CH = -1
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// main::@1
__b1:
// while(MESSAGE[i])
// [6] if((byte) 0!=*((const byte*) MESSAGE + (byte) main::i#2)) goto main::@2 -- vbuc1_neq_pbuc2_derefidx_vbuxx_then_la1
lda MESSAGE,x
cmp #0
bne __b2
// main::@3
// SCREEN[0x28] = CH
// [7] *((const nomodify byte*) SCREEN+(byte) $28) ← (const byte) CH -- _deref_pbuc1=vbuc2
lda #CH
sta SCREEN+$28
// main::@return
// }
// [8] return
rts
// main::@2
__b2:
// SCREEN[i] = MESSAGE[i++]
// [9] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← *((const byte*) MESSAGE + (byte) main::i#2) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuxx
lda MESSAGE,x
sta SCREEN,x
// SCREEN[i] = MESSAGE[i++];
// [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
jmp __b1
}
// File Data
MESSAGE: .text @"qwe\$ffasd\$ferty"
.byte 0

View File

@ -0,0 +1,16 @@
(label) @1
(label) @begin
(label) @end
(const byte) CH = (byte) '刺'pm
(const byte*) MESSAGE[] = (byte*) "qwe刺asd茶rty"pm
(const nomodify byte*) SCREEN = (byte*) 1024
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 202.0
(byte) main::i#2 reg byte x 168.33333333333331
reg byte x [ main::i#2 main::i#1 ]