1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-30 09:57:11 +00:00

Fixed literal strings initializing char* in array or struct. Closes #297

This commit is contained in:
jespergravgaard 2021-08-02 11:21:18 +02:00
parent 1898956932
commit 41c257a9df
12 changed files with 1275 additions and 768 deletions

View File

@ -15485,3 +15485,91 @@ bcc {la1}
sta $ff
cpy $ff
bcc {la1}
//FRAGMENT 0_neq_(qbuz1_derefidx_vbuc1)_derefidx_vbuz2_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vbsc1)_derefidx_vbuz2_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwuc1)_derefidx_vbuz2_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwsc1)_derefidx_vbuz2_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vduc1)_derefidx_vbuz2_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vdsc1)_derefidx_vbuz2_then_la1
NO_SYNTHESIS
//FRAGMENT pbuc1_derefidx_vbuz1=(qbuz2_derefidx_vbuc2)_derefidx_vbuz3
ldx {z1}
ldy #{c2}
lda ({z2}),y
sta $fe
iny
lda ({z2}),y
sta $ff
ldy {z3}
lda ($fe),y
sta {c1},x
//FRAGMENT 0_neq_(qbuz1_derefidx_vbuc1)_derefidx_vbuaa_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vbsc1)_derefidx_vbuaa_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwuc1)_derefidx_vbuaa_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwsc1)_derefidx_vbuaa_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vduc1)_derefidx_vbuaa_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vdsc1)_derefidx_vbuaa_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vbuc1)_derefidx_vbuxx_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vbsc1)_derefidx_vbuxx_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwuc1)_derefidx_vbuxx_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwsc1)_derefidx_vbuxx_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vduc1)_derefidx_vbuxx_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vdsc1)_derefidx_vbuxx_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vbuc1)_derefidx_vbuyy_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vbsc1)_derefidx_vbuyy_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwuc1)_derefidx_vbuyy_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vwsc1)_derefidx_vbuyy_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vduc1)_derefidx_vbuyy_then_la1
NO_SYNTHESIS
//FRAGMENT 0_neq_(qbuz1_derefidx_vdsc1)_derefidx_vbuyy_then_la1
NO_SYNTHESIS
//FRAGMENT qbuz1=qbuc1
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1
//FRAGMENT pbuc1_neq__deref_qbuz1_then_la1
ldy #0
lda #<{c1}
cmp ({z1}),y
bne {la1}
iny
lda #>{c1}
cmp ({z1}),y
bne {la1}
//FRAGMENT pbuz1=_deref_qbuz2
ldy #0
lda ({z2}),y
sta {z1}
iny
lda ({z2}),y
sta {z1}+1
//FRAGMENT qbuz1=qbuz1_plus_vbuc1
lda #{c1}
clc
adc {z1}
sta {z1}
bcc !+
inc {z1}+1
!:

View File

@ -497,6 +497,11 @@ public interface ProgramValue {
public void set(Value value) {
arrayList.getElements().set(idx, (ConstantValue) value);
}
public ConstantArrayList getArrayList() {
return arrayList;
}
}
/** Member of a constant struct value. */

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValue;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.statements.StatementCall;
import dk.camelot64.kickc.model.statements.StatementCallPrepare;
@ -10,10 +11,7 @@ import dk.camelot64.kickc.model.symbols.Scope;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantString;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.Value;
import dk.camelot64.kickc.model.values.*;
import java.util.List;
@ -28,7 +26,7 @@ public class Pass1ExtractInlineStrings extends Pass1Base {
@Override
public boolean step() {
ProgramValueIterator.execute(getGraph(), (programValue, currentStmt, stmtIt, currentBlock) -> {
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
String nameHint = null;
if(currentStmt instanceof StatementCall) {
StatementCall call = (StatementCall) currentStmt;
@ -55,11 +53,36 @@ public class Pass1ExtractInlineStrings extends Pass1Base {
}
}
}
Scope blockScope = Pass1ExtractInlineStrings.this.getProgram().getScope().getScope(currentBlock.getScope());
Value value = programValue.get();
if(value instanceof ConstantString) {
if(value instanceof ConstantString && currentStmt!=null) {
// String in statement expression
Scope blockScope = Pass1ExtractInlineStrings.this.getProgram().getScope().getScope(currentBlock.getScope());
Variable strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(blockScope, (ConstantString) programValue.get(), nameHint);
programValue.set(strConst.getRef());
} else if(value instanceof ConstantString && programValue instanceof ProgramValue.ProgramValueConstantStructMember) {
// Struct member initialization
final ProgramValue.ProgramValueConstantStructMember constantStructMember = (ProgramValue.ProgramValueConstantStructMember) programValue;
final SymbolVariableRef memberRef = constantStructMember.getMemberRef();
final Variable memberDef = getScope().getVar(memberRef);
if(memberDef.getType() instanceof SymbolTypePointer) {
if(((SymbolTypePointer) memberDef.getType()).getArraySpec()==null) {
// Member is not an array - create a string.
nameHint = memberDef.getFullName().replace("::","_").toLowerCase();
Variable strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(getScope(), (ConstantString) programValue.get(), nameHint);
programValue.set(strConst.getRef());
}
}
} else if(value instanceof ConstantString && programValue instanceof ProgramValue.ProgramValueConstantArrayElement) {
// Array element initialization
final ProgramValue.ProgramValueConstantArrayElement constantArrayElement = (ProgramValue.ProgramValueConstantArrayElement) programValue;
final SymbolType elementType = constantArrayElement.getArrayList().getElementType();
if(elementType instanceof SymbolTypePointer) {
if(((SymbolTypePointer) elementType).getArraySpec()==null) {
// Element is not an array - create a string.
Variable strConst = Pass1ExtractInlineStrings.this.createStringConstantVar(getScope(), (ConstantString) programValue.get(), null);
programValue.set(strConst.getRef());
}
}
}
});
return false;

View File

@ -2049,11 +2049,10 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("struct-ptr-30.c");
}
// TODO: Fix problem with structs containing pointer elements
//@Test
//public void testStructPtr29() throws IOException {
// compileAndCompare("struct-ptr-29.c");
//}
@Test
public void testStructPtr29() throws IOException {
compileAndCompare("struct-ptr-29.c");
}
@Test
public void testStructPtr28() throws IOException {
@ -3072,13 +3071,10 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("pointer-cast.c");
}
// TODO: Fix literal string array initialization. https://gitlab.com/camelot/kickc/issues/297
/*
@Test
public void testLiteralStringArray() throws IOException {
compileAndCompare("literal-string-array.c");
}
*/
@Test
public void testLiteralWordPointer0() throws IOException {

View File

@ -0,0 +1,79 @@
// Tests literal string array
// Commodore 64 PRG executable file
.file [name="literal-string-array.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.const SIZEOF_POINTER = 2
.label SCREEN = $400
.label NUL = 0
.segment Code
main: {
.label c = 4
.label msg = 2
ldx #0
lda #<msgs
sta.z msg
lda #>msgs
sta.z msg+1
__b1:
// while(*msg)
ldy #0
tya
cmp (msg),y
bne __b2
iny
cmp (msg),y
bne __b2
// }
rts
__b2:
// char* c = *msg
ldy #0
lda (msg),y
sta.z c
iny
lda (msg),y
sta.z c+1
__b3:
// while(*c)
ldy #0
lda (c),y
cmp #0
bne __b4
// msg++;
lda #SIZEOF_POINTER
clc
adc.z msg
sta.z msg
bcc !+
inc.z msg+1
!:
jmp __b1
__b4:
// SCREEN[i++] = *c++
ldy #0
lda (c),y
sta SCREEN,x
// SCREEN[i++] = *c++;
inx
inc.z c
bne !+
inc.z c+1
!:
jmp __b3
}
.segment Data
// Works
// char*[] msgs = { (char*)"hello", (char*)"cruel", (char*)"world", (char*)NUL };
// Not working
msgs: .word __0, __1, __2, NUL
__0: .text "hello"
.byte 0
__1: .text "cruel"
.byte 0
__2: .text "world"
.byte 0

View File

@ -0,0 +1,29 @@
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@5
[1] main::i#4 = phi( main/0, main::@5/main::i#2 )
[1] main::msg#2 = phi( main/msgs, main::@5/main::msg#1 )
[2] if((byte*)0!=*main::msg#2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] main::c#0 = *main::msg#2
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
[5] main::i#2 = phi( main::@2/main::i#4, main::@4/main::i#1 )
[5] main::c#2 = phi( main::@2/main::c#0, main::@4/main::c#1 )
[6] if(0!=*main::c#2) goto main::@4
to:main::@5
main::@5: scope:[main] from main::@3
[7] main::msg#1 = main::msg#2 + SIZEOF_POINTER
to:main::@1
main::@4: scope:[main] from main::@3
[8] SCREEN[main::i#2] = *main::c#2
[9] main::i#1 = ++ main::i#2
[10] main::c#1 = ++ main::c#2
to:main::@3

View File

@ -0,0 +1,483 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
main::i#0 = 0
main::msg#0 = msgs
to:main::@1
main::@1: scope:[main] from main main::@5
main::i#5 = phi( main/main::i#0, main::@5/main::i#6 )
main::msg#2 = phi( main/main::msg#0, main::@5/main::msg#1 )
main::$0 = (byte*)0 != *main::msg#2
if(main::$0) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
main::i#4 = phi( main::@1/main::i#5 )
main::msg#3 = phi( main::@1/main::msg#2 )
main::c#0 = *main::msg#3
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
main::msg#5 = phi( main::@2/main::msg#3, main::@4/main::msg#6 )
main::i#3 = phi( main::@2/main::i#4, main::@4/main::i#1 )
main::c#2 = phi( main::@2/main::c#0, main::@4/main::c#1 )
main::$1 = 0 != *main::c#2
if(main::$1) goto main::@4
to:main::@5
main::@4: scope:[main] from main::@3
main::msg#6 = phi( main::@3/main::msg#5 )
main::i#2 = phi( main::@3/main::i#3 )
main::c#3 = phi( main::@3/main::c#2 )
SCREEN[main::i#2] = *main::c#3
main::i#1 = ++ main::i#2
main::c#1 = ++ main::c#3
to:main::@3
main::@5: scope:[main] from main::@3
main::i#6 = phi( main::@3/main::i#3 )
main::msg#4 = phi( main::@3/main::msg#5 )
main::msg#1 = main::msg#4 + SIZEOF_POINTER
to:main::@1
main::@return: scope:[main] from main::@1
return
to:@return
void __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
constant byte* $0[6] = "hello"
constant byte* $1[6] = "cruel"
constant byte* $2[6] = "world"
constant void* const NUL = (void*)0
constant byte* const SCREEN = (byte*)$400
constant byte SIZEOF_POINTER = 2
void __start()
void main()
bool~ main::$0
bool~ main::$1
byte* main::c
byte* main::c#0
byte* main::c#1
byte* main::c#2
byte* main::c#3
byte main::i
byte main::i#0
byte main::i#1
byte main::i#2
byte main::i#3
byte main::i#4
byte main::i#5
byte main::i#6
byte** main::msg
byte** main::msg#0
byte** main::msg#1
byte** main::msg#2
byte** main::msg#3
byte** main::msg#4
byte** main::msg#5
byte** main::msg#6
constant byte** msgs[] = { $0, $1, $2, NUL }
Adding number conversion cast (unumber) 0 in main::$1 = 0 != *main::c#2
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant pointer cast (void*) 0
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias main::msg#2 = main::msg#3
Alias main::i#4 = main::i#5
Alias main::c#2 = main::c#3
Alias main::i#2 = main::i#3 main::i#6
Alias main::msg#4 = main::msg#6 main::msg#5
Successful SSA optimization Pass2AliasElimination
Identical Phi Values main::msg#4 main::msg#2
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition main::$0 [4] if((byte*)0!=*main::msg#2) goto main::@2
Simple Condition main::$1 [8] if(0!=*main::c#2) goto main::@4
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant main::i#0 = 0
Constant main::msg#0 = msgs
Successful SSA optimization Pass2ConstantIdentification
Removing unused procedure __start
Removing unused procedure block __start
Removing unused procedure block __start::@1
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Inlining constant with var siblings main::i#0
Inlining constant with var siblings main::msg#0
Constant inlined main::i#0 = 0
Constant inlined main::msg#0 = msgs
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of main
CALL GRAPH
Created 4 initial phi equivalence classes
Coalesced [5] main::c#4 = main::c#0
Coalesced [6] main::i#8 = main::i#4
Coalesced [10] main::msg#7 = main::msg#1
Coalesced (already) [11] main::i#7 = main::i#2
Coalesced [15] main::c#5 = main::c#1
Coalesced [16] main::i#9 = main::i#1
Coalesced down to 3 phi equivalence classes
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
void main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@5
[1] main::i#4 = phi( main/0, main::@5/main::i#2 )
[1] main::msg#2 = phi( main/msgs, main::@5/main::msg#1 )
[2] if((byte*)0!=*main::msg#2) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
main::@2: scope:[main] from main::@1
[4] main::c#0 = *main::msg#2
to:main::@3
main::@3: scope:[main] from main::@2 main::@4
[5] main::i#2 = phi( main::@2/main::i#4, main::@4/main::i#1 )
[5] main::c#2 = phi( main::@2/main::c#0, main::@4/main::c#1 )
[6] if(0!=*main::c#2) goto main::@4
to:main::@5
main::@5: scope:[main] from main::@3
[7] main::msg#1 = main::msg#2 + SIZEOF_POINTER
to:main::@1
main::@4: scope:[main] from main::@3
[8] SCREEN[main::i#2] = *main::c#2
[9] main::i#1 = ++ main::i#2
[10] main::c#1 = ++ main::c#2
to:main::@3
VARIABLE REGISTER WEIGHTS
void main()
byte* main::c
byte* main::c#0 22.0
byte* main::c#1 202.0
byte* main::c#2 103.75
byte main::i
byte main::i#1 101.0
byte main::i#2 81.25
byte main::i#4 7.333333333333333
byte** main::msg
byte** main::msg#1 22.0
byte** main::msg#2 5.5
Initial phi equivalence classes
[ main::msg#2 main::msg#1 ]
[ main::i#4 main::i#2 main::i#1 ]
[ main::c#2 main::c#0 main::c#1 ]
Complete equivalence classes
[ main::msg#2 main::msg#1 ]
[ main::i#4 main::i#2 main::i#1 ]
[ main::c#2 main::c#0 main::c#1 ]
Allocated zp[2]:2 [ main::msg#2 main::msg#1 ]
Allocated zp[1]:4 [ main::i#4 main::i#2 main::i#1 ]
Allocated zp[2]:5 [ main::c#2 main::c#0 main::c#1 ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] if((byte*)0!=*main::msg#2) goto main::@2 [ main::msg#2 main::i#4 ] ( [ main::msg#2 main::i#4 ] { } ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::i#4 main::i#2 main::i#1 ]
Removing always clobbered register reg byte y as potential for zp[1]:4 [ main::i#4 main::i#2 main::i#1 ]
Statement [4] main::c#0 = *main::msg#2 [ main::msg#2 main::i#4 main::c#0 ] ( [ main::msg#2 main::i#4 main::c#0 ] { } ) always clobbers reg byte a reg byte y
Statement [6] if(0!=*main::c#2) goto main::@4 [ main::msg#2 main::i#2 main::c#2 ] ( [ main::msg#2 main::i#2 main::c#2 ] { } ) always clobbers reg byte a reg byte y
Statement [7] main::msg#1 = main::msg#2 + SIZEOF_POINTER [ main::msg#1 main::i#2 ] ( [ main::msg#1 main::i#2 ] { } ) always clobbers reg byte a
Statement [8] SCREEN[main::i#2] = *main::c#2 [ main::msg#2 main::i#2 main::c#2 ] ( [ main::msg#2 main::i#2 main::c#2 ] { } ) always clobbers reg byte a reg byte y
Statement [2] if((byte*)0!=*main::msg#2) goto main::@2 [ main::msg#2 main::i#4 ] ( [ main::msg#2 main::i#4 ] { } ) always clobbers reg byte a reg byte y
Statement [4] main::c#0 = *main::msg#2 [ main::msg#2 main::i#4 main::c#0 ] ( [ main::msg#2 main::i#4 main::c#0 ] { } ) always clobbers reg byte a reg byte y
Statement [6] if(0!=*main::c#2) goto main::@4 [ main::msg#2 main::i#2 main::c#2 ] ( [ main::msg#2 main::i#2 main::c#2 ] { } ) always clobbers reg byte a reg byte y
Statement [7] main::msg#1 = main::msg#2 + SIZEOF_POINTER [ main::msg#1 main::i#2 ] ( [ main::msg#1 main::i#2 ] { } ) always clobbers reg byte a
Statement [8] SCREEN[main::i#2] = *main::c#2 [ main::msg#2 main::i#2 main::c#2 ] ( [ main::msg#2 main::i#2 main::c#2 ] { } ) always clobbers reg byte a reg byte y
Potential registers zp[2]:2 [ main::msg#2 main::msg#1 ] : zp[2]:2 ,
Potential registers zp[1]:4 [ main::i#4 main::i#2 main::i#1 ] : zp[1]:4 , reg byte x ,
Potential registers zp[2]:5 [ main::c#2 main::c#0 main::c#1 ] : zp[2]:5 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 327.75: zp[2]:5 [ main::c#2 main::c#0 main::c#1 ] 189.58: zp[1]:4 [ main::i#4 main::i#2 main::i#1 ] 27.5: zp[2]:2 [ main::msg#2 main::msg#1 ]
Uplift Scope []
Uplifting [main] best 5641 combination zp[2]:5 [ main::c#2 main::c#0 main::c#1 ] reg byte x [ main::i#4 main::i#2 main::i#1 ] zp[2]:2 [ main::msg#2 main::msg#1 ]
Uplifting [] best 5641 combination
Allocated (was zp[2]:5) zp[2]:4 [ main::c#2 main::c#0 main::c#1 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Tests literal string array
// Upstart
// Commodore 64 PRG executable file
.file [name="literal-string-array.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const SIZEOF_POINTER = 2
.label SCREEN = $400
.label NUL = 0
.segment Code
// main
main: {
.label c = 4
.label msg = 2
// [1] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [1] phi main::i#4 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// [1] phi main::msg#2 = msgs [phi:main->main::@1#1] -- qbuz1=qbuc1
lda #<msgs
sta.z msg
lda #>msgs
sta.z msg+1
jmp __b1
// main::@1
__b1:
// [2] if((byte*)0!=*main::msg#2) goto main::@2 -- pbuc1_neq__deref_qbuz1_then_la1
ldy #0
lda #<0
cmp (msg),y
bne __b2
iny
lda #>0
cmp (msg),y
bne __b2
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
// main::@2
__b2:
// [4] main::c#0 = *main::msg#2 -- pbuz1=_deref_qbuz2
ldy #0
lda (msg),y
sta.z c
iny
lda (msg),y
sta.z c+1
// [5] phi from main::@2 main::@4 to main::@3 [phi:main::@2/main::@4->main::@3]
__b3_from___b2:
__b3_from___b4:
// [5] phi main::i#2 = main::i#4 [phi:main::@2/main::@4->main::@3#0] -- register_copy
// [5] phi main::c#2 = main::c#0 [phi:main::@2/main::@4->main::@3#1] -- register_copy
jmp __b3
// main::@3
__b3:
// [6] if(0!=*main::c#2) goto main::@4 -- 0_neq__deref_pbuz1_then_la1
ldy #0
lda (c),y
cmp #0
bne __b4
jmp __b5
// main::@5
__b5:
// [7] main::msg#1 = main::msg#2 + SIZEOF_POINTER -- qbuz1=qbuz1_plus_vbuc1
lda #SIZEOF_POINTER
clc
adc.z msg
sta.z msg
bcc !+
inc.z msg+1
!:
// [1] phi from main::@5 to main::@1 [phi:main::@5->main::@1]
__b1_from___b5:
// [1] phi main::i#4 = main::i#2 [phi:main::@5->main::@1#0] -- register_copy
// [1] phi main::msg#2 = main::msg#1 [phi:main::@5->main::@1#1] -- register_copy
jmp __b1
// main::@4
__b4:
// [8] SCREEN[main::i#2] = *main::c#2 -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (c),y
sta SCREEN,x
// [9] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] main::c#1 = ++ main::c#2 -- pbuz1=_inc_pbuz1
inc.z c
bne !+
inc.z c+1
!:
jmp __b3_from___b4
}
// File Data
.segment Data
// Works
// char*[] msgs = { (char*)"hello", (char*)"cruel", (char*)"world", (char*)NUL };
// Not working
msgs: .word __0, __1, __2, NUL
__0: .text "hello"
.byte 0
__1: .text "cruel"
.byte 0
__2: .text "world"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Removing instruction jmp __b3
Removing instruction jmp __b5
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction lda #<0 with TYA
Removing instruction lda #>0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label __b3_from___b4 with __b3
Removing instruction __b3_from___b2:
Removing instruction __b3_from___b4:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1_from_main:
Removing instruction __breturn:
Removing instruction __b5:
Removing instruction __b1_from___b5:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
constant byte* $0[6] = "hello"
constant byte* $1[6] = "cruel"
constant byte* $2[6] = "world"
constant void* const NUL = (void*) 0
constant byte* const SCREEN = (byte*) 1024
constant byte SIZEOF_POINTER = 2
void main()
byte* main::c
byte* main::c#0 c zp[2]:4 22.0
byte* main::c#1 c zp[2]:4 202.0
byte* main::c#2 c zp[2]:4 103.75
byte main::i
byte main::i#1 reg byte x 101.0
byte main::i#2 reg byte x 81.25
byte main::i#4 reg byte x 7.333333333333333
byte** main::msg
byte** main::msg#1 msg zp[2]:2 22.0
byte** main::msg#2 msg zp[2]:2 5.5
constant byte** msgs[] = { $0, $1, $2, NUL }
zp[2]:2 [ main::msg#2 main::msg#1 ]
reg byte x [ main::i#4 main::i#2 main::i#1 ]
zp[2]:4 [ main::c#2 main::c#0 main::c#1 ]
FINAL ASSEMBLER
Score: 4961
// File Comments
// Tests literal string array
// Upstart
// Commodore 64 PRG executable file
.file [name="literal-string-array.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.const SIZEOF_POINTER = 2
.label SCREEN = $400
.label NUL = 0
.segment Code
// main
main: {
.label c = 4
.label msg = 2
// [1] phi from main to main::@1 [phi:main->main::@1]
// [1] phi main::i#4 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// [1] phi main::msg#2 = msgs [phi:main->main::@1#1] -- qbuz1=qbuc1
lda #<msgs
sta.z msg
lda #>msgs
sta.z msg+1
// main::@1
__b1:
// while(*msg)
// [2] if((byte*)0!=*main::msg#2) goto main::@2 -- pbuc1_neq__deref_qbuz1_then_la1
ldy #0
tya
cmp (msg),y
bne __b2
iny
cmp (msg),y
bne __b2
// main::@return
// }
// [3] return
rts
// main::@2
__b2:
// char* c = *msg
// [4] main::c#0 = *main::msg#2 -- pbuz1=_deref_qbuz2
ldy #0
lda (msg),y
sta.z c
iny
lda (msg),y
sta.z c+1
// [5] phi from main::@2 main::@4 to main::@3 [phi:main::@2/main::@4->main::@3]
// [5] phi main::i#2 = main::i#4 [phi:main::@2/main::@4->main::@3#0] -- register_copy
// [5] phi main::c#2 = main::c#0 [phi:main::@2/main::@4->main::@3#1] -- register_copy
// main::@3
__b3:
// while(*c)
// [6] if(0!=*main::c#2) goto main::@4 -- 0_neq__deref_pbuz1_then_la1
ldy #0
lda (c),y
cmp #0
bne __b4
// main::@5
// msg++;
// [7] main::msg#1 = main::msg#2 + SIZEOF_POINTER -- qbuz1=qbuz1_plus_vbuc1
lda #SIZEOF_POINTER
clc
adc.z msg
sta.z msg
bcc !+
inc.z msg+1
!:
// [1] phi from main::@5 to main::@1 [phi:main::@5->main::@1]
// [1] phi main::i#4 = main::i#2 [phi:main::@5->main::@1#0] -- register_copy
// [1] phi main::msg#2 = main::msg#1 [phi:main::@5->main::@1#1] -- register_copy
jmp __b1
// main::@4
__b4:
// SCREEN[i++] = *c++
// [8] SCREEN[main::i#2] = *main::c#2 -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (c),y
sta SCREEN,x
// SCREEN[i++] = *c++;
// [9] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] main::c#1 = ++ main::c#2 -- pbuz1=_inc_pbuz1
inc.z c
bne !+
inc.z c+1
!:
jmp __b3
}
// File Data
.segment Data
// Works
// char*[] msgs = { (char*)"hello", (char*)"cruel", (char*)"world", (char*)NUL };
// Not working
msgs: .word __0, __1, __2, NUL
__0: .text "hello"
.byte 0
__1: .text "cruel"
.byte 0
__2: .text "world"
.byte 0

View File

@ -0,0 +1,23 @@
constant byte* $0[6] = "hello"
constant byte* $1[6] = "cruel"
constant byte* $2[6] = "world"
constant void* const NUL = (void*) 0
constant byte* const SCREEN = (byte*) 1024
constant byte SIZEOF_POINTER = 2
void main()
byte* main::c
byte* main::c#0 c zp[2]:4 22.0
byte* main::c#1 c zp[2]:4 202.0
byte* main::c#2 c zp[2]:4 103.75
byte main::i
byte main::i#1 reg byte x 101.0
byte main::i#2 reg byte x 81.25
byte main::i#4 reg byte x 7.333333333333333
byte** main::msg
byte** main::msg#1 msg zp[2]:2 22.0
byte** main::msg#2 msg zp[2]:2 5.5
constant byte** msgs[] = { $0, $1, $2, NUL }
zp[2]:2 [ main::msg#2 main::msg#1 ]
reg byte x [ main::i#4 main::i#2 main::i#1 ]
zp[2]:4 [ main::c#2 main::c#0 main::c#1 ]

View File

@ -1,75 +1,76 @@
// Example of a struct containing a pointer
.pc = $801 "Basic"
// Commodore 64 PRG executable file
.file [name="struct-ptr-29.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
.const SIZEOF_STRUCT_PERSON = 3
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
.label idx = 5
.segment Code
main: {
// print_person(&persons[0])
ldx #0
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// print_person(&persons[1])
lda #<persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person
lda #>persons+1*SIZEOF_STRUCT_PERSON
sta.z print_person.person+1
jsr print_person
// }
rts
}
// print_person(struct Person* zeropage(2) person)
// print_person(struct Person* zp(2) person)
print_person: {
.label i = 4
.label person = 2
// SCREEN[idx++] = DIGIT[person->id]
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
// SCREEN[idx++] = DIGIT[person->id];
inx
// SCREEN[idx++] = ' '
lda #' '
sta SCREEN,x
// SCREEN[idx++] = ' ';
inx
stx.z idx
lda #0
sta.z i
__b1:
ldy #OFFSET_STRUCT_PERSON_NAME
lda (person),y
sta.z $fe
iny
lda (person),y
sta.z $ff
ldy.z i
lda ($fe),y
cmp #0
bne __b2
// for(byte i=0; person->name[i]; i++)
.assert "Missing ASM fragment Fragment not found 0_neq_(qbuz1_derefidx_vbuc1)_derefidx_vbuz2_then_la1. Attempted variations 0_neq_(qbuz1_derefidx_vbuc1)_derefidx_vbuz2_then_la1 0_neq_(qbuz1_derefidx_vbsc1)_derefidx_vbuz2_then_la1 0_neq_(qbuz1_derefidx_vwuc1)_derefidx_vbuz2_then_la1 0_neq_(qbuz1_derefidx_vwsc1)_derefidx_vbuz2_then_la1 0_neq_(qbuz1_derefidx_vduc1)_derefidx_vbuz2_then_la1 0_neq_(qbuz1_derefidx_vdsc1)_derefidx_vbuz2_then_la1 ", 0, 1
// SCREEN[idx++] = ' '
lda #' '
sta SCREEN,x
ldy.z idx
sta SCREEN,y
// SCREEN[idx++] = ' ';
inx
// }
rts
__b2:
ldy #OFFSET_STRUCT_PERSON_NAME
lda (person),y
sta.z $fe
iny
lda (person),y
sta.z $ff
ldy.z i
lda ($fe),y
sta SCREEN,x
inx
inc.z i
jmp __b1
// SCREEN[idx++] = person->name[i]
// SCREEN[idx++] = person->name[i];
// for(byte i=0; person->name[i]; i++)
}
.segment Data
persons: .byte 4
.word person_name
.byte 7
.word person_name1
DIGIT: .text "0123456789"
.byte 0
__0: .text "jesper"
person_name: .text "jesper"
.byte 0
__1: .text "repsej"
person_name1: .text "repsej"
.byte 0
persons: .byte 4
.word __0
.byte 7
.word __1

View File

@ -1,49 +1,40 @@
@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()
[5] call print_person
void main()
main: scope:[main] from
[0] phi()
[1] call print_person
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print_person
[2] phi()
[3] call print_person
to:main::@return
main::@return: scope:[main] from main::@1
[8] return
[4] return
to:@return
(void()) print_person((struct Person*) print_person::person)
void print_person(struct Person* print_person::person)
print_person: scope:[print_person] from main main::@1
[9] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 )
[9] (struct Person*) print_person::person#2 ← phi( main/(const struct Person[2]) persons main::@1/(const struct Person[2]) persons+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON )
[10] *((const byte*) SCREEN + (byte) idx#13) ← *((const byte[]) DIGIT + *((byte*)(struct Person*) print_person::person#2))
[11] (byte) idx#4 ← ++ (byte) idx#13
[12] *((const byte*) SCREEN + (byte) idx#4) ← (byte) ' '
[13] (byte) idx#5 ← ++ (byte) idx#4
[5] idx#14 = phi( main/0, main::@1/idx#17 )
[5] print_person::person#2 = phi( main/persons, main::@1/persons+1*SIZEOF_STRUCT_PERSON )
[6] SCREEN[idx#14] = DIGIT[*((byte*)print_person::person#2)]
[7] idx#3 = ++ idx#14
[8] SCREEN[idx#3] = ' '
[9] idx#4 = ++ idx#3
to:print_person::@1
print_person::@1: scope:[print_person] from print_person print_person::@2
[14] (byte) idx#14 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 )
[14] (byte) print_person::i#2 ← phi( print_person/(byte) 0 print_person::@2/(byte) print_person::i#1 )
[15] if((byte) 0!=*(*((byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2
[10] idx#15 = phi( print_person/idx#4, print_person::@2/idx#5 )
[10] print_person::i#2 = phi( print_person/0, print_person::@2/print_person::i#1 )
[11] if(0!=(((byte**)print_person::person#2)[OFFSET_STRUCT_PERSON_NAME])[print_person::i#2]) goto print_person::@2
to:print_person::@3
print_person::@3: scope:[print_person] from print_person::@1
[16] *((const byte*) SCREEN + (byte) idx#14) ← (byte) ' '
[17] (byte) idx#16 ← ++ (byte) idx#14
[12] SCREEN[idx#15] = ' '
[13] idx#17 = ++ idx#15
to:print_person::@return
print_person::@return: scope:[print_person] from print_person::@3
[18] return
[14] return
to:@return
print_person::@2: scope:[print_person] from print_person::@1
[19] *((const byte*) SCREEN + (byte) idx#14) ← *(*((byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)
[20] (byte) idx#6 ← ++ (byte) idx#14
[21] (byte) print_person::i#1 ← ++ (byte) print_person::i#2
[15] SCREEN[idx#15] = (((byte**)print_person::person#2)[OFFSET_STRUCT_PERSON_NAME])[print_person::i#2]
[16] idx#5 = ++ idx#15
[17] print_person::i#1 = ++ print_person::i#2
to:print_person::@1

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,27 @@
(const string) $0 = (string) "jesper"
(const string) $1 = (string) "repsej"
(label) @1
(label) @begin
(label) @end
(const byte[]) DIGIT = (string) "0123456789"
(const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1
(byte) Person::id
(byte*) Person::name
(const byte*) SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_PERSON = (byte) 3
(byte) idx
(byte) idx#13 reg byte x 3.0
(byte) idx#14 reg byte x 9.75
(byte) idx#16 reg byte x 1.0
(byte) idx#4 reg byte x 3.0
(byte) idx#5 reg byte x 4.0
(byte) idx#6 reg byte x 11.0
(void()) main()
(label) main::@1
(label) main::@return
(const struct Person[2]) persons = { { id: (byte) 4, name: (const string) $0 }, { id: (byte) 7, name: (const string) $1 } }
(void()) print_person((struct Person*) print_person::person)
(label) print_person::@1
(label) print_person::@2
(label) print_person::@3
(label) print_person::@return
(byte) print_person::i
(byte) print_person::i#1 i zp[1]:4 22.0
(byte) print_person::i#2 i zp[1]:4 11.0
(struct Person*) print_person::person
(struct Person*) print_person::person#2 person zp[2]:2
constant byte* DIGIT[] = "0123456789"
constant byte OFFSET_STRUCT_PERSON_NAME = 1
constant byte* const SCREEN = (byte*) 1024
constant byte SIZEOF_STRUCT_PERSON = 3
byte idx
byte idx#14 reg byte x 12.0
byte idx#15 idx zp[1]:5 84.0
byte idx#17 reg byte x 3.25
byte idx#3 reg byte x 16.5
byte idx#4 idx zp[1]:5 22.0
byte idx#5 idx zp[1]:5 101.0
void main()
constant byte* person_name[7] = "jesper"
constant byte* person_name1[7] = "repsej"
constant struct Person* persons[2] = { { id: 4, name: person_name }, { id: 7, name: person_name1 } }
void print_person(struct Person* print_person::person)
byte print_person::i
byte print_person::i#1 i zp[1]:4 202.0
byte print_person::i#2 i zp[1]:4 101.0
struct Person* print_person::person
struct Person* print_person::person#2 person zp[2]:2
zp[2]:2 [ print_person::person#2 ]
reg byte x [ idx#13 idx#16 ]
reg byte x [ idx#14 idx#17 ]
zp[1]:4 [ print_person::i#2 print_person::i#1 ]
reg byte x [ idx#14 idx#5 idx#6 ]
reg byte x [ idx#4 ]
zp[1]:5 [ idx#15 idx#4 idx#5 ]
reg byte x [ idx#3 ]