1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-29 03:56:15 +00:00

Fixed double emitting of strings inside arrays inside structs. Closes #312

This commit is contained in:
jespergravgaard 2019-09-13 23:29:42 +02:00
parent edb12d8577
commit 4f6908ac80
24 changed files with 1262 additions and 161 deletions

View File

@ -364,6 +364,7 @@ public class Compiler {
constantOptimizations.add(new Pass2NopCastInlining(program));
constantOptimizations.add(new Pass2MultiplyToShiftRewriting(program));
constantOptimizations.add(new Pass2ConstantInlining(program));
constantOptimizations.add(new Pass2ArrayInStructInlining(program));
constantOptimizations.add(new Pass2ConstantAdditionElimination(program));
constantOptimizations.add(new Pass2ConstantSimplification(program));
constantOptimizations.addAll(getPass2Optimizations());

View File

@ -477,6 +477,10 @@ public interface ProgramValue {
public void set(Value value) {
structValue.setValue(memberRef, (ConstantValue) value);
}
public VariableRef getMemberRef() {
return memberRef;
}
}
/** Value inside a constant array filled expression. */

View File

@ -0,0 +1,80 @@
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.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeArray;
import dk.camelot64.kickc.model.values.ConstantRef;
import dk.camelot64.kickc.model.values.ConstantValue;
import dk.camelot64.kickc.model.values.Value;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.HashMap;
import java.util.Map;
/**
* Compiler Pass inlining arrays inside literal structs
*/
public class Pass2ArrayInStructInlining extends Pass2SsaOptimization {
public Pass2ArrayInStructInlining(Program program) {
super(program);
}
/**
* Consolidate unnamed constants into other constants value
*
* @return true optimization was performed. false if no optimization was possible.
*/
@Override
public boolean step() {
Map<ConstantRef, ConstantValue> inline = new HashMap<>();
inline.putAll(findArrayInStruct());
// Replace all usages of the constants in the control flow graph or symbol table
replaceVariables(inline);
// Remove from symbol table
deleteSymbols(getScope(), inline.keySet());
for(ConstantRef constantRef : inline.keySet()) {
getLog().append("Constant array inlined into struct " + constantRef.toString() + " = " + inline.get(constantRef).toString(getProgram()));
}
return inline.size() > 0;
}
/**
* Find constant fixed size arrays inside structs.
*
* @return Map from constant name to constant value
*/
private Map<ConstantRef, ConstantValue> findArrayInStruct() {
Map<ConstantRef, ConstantValue> inline = new HashMap<>();
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
Value value = programValue.get();
if(programValue instanceof ProgramValue.ProgramValueConstantStructMember) {
VariableRef memberRef = ((ProgramValue.ProgramValueConstantStructMember) programValue).getMemberRef();
Variable structMemberVar = getScope().getVariable(memberRef);
if(structMemberVar.getType() instanceof SymbolTypeArray) {
if(((SymbolTypeArray) structMemberVar.getType()).getSize() != null) {
if(value instanceof ConstantValue) {
ConstantValue constantValue = (ConstantValue) value;
if(constantValue.getType(getProgram().getScope()).equals(SymbolType.STRING)) {
if(constantValue instanceof ConstantRef) {
ConstantVar constantStringVar = getScope().getConstant((ConstantRef) constantValue);
inline.put((ConstantRef) constantValue, constantStringVar.getValue());
}
}
}
}
}
}
});
return inline;
}
}

View File

@ -231,17 +231,6 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
static ConstantValue createBinary(ConstantValue c1, OperatorBinary operator, ConstantValue c2, ProgramScope programScope) {
// Special handling of string append using +
if(Operators.PLUS.equals(operator) && SymbolType.STRING.equals(c1.getType(programScope))) {
if(c1 instanceof ConstantRef) {
c1 = programScope.getConstant((ConstantRef) c1).getValue();
}
if(c2 instanceof ConstantRef) {
c2 = programScope.getConstant((ConstantRef) c2).getValue();
}
return new ConstantBinary(c1, operator, c2);
}
if(Operators.PLUS.equals(operator)) {
return new ConstantBinary(c1, operator, c2);
}

View File

@ -36,8 +36,7 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
@Override
public boolean step() {
Map<ConstantRef, ConstantValue> inline = new HashMap<>();
Map<ConstantRef, ConstantValue> aliasConstants = findAliasConstants();
inline.putAll(aliasConstants);
inline.putAll(findAliasConstants());
inline.putAll(findUnnamedConstants());
inline.putAll(findConstVarVersions());

View File

@ -655,9 +655,14 @@ public class TestPrograms {
}
*/
@Test
public void testStructPtr34() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-34");
}
@Test
public void testStructPtr33() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-33", log());
compileAndCompare("struct-ptr-33");
}
@Test

View File

@ -5,12 +5,9 @@ struct Person {
char* name;
};
char* name1 = "jesper";
char* name2 = "repsej";
struct Person[2] persons = {
{ 4, name1 },
{ 7, name2 }
{ 4, "jesper" },
{ 7, "repsej" }
};
void main() {

View File

@ -0,0 +1,29 @@
// Example of a struct containing an array
struct Person {
char id;
char[16] name;
};
void main() {
struct Person jesper = { 4, "jesper" };
print_person(jesper);
struct Person henriette = { 7, "henriette" };
print_person(henriette);
}
const char* SCREEN = 0x0400;
char idx = 0;
char[] DIGIT = "0123456789";
void print_person(struct Person person) {
SCREEN[idx++] = DIGIT[person.id];
SCREEN[idx++] = ' ';
for(byte i=0; person.name[i]; i++)
SCREEN[idx++] = person.name[i];
SCREEN[idx++] = ' ';
}

View File

@ -65,10 +65,6 @@ print_person: {
inx
rts
}
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8

View File

@ -208,6 +208,9 @@ Constant inlined print_person::person#0 = (const struct Person[]) persons#0
Constant inlined main::person#0 = (const struct Person[]) persons#0
Constant inlined print_person::person#1 = (const struct Person*) main::person#1
Successful SSA optimization Pass2ConstantInlining
Constant array inlined into struct $0 = (string) "jgr"
Constant array inlined into struct $1 = (string) "hbg"
Successful SSA optimization Pass2ArrayInStructInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
@ -490,10 +493,6 @@ print_person: {
rts
}
// File Data
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8
@ -682,10 +681,6 @@ print_person: {
rts
}
// File Data
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8
@ -720,8 +715,6 @@ Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "jgr"
(const string) $1 $1 = (string) "hbg"
(label) @1
(label) @begin
(label) @end
@ -745,7 +738,7 @@ FINAL SYMBOL TABLE
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 1, initials: (const string) $0 }, { id: (byte) 8, initials: (const string) $1 } }
(const struct Person[]) persons#0 persons = { { id: (byte) 1, initials: (string) "jgr" }, { id: (byte) 8, initials: (string) "hbg" } }
(void()) print_person((struct Person*) print_person::person)
(byte~) print_person::$0 reg byte a 4.0
(byte[4]) print_person::$3 $3 zp ZP_WORD:4 4.0
@ -894,10 +887,6 @@ print_person: {
rts
}
// File Data
_0: .text "jgr"
.byte 0
_1: .text "hbg"
.byte 0
persons: .byte 1
.text "jgr"
.byte 0, 8

View File

@ -1,5 +1,3 @@
(const string) $0 $0 = (string) "jgr"
(const string) $1 $1 = (string) "hbg"
(label) @1
(label) @begin
(label) @end
@ -23,7 +21,7 @@
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 1, initials: (const string) $0 }, { id: (byte) 8, initials: (const string) $1 } }
(const struct Person[]) persons#0 persons = { { id: (byte) 1, initials: (string) "jgr" }, { id: (byte) 8, initials: (string) "hbg" } }
(void()) print_person((struct Person*) print_person::person)
(byte~) print_person::$0 reg byte a 4.0
(byte[4]) print_person::$3 $3 zp ZP_WORD:4 4.0

View File

@ -63,13 +63,13 @@ print_person: {
inc.z i
jmp b1
}
name1: .text "jesper"
_0: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
_1: .text "repsej"
.byte 0
persons: .byte 4
.word name1
.word _0
.byte 7
.word name2
.word _1
DIGIT: .text "0123456789"
.byte 0

View File

@ -4,17 +4,13 @@ Rewriting struct pointer member access *((struct Person*) print_person::person).
Rewriting struct pointer member access *((struct Person*) print_person::person).name
Rewriting struct pointer member access *((struct Person*) print_person::person).name
Warning! Adding boolean cast to non-boolean condition *(*((byte**) print_person::$1) + (byte) print_person::i)
Identified constant variable (byte*) name1
Identified constant variable (byte*) name2
Culled Empty Block (label) print_person::@4
Culled Empty Block (label) print_person::@5
Culled Empty Block (label) print_person::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) name1#0 ← (const string) $0
(byte*) name2#0 ← (const string) $1
(struct Person[2]) persons#0 ← { { (number) 4, (byte*) name1#0 }, { (number) 7, (byte*) name2#0 } }
(struct Person[2]) persons#0 ← { { (number) 4, (const string) $0 }, { (number) 7, (const string) $1 } }
to:@1
main: scope:[main] from @2
(byte) idx#18 ← phi( @2/(byte) idx#20 )
@ -140,10 +136,6 @@ SYMBOL TABLE SSA
(label) main::@1
(label) main::@2
(label) main::@return
(byte*) name1
(byte*) name1#0
(byte*) name2
(byte*) name2#0
(struct Person[2]) persons
(struct Person[2]) persons#0
(void()) print_person((struct Person*) print_person::person)
@ -175,7 +167,7 @@ Adding number conversion cast (unumber) 0 in (byte) idx#3 ← (number) 0
Adding number conversion cast (unumber) 0 in (byte) print_person::i#0 ← (number) 0
Adding number conversion cast (unumber) 0 in (bool~) print_person::$3 ← (number) 0 != *(*((byte**) print_person::$1) + (byte) print_person::i#2)
Successful SSA optimization PassNAddNumberTypeConversions
Added casts to value list in (struct Person[2]) persons#0 ← (struct Person[2]){ (struct Person){ (byte)(number) 4, (byte*) name1#0 }, (struct Person){ (byte)(number) 7, (byte*) name2#0 } }
Added casts to value list in (struct Person[2]) persons#0 ← (struct Person[2]){ (struct Person){ (byte)(number) 4, (const string) $0 }, (struct Person){ (byte)(number) 7, (const string) $1 } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) idx#3 ← (unumber)(number) 0
@ -215,16 +207,20 @@ Identical Phi Values (byte) idx#1 (byte) idx#16
Identical Phi Values (struct Person*) print_person::person#3 (struct Person*) print_person::person#2
Identical Phi Values (byte) idx#17 (byte) idx#1
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) print_person::$3 [32] if((byte) 0!=*(*((byte**) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2
Simple Condition (bool~) print_person::$3 [30] if((byte) 0!=*(*((byte**) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Rewriting array member address-of to pointer addition [5] (struct Person*) print_person::person#0 ← (struct Person[2]) persons#0 + (byte~) main::$4
Rewriting array member address-of to pointer addition [11] (struct Person*) print_person::person#1 ← (struct Person[2]) persons#0 + (byte~) main::$5
Rewriting array member address-of to pointer addition [3] (struct Person*) print_person::person#0 ← (struct Person[2]) persons#0 + (byte~) main::$4
Rewriting array member address-of to pointer addition [9] (struct Person*) print_person::person#1 ← (struct Person[2]) persons#0 + (byte~) main::$5
Successful SSA optimization PassNArrayElementAddressOfRewriting
Constant right-side identified [4] (byte~) main::$4 ← (byte) 0 * (const byte) SIZEOF_STRUCT_PERSON
Constant right-side identified [10] (byte~) main::$5 ← (byte) 1 * (const byte) SIZEOF_STRUCT_PERSON
Constant right-side identified [2] (byte~) main::$4 ← (byte) 0 * (const byte) SIZEOF_STRUCT_PERSON
Constant right-side identified [8] (byte~) main::$5 ← (byte) 1 * (const byte) SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) name1#0 = $0
Constant (const byte*) name2#0 = $1
Identified constant from value list (struct Person) { id: (byte) 4, name: (const string) $0 }
Identified constant from value list (struct Person) { id: (byte) 7, name: (const string) $1 }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Person[2]) { { id: (byte) 4, name: (const string) $0 }, { id: (byte) 7, name: (const string) $1 } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const struct Person[2]) persons#0 = { { id: 4, name: $0 }, { id: 7, name: $1 } }
Constant (const byte) main::$4 = 0*SIZEOF_STRUCT_PERSON
Constant (const byte) main::$5 = 1*SIZEOF_STRUCT_PERSON
Constant (const byte*) SCREEN#0 = (byte*) 1024
@ -232,45 +228,35 @@ Constant (const byte) idx#20 = 0
Constant (const byte[]) DIGIT#0 = $2
Constant (const byte) print_person::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Converting *(pointer+n) to pointer[n] [24] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*) print_person::$0)) -- *((byte*)print_person::person#2 + OFFSET_STRUCT_PERSON_ID)
Converting *(pointer+n) to pointer[n] [32] if((byte) 0!=*(*((byte**) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2 -- *((byte**)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME)
Converting *(pointer+n) to pointer[n] [35] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte**) print_person::$2) + (byte) print_person::i#2) -- *((byte**)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME)
Converting *(pointer+n) to pointer[n] [22] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*) print_person::$0)) -- *((byte*)print_person::person#2 + OFFSET_STRUCT_PERSON_ID)
Converting *(pointer+n) to pointer[n] [30] if((byte) 0!=*(*((byte**) print_person::$1) + (byte) print_person::i#2)) goto print_person::@2 -- *((byte**)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME)
Converting *(pointer+n) to pointer[n] [33] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte**) print_person::$2) + (byte) print_person::i#2) -- *((byte**)print_person::person#2 + OFFSET_STRUCT_PERSON_NAME)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_PERSON in
Successful SSA optimization PassNSimplifyConstantZero
Simplifying expression containing zero persons#0 in [5] (struct Person*) print_person::person#0 ← (struct Person[2]) persons#0 + (const byte) main::$4
Simplifying expression containing zero (byte*)print_person::person#2 in [23] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID
Simplifying expression containing zero (byte*)print_person::person#2 in [24] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID))
Simplifying expression containing zero persons#0 in [3] (struct Person*) print_person::person#0 ← (const struct Person[2]) persons#0 + (const byte) main::$4
Simplifying expression containing zero (byte*)print_person::person#2 in [21] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID
Simplifying expression containing zero (byte*)print_person::person#2 in [22] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID))
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte*) print_person::$0 and assignment [7] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2
Eliminating unused variable (byte**) print_person::$1 and assignment [13] (byte**) print_person::$1 ← (byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
Eliminating unused variable (byte**) print_person::$2 and assignment [15] (byte**) print_person::$2 ← (byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
Eliminating unused variable (byte*) print_person::$0 and assignment [6] (byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2
Eliminating unused variable (byte**) print_person::$1 and assignment [12] (byte**) print_person::$1 ← (byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
Eliminating unused variable (byte**) print_person::$2 and assignment [14] (byte**) print_person::$2 ← (byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME
Eliminating unused constant (const byte) main::$4
Eliminating unused constant (const byte) OFFSET_STRUCT_PERSON_ID
Successful SSA optimization PassNEliminateUnusedVars
Identified constant from value list (struct Person) { id: (byte) 4, name: (const byte*) name1#0 }
Identified constant from value list (struct Person) { id: (byte) 7, name: (const byte*) name2#0 }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Person[2]) { { id: (byte) 4, name: (const byte*) name1#0 }, { id: (byte) 7, name: (const byte*) name2#0 } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const struct Person[2]) persons#0 = { { id: 4, name: name1#0 }, { id: 7, name: name2#0 } }
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Person*) print_person::person#0 = persons#0
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [1] (struct Person*) print_person::person#1 ← (const struct Person[2]) persons#0 + (const byte) main::$5
Constant right-side identified [2] (struct Person*) print_person::person#1 ← (const struct Person[2]) persons#0 + (const byte) main::$5
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const struct Person*) print_person::person#0 = persons#0
Constant (const struct Person*) print_person::person#1 = persons#0+main::$5
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte) print_person::i#0
Inlining constant with var siblings (const struct Person*) print_person::person#0
Inlining constant with var siblings (const struct Person*) print_person::person#1
Inlining constant with var siblings (const byte) idx#20
Constant inlined idx#20 = (byte) 0
Constant inlined print_person::i#0 = (byte) 0
Constant inlined main::$5 = (byte) 1*(const byte) SIZEOF_STRUCT_PERSON
Constant inlined idx#20 = (byte) 0
Constant inlined print_person::person#0 = (const struct Person[2]) persons#0
Constant inlined $0 = (const byte*) name1#0
Constant inlined $1 = (const byte*) name2#0
Constant inlined print_person::i#0 = (byte) 0
Constant inlined $2 = (const byte[]) DIGIT#0
Constant inlined print_person::person#1 = (const struct Person[2]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantInlining
@ -362,8 +348,6 @@ VARIABLE REGISTER WEIGHTS
(byte) idx#5 4.0
(byte) idx#6 11.0
(void()) main()
(byte*) name1
(byte*) name2
(struct Person[2]) persons
(void()) print_person((struct Person*) print_person::person)
(byte) print_person::i
@ -543,16 +527,16 @@ print_person: {
jmp b1
}
// File Data
name1: .text "jesper"
_0: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
_1: .text "repsej"
.byte 0
persons: .byte 4
.word name1
.word _0
.byte 7
.word name2
.word _1
DIGIT: .text "0123456789"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) [ print_person::person#2 idx#13 ] ( main:2::print_person:5 [ print_person::person#2 idx#13 ] main:2::print_person:7 [ print_person::person#2 idx#13 ] ) always clobbers reg byte a reg byte y
@ -727,16 +711,16 @@ print_person: {
jmp b1
}
// File Data
name1: .text "jesper"
_0: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
_1: .text "repsej"
.byte 0
persons: .byte 4
.word name1
.word _0
.byte 7
.word name2
.word _1
DIGIT: .text "0123456789"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
@ -770,6 +754,8 @@ Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "repsej"
(label) @1
(label) @begin
(label) @end
@ -791,12 +777,8 @@ FINAL SYMBOL TABLE
(void()) main()
(label) main::@1
(label) main::@return
(byte*) name1
(const byte*) name1#0 name1 = (string) "jesper"
(byte*) name2
(const byte*) name2#0 name2 = (string) "repsej"
(struct Person[2]) persons
(const struct Person[2]) persons#0 persons = { { id: (byte) 4, name: (const byte*) name1#0 }, { id: (byte) 7, name: (const byte*) name2#0 } }
(const struct Person[2]) persons#0 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
@ -943,14 +925,14 @@ print_person: {
jmp b1
}
// File Data
name1: .text "jesper"
_0: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
_1: .text "repsej"
.byte 0
persons: .byte 4
.word name1
.word _0
.byte 7
.word name2
.word _1
DIGIT: .text "0123456789"
.byte 0

View File

@ -1,3 +1,5 @@
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "repsej"
(label) @1
(label) @begin
(label) @end
@ -19,12 +21,8 @@
(void()) main()
(label) main::@1
(label) main::@return
(byte*) name1
(const byte*) name1#0 name1 = (string) "jesper"
(byte*) name2
(const byte*) name2#0 name2 = (string) "repsej"
(struct Person[2]) persons
(const struct Person[2]) persons#0 persons = { { id: (byte) 4, name: (const byte*) name1#0 }, { id: (byte) 7, name: (const byte*) name2#0 } }
(const struct Person[2]) persons#0 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

View File

@ -63,10 +63,6 @@ print_person: {
iny
jmp b1
}
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0

View File

@ -239,6 +239,9 @@ Constant inlined print_person::i#0 = (byte) 0
Constant inlined $2 = (const byte[]) DIGIT#0
Constant inlined print_person::person#1 = (const struct Person[]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON
Successful SSA optimization Pass2ConstantInlining
Constant array inlined into struct $0 = (string) "jesper"
Constant array inlined into struct $1 = (string) "henriette"
Successful SSA optimization Pass2ArrayInStructInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
@ -522,10 +525,6 @@ print_person: {
jmp b1
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0
@ -715,10 +714,6 @@ print_person: {
jmp b1
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0
@ -762,8 +757,6 @@ Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henriette"
(label) @1
(label) @begin
(label) @end
@ -786,7 +779,7 @@ FINAL SYMBOL TABLE
(label) main::@1
(label) main::@return
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 4, name: (const string) $0 }, { id: (byte) 7, name: (const string) $1 } }
(const struct Person[]) persons#0 persons = { { id: (byte) 4, name: (string) "jesper" }, { id: (byte) 7, name: (string) "henriette" } }
(void()) print_person((struct Person*) print_person::person)
(byte[$10]) print_person::$1 $1 zp ZP_WORD:4 22.0
(byte[$10]) print_person::$2 $2 zp ZP_WORD:6 22.0
@ -939,10 +932,6 @@ print_person: {
jmp b1
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henriette"
.byte 0
persons: .byte 4
.text "jesper"
.byte 0

View File

@ -1,5 +1,3 @@
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henriette"
(label) @1
(label) @begin
(label) @end
@ -22,7 +20,7 @@
(label) main::@1
(label) main::@return
(struct Person[]) persons
(const struct Person[]) persons#0 persons = { { id: (byte) 4, name: (const string) $0 }, { id: (byte) 7, name: (const string) $1 } }
(const struct Person[]) persons#0 persons = { { id: (byte) 4, name: (string) "jesper" }, { id: (byte) 7, name: (string) "henriette" } }
(void()) print_person((struct Person*) print_person::person)
(byte[$10]) print_person::$1 $1 zp ZP_WORD:4 22.0
(byte[$10]) print_person::$2 $2 zp ZP_WORD:6 22.0

View File

@ -13,10 +13,6 @@ main: {
sta SCREEN+1
rts
}
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0

View File

@ -106,6 +106,9 @@ Constant inlined main::$1 = (byte[$d])(const struct Person*) main::person#1+(con
Constant inlined main::person#0 = (const struct Person[2]) persons#0
Constant inlined main::$0 = (byte[$d])(const struct Person[2]) persons#0+(const byte) OFFSET_STRUCT_PERSON_NAME
Successful SSA optimization Pass2ConstantInlining
Constant array inlined into struct $0 = (string) "jesper"
Constant array inlined into struct $1 = (string) "henry"
Successful SSA optimization Pass2ArrayInStructInlining
Consolidated array index constant in *((byte[$d])persons#0+OFFSET_STRUCT_PERSON_NAME+2)
Consolidated array index constant in *((byte[$d])main::person#1+OFFSET_STRUCT_PERSON_NAME+2)
Consolidated array index constant in *(main::SCREEN#0+1)
@ -197,10 +200,6 @@ main: {
rts
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0
@ -266,10 +265,6 @@ main: {
rts
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0
@ -300,8 +295,6 @@ Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henry"
(label) @1
(label) @begin
(label) @end
@ -317,7 +310,7 @@ FINAL SYMBOL TABLE
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[2]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[2]) persons
(const struct Person[2]) persons#0 persons = { { id: (byte) 7, name: (const string) $0, age: (word) $141 }, { id: (byte) 9, name: (const string) $1, age: (word) $7b } }
(const struct Person[2]) persons#0 persons = { { id: (byte) 7, name: (string) "jesper", age: (word) $141 }, { id: (byte) 9, name: (string) "henry", age: (word) $7b } }
@ -357,10 +350,6 @@ main: {
rts
}
// File Data
_0: .text "jesper"
.byte 0
_1: .text "henry"
.byte 0
persons: .byte 7
.text "jesper"
.byte 0

View File

@ -1,5 +1,3 @@
(const string) $0 $0 = (string) "jesper"
(const string) $1 $1 = (string) "henry"
(label) @1
(label) @begin
(label) @end
@ -15,5 +13,5 @@
(struct Person*) main::person
(const struct Person*) main::person#1 person = (const struct Person[2]) persons#0+(const byte) SIZEOF_STRUCT_PERSON
(struct Person[2]) persons
(const struct Person[2]) persons#0 persons = { { id: (byte) 7, name: (const string) $0, age: (word) $141 }, { id: (byte) 9, name: (const string) $1, age: (word) $7b } }
(const struct Person[2]) persons#0 persons = { { id: (byte) 7, name: (string) "jesper", age: (word) $141 }, { id: (byte) 9, name: (string) "henry", age: (word) $7b } }

View File

@ -0,0 +1,62 @@
// Example of a struct containing an array
// It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers.
// https://gitlab.com/camelot/kickc/issues/312
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
.const jesper_id = 4
.const henriette_id = 7
lda #<jesper_name
sta.z print_person.person_name
lda #>jesper_name
sta.z print_person.person_name+1
ldy #0
ldx #jesper_id
jsr print_person
lda #<henriette_name
sta.z print_person.person_name
lda #>henriette_name
sta.z print_person.person_name+1
ldx #henriette_id
jsr print_person
rts
jesper_name: .text "jesper"
.byte 0
.fill 9, 0
henriette_name: .text "henriette"
.byte 0
.fill 6, 0
}
// print_person(byte register(X) person_id, byte[$10] zeropage(2) person_name)
print_person: {
.label person_name = 2
lda DIGIT,x
sta SCREEN,y
tya
tax
inx
lda #' '
sta SCREEN,x
inx
ldy #0
b1:
lda (person_name),y
cmp #0
bne b2
lda #' '
sta SCREEN,x
txa
tay
iny
rts
b2:
lda (person_name),y
sta SCREEN,x
inx
iny
jmp b1
}
DIGIT: .text "0123456789"
.byte 0

View File

@ -0,0 +1,46 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
[5] call print_person
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print_person
to:main::@return
main::@return: scope:[main] from main::@1
[8] return
to:@return
print_person: scope:[print_person] from main main::@1
[9] (byte[$10]) print_person::person_name#4 ← phi( main/(const byte[$10]) main::jesper_name#0 main::@1/(const byte[$10]) main::henriette_name#0 )
[9] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 )
[9] (byte) print_person::person_id#2 ← phi( main/(const byte) main::jesper_id#0 main::@1/(const byte) main::henriette_id#0 )
[10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + (byte) print_person::person_id#2)
[11] (byte) idx#4 ← ++ (byte) idx#13
[12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
[13] (byte) idx#5 ← ++ (byte) idx#4
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[$10]) print_person::person_name#4 + (byte) 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#0 + (byte) idx#14) ← (byte) ' '
[17] (byte) idx#16 ← ++ (byte) idx#14
to:print_person::@return
print_person::@return: scope:[print_person] from print_person::@3
[18] return
to:@return
print_person::@2: scope:[print_person] from print_person::@1
[19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)
[20] (byte) idx#6 ← ++ (byte) idx#14
[21] (byte) print_person::i#1 ← ++ (byte) print_person::i#2
to:print_person::@1

View File

@ -0,0 +1,913 @@
Fixing struct type size struct Person to 17
Fixing struct type size struct Person to 17
Fixing struct type size struct Person to 17
Created struct value member variable (byte) main::jesper_id
Created struct value member variable (byte[$10]) main::jesper_name
Converted struct value to member variables (struct Person) main::jesper
Created struct value member variable (byte) main::henriette_id
Created struct value member variable (byte[$10]) main::henriette_name
Converted struct value to member variables (struct Person) main::henriette
Created struct value member variable (byte) print_person::person_id
Created struct value member variable (byte[$10]) print_person::person_name
Converted struct value to member variables (struct Person) print_person::person
Converted procedure struct value parameter to member unwinding (void()) print_person((byte) print_person::person_id , (byte[$10]) print_person::person_name)
Adding struct value list initializer (byte) main::jesper_id ← (number) 4
Adding struct value list initializer (byte[$10]) main::jesper_name ← (string) "jesper"
Converted procedure struct value parameter to member unwinding in call (void~) main::$0 ← call print_person (byte) main::jesper_id (byte[$10]) main::jesper_name
Adding struct value list initializer (byte) main::henriette_id ← (number) 7
Adding struct value list initializer (byte[$10]) main::henriette_name ← (string) "henriette"
Converted procedure struct value parameter to member unwinding in call (void~) main::$1 ← call print_person (byte) main::henriette_id (byte[$10]) main::henriette_name
Replacing struct member reference (struct Person) print_person::person.id with member unwinding reference (byte) print_person::person_id
Replacing struct member reference (struct Person) print_person::person.name with member unwinding reference (byte[$10]) print_person::person_name
Replacing struct member reference (struct Person) print_person::person.name with member unwinding reference (byte[$10]) print_person::person_name
Warning! Adding boolean cast to non-boolean condition *((byte[$10]) print_person::person_name + (byte) print_person::i)
Identified constant variable (byte) main::jesper_id
Identified constant variable (byte[$10]) main::jesper_name
Identified constant variable (byte) main::henriette_id
Identified constant variable (byte[$10]) main::henriette_name
Culled Empty Block (label) print_person::@4
Culled Empty Block (label) print_person::@5
Culled Empty Block (label) print_person::@6
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @2
(byte) idx#18 ← phi( @2/(byte) idx#20 )
(byte) main::jesper_id#0 ← (number) 4
(byte[$10]) main::jesper_name#0 ← (const string) main::$2
(byte) print_person::person_id#0 ← (byte) main::jesper_id#0
(byte[$10]) print_person::person_name#0 ← (byte[$10]) main::jesper_name#0
call print_person
to:main::@1
main::@1: scope:[main] from main
(byte) idx#10 ← phi( main/(byte) idx#8 )
(byte) idx#0 ← (byte) idx#10
(byte) main::henriette_id#0 ← (number) 7
(byte[$10]) main::henriette_name#0 ← (const string) main::$3
(byte) print_person::person_id#1 ← (byte) main::henriette_id#0
(byte[$10]) print_person::person_name#1 ← (byte[$10]) main::henriette_name#0
call print_person
to:main::@2
main::@2: scope:[main] from main::@1
(byte) idx#11 ← phi( main::@1/(byte) idx#8 )
(byte) idx#1 ← (byte) idx#11
to:main::@return
main::@return: scope:[main] from main::@2
(byte) idx#12 ← phi( main::@2/(byte) idx#1 )
(byte) idx#2 ← (byte) idx#12
return
to:@return
@1: scope:[] from @begin
(byte*) SCREEN#0 ← ((byte*)) (number) $400
(byte) idx#3 ← (number) 0
(byte[]) DIGIT#0 ← (const string) $0
to:@2
print_person: scope:[print_person] from main main::@1
(byte[$10]) print_person::person_name#4 ← phi( main/(byte[$10]) print_person::person_name#0 main::@1/(byte[$10]) print_person::person_name#1 )
(byte) idx#13 ← phi( main/(byte) idx#18 main::@1/(byte) idx#0 )
(byte) print_person::person_id#2 ← phi( main/(byte) print_person::person_id#0 main::@1/(byte) print_person::person_id#1 )
*((byte*) SCREEN#0 + (byte) idx#13) ← *((byte[]) DIGIT#0 + (byte) print_person::person_id#2)
(byte) idx#4 ← ++ (byte) idx#13
*((byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
(byte) idx#5 ← ++ (byte) idx#4
(byte) print_person::i#0 ← (number) 0
to:print_person::@1
print_person::@1: scope:[print_person] from print_person print_person::@2
(byte) idx#19 ← phi( print_person/(byte) idx#5 print_person::@2/(byte) idx#6 )
(byte) print_person::i#2 ← phi( print_person/(byte) print_person::i#0 print_person::@2/(byte) print_person::i#1 )
(byte[$10]) print_person::person_name#2 ← phi( print_person/(byte[$10]) print_person::person_name#4 print_person::@2/(byte[$10]) print_person::person_name#3 )
(bool~) print_person::$0 ← (number) 0 != *((byte[$10]) print_person::person_name#2 + (byte) print_person::i#2)
if((bool~) print_person::$0) goto print_person::@2
to:print_person::@3
print_person::@2: scope:[print_person] from print_person::@1
(byte) idx#14 ← phi( print_person::@1/(byte) idx#19 )
(byte) print_person::i#3 ← phi( print_person::@1/(byte) print_person::i#2 )
(byte[$10]) print_person::person_name#3 ← phi( print_person::@1/(byte[$10]) print_person::person_name#2 )
*((byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#3 + (byte) print_person::i#3)
(byte) idx#6 ← ++ (byte) idx#14
(byte) print_person::i#1 ← ++ (byte) print_person::i#3
to:print_person::@1
print_person::@3: scope:[print_person] from print_person::@1
(byte) idx#15 ← phi( print_person::@1/(byte) idx#19 )
*((byte*) SCREEN#0 + (byte) idx#15) ← (byte) ' '
(byte) idx#7 ← ++ (byte) idx#15
to:print_person::@return
print_person::@return: scope:[print_person] from print_person::@3
(byte) idx#16 ← phi( print_person::@3/(byte) idx#7 )
(byte) idx#8 ← (byte) idx#16
return
to:@return
@2: scope:[] from @1
(byte) idx#20 ← phi( @1/(byte) idx#3 )
call main
to:@3
@3: scope:[] from @2
(byte) idx#17 ← phi( @2/(byte) idx#2 )
(byte) idx#9 ← (byte) idx#17
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(const string) $0 = (string) "0123456789"
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(byte[]) DIGIT
(byte[]) DIGIT#0
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(byte*) SCREEN#0
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#10
(byte) idx#11
(byte) idx#12
(byte) idx#13
(byte) idx#14
(byte) idx#15
(byte) idx#16
(byte) idx#17
(byte) idx#18
(byte) idx#19
(byte) idx#2
(byte) idx#20
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(const string) main::$2 = (string) "jesper"
(const string) main::$3 = (string) "henriette"
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::henriette_id
(byte) main::henriette_id#0
(byte[$10]) main::henriette_name
(byte[$10]) main::henriette_name#0
(byte) main::jesper_id
(byte) main::jesper_id#0
(byte[$10]) main::jesper_name
(byte[$10]) main::jesper_name#0
(void()) print_person((byte) print_person::person_id , (byte[$10]) print_person::person_name)
(bool~) print_person::$0
(label) print_person::@1
(label) print_person::@2
(label) print_person::@3
(label) print_person::@return
(byte) print_person::i
(byte) print_person::i#0
(byte) print_person::i#1
(byte) print_person::i#2
(byte) print_person::i#3
(struct Person) print_person::person
(byte) print_person::person_id
(byte) print_person::person_id#0
(byte) print_person::person_id#1
(byte) print_person::person_id#2
(byte[$10]) print_person::person_name
(byte[$10]) print_person::person_name#0
(byte[$10]) print_person::person_name#1
(byte[$10]) print_person::person_name#2
(byte[$10]) print_person::person_name#3
(byte[$10]) print_person::person_name#4
Adding number conversion cast (unumber) 4 in (byte) main::jesper_id#0 ← (number) 4
Adding number conversion cast (unumber) 7 in (byte) main::henriette_id#0 ← (number) 7
Adding number conversion cast (unumber) 0 in (byte) idx#3 ← (number) 0
Adding number conversion cast (unumber) 0 in (byte) print_person::i#0 ← (number) 0
Adding number conversion cast (unumber) 0 in (bool~) print_person::$0 ← (number) 0 != *((byte[$10]) print_person::person_name#2 + (byte) print_person::i#2)
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte) main::jesper_id#0 ← (unumber)(number) 4
Inlining cast (byte) main::henriette_id#0 ← (unumber)(number) 7
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) idx#3 ← (unumber)(number) 0
Inlining cast (byte) print_person::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 4
Simplifying constant integer cast 7
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 4
Finalized unsigned number type (byte) 7
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte) idx#0 = (byte) idx#10
Alias (byte) idx#1 = (byte) idx#11 (byte) idx#12 (byte) idx#2
Alias (byte[$10]) print_person::person_name#2 = (byte[$10]) print_person::person_name#3
Alias (byte) print_person::i#2 = (byte) print_person::i#3
Alias (byte) idx#14 = (byte) idx#19 (byte) idx#15
Alias (byte) idx#16 = (byte) idx#7 (byte) idx#8
Alias (byte) idx#20 = (byte) idx#3
Alias (byte) idx#17 = (byte) idx#9
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#18 (byte) idx#20
Identical Phi Values (byte) idx#0 (byte) idx#16
Identical Phi Values (byte) idx#1 (byte) idx#16
Identical Phi Values (byte[$10]) print_person::person_name#2 (byte[$10]) print_person::person_name#4
Identical Phi Values (byte) idx#17 (byte) idx#1
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) print_person::$0 [29] if((byte) 0!=*((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)) goto print_person::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte) main::jesper_id#0 = 4
Constant (const byte[$10]) main::jesper_name#0 = main::$2
Constant (const byte) main::henriette_id#0 = 7
Constant (const byte[$10]) main::henriette_name#0 = main::$3
Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const byte) idx#20 = 0
Constant (const byte[]) DIGIT#0 = $0
Constant (const byte) print_person::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const byte) print_person::person_id#0 = main::jesper_id#0
Constant (const byte[$10]) print_person::person_name#0 = main::jesper_name#0
Constant (const byte) print_person::person_id#1 = main::henriette_id#0
Constant (const byte[$10]) print_person::person_name#1 = main::henriette_name#0
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with var siblings (const byte) print_person::i#0
Inlining constant with var siblings (const byte) print_person::person_id#0
Inlining constant with var siblings (const byte[$10]) print_person::person_name#0
Inlining constant with var siblings (const byte) print_person::person_id#1
Inlining constant with var siblings (const byte[$10]) print_person::person_name#1
Inlining constant with var siblings (const byte) idx#20
Constant inlined idx#20 = (byte) 0
Constant inlined print_person::person_id#1 = (const byte) main::henriette_id#0
Constant inlined print_person::person_id#0 = (const byte) main::jesper_id#0
Constant inlined main::$2 = (const byte[$10]) main::jesper_name#0
Constant inlined print_person::i#0 = (byte) 0
Constant inlined print_person::person_name#1 = (const byte[$10]) main::henriette_name#0
Constant inlined main::$3 = (const byte[$10]) main::henriette_name#0
Constant inlined $0 = (const byte[]) DIGIT#0
Constant inlined print_person::person_name#0 = (const byte[$10]) main::jesper_name#0
Successful SSA optimization Pass2ConstantInlining
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 @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@2
CALL GRAPH
Calls in [] to main:3
Calls in [main] to print_person:7 print_person:9
Created 5 initial phi equivalence classes
Coalesced [8] idx#21 ← idx#16
Coalesced [17] idx#22 ← idx#5
Coalesced [26] print_person::i#4 ← print_person::i#1
Coalesced [27] idx#23 ← idx#6
Coalesced down to 5 phi equivalence classes
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Culled Empty Block (label) main::@2
Renumbering block @2 to @1
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
[5] call print_person
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print_person
to:main::@return
main::@return: scope:[main] from main::@1
[8] return
to:@return
print_person: scope:[print_person] from main main::@1
[9] (byte[$10]) print_person::person_name#4 ← phi( main/(const byte[$10]) main::jesper_name#0 main::@1/(const byte[$10]) main::henriette_name#0 )
[9] (byte) idx#13 ← phi( main/(byte) 0 main::@1/(byte) idx#16 )
[9] (byte) print_person::person_id#2 ← phi( main/(const byte) main::jesper_id#0 main::@1/(const byte) main::henriette_id#0 )
[10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + (byte) print_person::person_id#2)
[11] (byte) idx#4 ← ++ (byte) idx#13
[12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' '
[13] (byte) idx#5 ← ++ (byte) idx#4
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[$10]) print_person::person_name#4 + (byte) 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#0 + (byte) idx#14) ← (byte) ' '
[17] (byte) idx#16 ← ++ (byte) idx#14
to:print_person::@return
print_person::@return: scope:[print_person] from print_person::@3
[18] return
to:@return
print_person::@2: scope:[print_person] from print_person::@1
[19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)
[20] (byte) idx#6 ← ++ (byte) idx#14
[21] (byte) print_person::i#1 ← ++ (byte) print_person::i#2
to:print_person::@1
VARIABLE REGISTER WEIGHTS
(byte[]) DIGIT
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(byte) idx
(byte) idx#13 3.0
(byte) idx#14 9.75
(byte) idx#16 1.0
(byte) idx#4 3.0
(byte) idx#5 4.0
(byte) idx#6 11.0
(void()) main()
(byte) main::henriette_id
(byte[$10]) main::henriette_name
(byte) main::jesper_id
(byte[$10]) main::jesper_name
(void()) print_person((byte) print_person::person_id , (byte[$10]) print_person::person_name)
(byte) print_person::i
(byte) print_person::i#1 22.0
(byte) print_person::i#2 11.0
(struct Person) print_person::person
(byte) print_person::person_id
(byte) print_person::person_id#2 2.0
(byte[$10]) print_person::person_name
(byte[$10]) print_person::person_name#4 2.2
Initial phi equivalence classes
[ print_person::person_id#2 ]
[ idx#13 idx#16 ]
[ print_person::person_name#4 ]
[ print_person::i#2 print_person::i#1 ]
[ idx#14 idx#5 idx#6 ]
Added variable idx#4 to zero page equivalence class [ idx#4 ]
Complete equivalence classes
[ print_person::person_id#2 ]
[ idx#13 idx#16 ]
[ print_person::person_name#4 ]
[ print_person::i#2 print_person::i#1 ]
[ idx#14 idx#5 idx#6 ]
[ idx#4 ]
Allocated zp ZP_BYTE:2 [ print_person::person_id#2 ]
Allocated zp ZP_BYTE:3 [ idx#13 idx#16 ]
Allocated zp ZP_WORD:4 [ print_person::person_name#4 ]
Allocated zp ZP_BYTE:6 [ print_person::i#2 print_person::i#1 ]
Allocated zp ZP_BYTE:7 [ idx#14 idx#5 idx#6 ]
Allocated zp ZP_BYTE:8 [ idx#4 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Example of a struct containing an array
// It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers.
// https://gitlab.com/camelot/kickc/issues/312
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
.label idx = 8
.label idx_5 = 7
.label idx_6 = 7
.label idx_13 = 3
.label idx_14 = 7
.label idx_16 = 3
// @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: {
.const jesper_id = 4
.const henriette_id = 7
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte[$10]) print_person::person_name#4 = (const byte[$10]) main::jesper_name#0 [phi:main->print_person#0] -- pbuz1=pbuc1
lda #<jesper_name
sta.z print_person.person_name
lda #>jesper_name
sta.z print_person.person_name+1
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#1] -- vbuz1=vbuc1
lda #0
sta.z idx_13
// [9] phi (byte) print_person::person_id#2 = (const byte) main::jesper_id#0 [phi:main->print_person#2] -- vbuz1=vbuc1
lda #jesper_id
sta.z print_person.person_id
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
// main::@1
b1:
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
print_person_from_b1:
// [9] phi (byte[$10]) print_person::person_name#4 = (const byte[$10]) main::henriette_name#0 [phi:main::@1->print_person#0] -- pbuz1=pbuc1
lda #<henriette_name
sta.z print_person.person_name
lda #>henriette_name
sta.z print_person.person_name+1
// [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#1] -- register_copy
// [9] phi (byte) print_person::person_id#2 = (const byte) main::henriette_id#0 [phi:main::@1->print_person#2] -- vbuz1=vbuc1
lda #henriette_id
sta.z print_person.person_id
jsr print_person
jmp breturn
// main::@return
breturn:
// [8] return
rts
jesper_name: .text "jesper"
.byte 0
.fill 9, 0
henriette_name: .text "henriette"
.byte 0
.fill 6, 0
}
// print_person
// print_person(byte zeropage(2) person_id, byte[$10] zeropage(4) person_name)
print_person: {
.label i = 6
.label person_id = 2
.label person_name = 4
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + (byte) print_person::person_id#2) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2
ldy.z person_id
lda DIGIT,y
ldy.z idx_13
sta SCREEN,y
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuz1=_inc_vbuz2
ldy.z idx_13
iny
sty.z idx
// [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy.z idx
sta SCREEN,y
// [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2
ldy.z idx
iny
sty.z idx_5
// [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1]
b1_from_print_person:
// [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuz1=vbuc1
lda #0
sta.z i
jmp b1
// print_person::@1
b1:
// [15] if((byte) 0!=*((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuz2_then_la1
ldy.z i
lda (person_name),y
cmp #0
bne b2
jmp b3
// print_person::@3
b3:
// [16] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy.z idx_14
sta SCREEN,y
// [17] (byte) idx#16 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2
ldy.z idx_14
iny
sty.z idx_16
jmp breturn
// print_person::@return
breturn:
// [18] return
rts
// print_person::@2
b2:
// [19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz3
ldx.z idx_14
ldy.z i
lda (person_name),y
sta SCREEN,x
// [20] (byte) idx#6 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz1
inc.z idx_6
// [21] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1]
b1_from_b2:
// [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy
jmp b1
}
// File Data
DIGIT: .text "0123456789"
.byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + (byte) print_person::person_id#2) [ idx#13 print_person::person_name#4 ] ( main:2::print_person:5 [ idx#13 print_person::person_name#4 ] main:2::print_person:7 [ idx#13 print_person::person_name#4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ idx#13 idx#16 ]
Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person_name#4 idx#4 ] ( main:2::print_person:5 [ print_person::person_name#4 idx#4 ] main:2::print_person:7 [ print_person::person_name#4 idx#4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ idx#4 ]
Statement [15] if((byte) 0!=*((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person_name#4 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person_name#4 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person_name#4 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ print_person::i#2 print_person::i#1 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ idx#14 idx#5 idx#6 ]
Statement [16] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:5 [ idx#14 ] main:2::print_person:7 [ idx#14 ] ) always clobbers reg byte a
Statement [19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2) [ print_person::person_name#4 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person_name#4 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person_name#4 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Statement [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + (byte) print_person::person_id#2) [ idx#13 print_person::person_name#4 ] ( main:2::print_person:5 [ idx#13 print_person::person_name#4 ] main:2::print_person:7 [ idx#13 print_person::person_name#4 ] ) always clobbers reg byte a
Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person_name#4 idx#4 ] ( main:2::print_person:5 [ print_person::person_name#4 idx#4 ] main:2::print_person:7 [ print_person::person_name#4 idx#4 ] ) always clobbers reg byte a
Statement [15] if((byte) 0!=*((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)) goto print_person::@2 [ print_person::person_name#4 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person_name#4 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person_name#4 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Statement [16] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' [ idx#14 ] ( main:2::print_person:5 [ idx#14 ] main:2::print_person:7 [ idx#14 ] ) always clobbers reg byte a
Statement [19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2) [ print_person::person_name#4 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person_name#4 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person_name#4 print_person::i#2 idx#14 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ print_person::person_id#2 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ idx#13 idx#16 ] : zp ZP_BYTE:3 , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:4 [ print_person::person_name#4 ] : zp ZP_WORD:4 ,
Potential registers zp ZP_BYTE:6 [ print_person::i#2 print_person::i#1 ] : zp ZP_BYTE:6 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:7 [ idx#14 idx#5 idx#6 ] : zp ZP_BYTE:7 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:8 [ idx#4 ] : zp ZP_BYTE:8 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [print_person] 33: zp ZP_BYTE:6 [ print_person::i#2 print_person::i#1 ] 2.2: zp ZP_WORD:4 [ print_person::person_name#4 ] 2: zp ZP_BYTE:2 [ print_person::person_id#2 ]
Uplift Scope [] 24.75: zp ZP_BYTE:7 [ idx#14 idx#5 idx#6 ] 4: zp ZP_BYTE:3 [ idx#13 idx#16 ] 3: zp ZP_BYTE:8 [ idx#4 ]
Uplift Scope [Person]
Uplift Scope [main]
Uplifting [print_person] best 545 combination reg byte y [ print_person::i#2 print_person::i#1 ] zp ZP_WORD:4 [ print_person::person_name#4 ] reg byte x [ print_person::person_id#2 ]
Uplifting [] best 463 combination reg byte x [ idx#14 idx#5 idx#6 ] reg byte y [ idx#13 idx#16 ] reg byte x [ idx#4 ]
Uplifting [Person] best 463 combination
Uplifting [main] best 463 combination
Allocated (was zp ZP_WORD:4) zp ZP_WORD:2 [ print_person::person_name#4 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Example of a struct containing an array
// It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers.
// https://gitlab.com/camelot/kickc/issues/312
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
.const jesper_id = 4
.const henriette_id = 7
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte[$10]) print_person::person_name#4 = (const byte[$10]) main::jesper_name#0 [phi:main->print_person#0] -- pbuz1=pbuc1
lda #<jesper_name
sta.z print_person.person_name
lda #>jesper_name
sta.z print_person.person_name+1
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#1] -- vbuyy=vbuc1
ldy #0
// [9] phi (byte) print_person::person_id#2 = (const byte) main::jesper_id#0 [phi:main->print_person#2] -- vbuxx=vbuc1
ldx #jesper_id
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
// main::@1
b1:
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
print_person_from_b1:
// [9] phi (byte[$10]) print_person::person_name#4 = (const byte[$10]) main::henriette_name#0 [phi:main::@1->print_person#0] -- pbuz1=pbuc1
lda #<henriette_name
sta.z print_person.person_name
lda #>henriette_name
sta.z print_person.person_name+1
// [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#1] -- register_copy
// [9] phi (byte) print_person::person_id#2 = (const byte) main::henriette_id#0 [phi:main::@1->print_person#2] -- vbuxx=vbuc1
ldx #henriette_id
jsr print_person
jmp breturn
// main::@return
breturn:
// [8] return
rts
jesper_name: .text "jesper"
.byte 0
.fill 9, 0
henriette_name: .text "henriette"
.byte 0
.fill 6, 0
}
// print_person
// print_person(byte register(X) person_id, byte[$10] zeropage(2) person_name)
print_person: {
.label person_name = 2
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + (byte) print_person::person_id#2) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx
lda DIGIT,x
sta SCREEN,y
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuyy
tya
tax
inx
// [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx
inx
// [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1]
b1_from_print_person:
// [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuyy=vbuc1
ldy #0
jmp b1
// print_person::@1
b1:
// [15] if((byte) 0!=*((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1
lda (person_name),y
cmp #0
bne b2
jmp b3
// print_person::@3
b3:
// [16] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// [17] (byte) idx#16 ← ++ (byte) idx#14 -- vbuyy=_inc_vbuxx
txa
tay
iny
jmp breturn
// print_person::@return
breturn:
// [18] return
rts
// print_person::@2
b2:
// [19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (person_name),y
sta SCREEN,x
// [20] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx
inx
// [21] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuyy=_inc_vbuyy
iny
// [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1]
b1_from_b2:
// [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy
jmp b1
}
// File Data
DIGIT: .text "0123456789"
.byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
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:
Removing instruction b1_from_main:
Removing instruction print_person_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction print_person_from_main:
Removing instruction b1:
Removing instruction breturn:
Removing instruction b1_from_print_person:
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
(byte[]) DIGIT
(const byte[]) DIGIT#0 DIGIT = (string) "0123456789"
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx
(byte) idx#13 reg byte y 3.0
(byte) idx#14 reg byte x 9.75
(byte) idx#16 reg byte y 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
(byte) main::henriette_id
(const byte) main::henriette_id#0 henriette_id = (byte) 7
(byte[$10]) main::henriette_name
(const byte[$10]) main::henriette_name#0 henriette_name = (string) "henriette"
(byte) main::jesper_id
(const byte) main::jesper_id#0 jesper_id = (byte) 4
(byte[$10]) main::jesper_name
(const byte[$10]) main::jesper_name#0 jesper_name = (string) "jesper"
(void()) print_person((byte) print_person::person_id , (byte[$10]) print_person::person_name)
(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 reg byte y 22.0
(byte) print_person::i#2 reg byte y 11.0
(struct Person) print_person::person
(byte) print_person::person_id
(byte) print_person::person_id#2 reg byte x 2.0
(byte[$10]) print_person::person_name
(byte[$10]) print_person::person_name#4 person_name zp ZP_WORD:2 2.2
reg byte x [ print_person::person_id#2 ]
reg byte y [ idx#13 idx#16 ]
zp ZP_WORD:2 [ print_person::person_name#4 ]
reg byte y [ print_person::i#2 print_person::i#1 ]
reg byte x [ idx#14 idx#5 idx#6 ]
reg byte x [ idx#4 ]
FINAL ASSEMBLER
Score: 382
// File Comments
// Example of a struct containing an array
// It works on the surface - but illustrates the problem with structs containing arrays treating them like pointers.
// https://gitlab.com/camelot/kickc/issues/312
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.const jesper_id = 4
.const henriette_id = 7
// print_person(jesper)
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
// [9] phi (byte[$10]) print_person::person_name#4 = (const byte[$10]) main::jesper_name#0 [phi:main->print_person#0] -- pbuz1=pbuc1
lda #<jesper_name
sta.z print_person.person_name
lda #>jesper_name
sta.z print_person.person_name+1
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#1] -- vbuyy=vbuc1
ldy #0
// [9] phi (byte) print_person::person_id#2 = (const byte) main::jesper_id#0 [phi:main->print_person#2] -- vbuxx=vbuc1
ldx #jesper_id
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
// main::@1
// print_person(henriette)
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
// [9] phi (byte[$10]) print_person::person_name#4 = (const byte[$10]) main::henriette_name#0 [phi:main::@1->print_person#0] -- pbuz1=pbuc1
lda #<henriette_name
sta.z print_person.person_name
lda #>henriette_name
sta.z print_person.person_name+1
// [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#1] -- register_copy
// [9] phi (byte) print_person::person_id#2 = (const byte) main::henriette_id#0 [phi:main::@1->print_person#2] -- vbuxx=vbuc1
ldx #henriette_id
jsr print_person
// main::@return
// }
// [8] return
rts
jesper_name: .text "jesper"
.byte 0
.fill 9, 0
henriette_name: .text "henriette"
.byte 0
.fill 6, 0
}
// print_person
// print_person(byte register(X) person_id, byte[$10] zeropage(2) person_name)
print_person: {
.label person_name = 2
// SCREEN[idx++] = DIGIT[person.id]
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + (byte) print_person::person_id#2) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx
lda DIGIT,x
sta SCREEN,y
// SCREEN[idx++] = DIGIT[person.id];
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuyy
tya
tax
inx
// SCREEN[idx++] = ' '
// [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// SCREEN[idx++] = ' ';
// [13] (byte) idx#5 ← ++ (byte) idx#4 -- vbuxx=_inc_vbuxx
inx
// [14] phi from print_person to print_person::@1 [phi:print_person->print_person::@1]
// [14] phi (byte) idx#14 = (byte) idx#5 [phi:print_person->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) 0 [phi:print_person->print_person::@1#1] -- vbuyy=vbuc1
ldy #0
// print_person::@1
b1:
// for(byte i=0; person.name[i]; i++)
// [15] if((byte) 0!=*((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_pbuz1_derefidx_vbuyy_then_la1
lda (person_name),y
cmp #0
bne b2
// print_person::@3
// SCREEN[idx++] = ' '
// [16] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
// SCREEN[idx++] = ' ';
// [17] (byte) idx#16 ← ++ (byte) idx#14 -- vbuyy=_inc_vbuxx
txa
tay
iny
// print_person::@return
// }
// [18] return
rts
// print_person::@2
b2:
// SCREEN[idx++] = person.name[i]
// [19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$10]) print_person::person_name#4 + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (person_name),y
sta SCREEN,x
// SCREEN[idx++] = person.name[i];
// [20] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx
inx
// for(byte i=0; person.name[i]; i++)
// [21] (byte) print_person::i#1 ← ++ (byte) print_person::i#2 -- vbuyy=_inc_vbuyy
iny
// [14] phi from print_person::@2 to print_person::@1 [phi:print_person::@2->print_person::@1]
// [14] phi (byte) idx#14 = (byte) idx#6 [phi:print_person::@2->print_person::@1#0] -- register_copy
// [14] phi (byte) print_person::i#2 = (byte) print_person::i#1 [phi:print_person::@2->print_person::@1#1] -- register_copy
jmp b1
}
// File Data
DIGIT: .text "0123456789"
.byte 0

View File

@ -0,0 +1,47 @@
(label) @1
(label) @begin
(label) @end
(byte[]) DIGIT
(const byte[]) DIGIT#0 DIGIT = (string) "0123456789"
(byte) Person::id
(byte[$10]) Person::name
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx
(byte) idx#13 reg byte y 3.0
(byte) idx#14 reg byte x 9.75
(byte) idx#16 reg byte y 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
(byte) main::henriette_id
(const byte) main::henriette_id#0 henriette_id = (byte) 7
(byte[$10]) main::henriette_name
(const byte[$10]) main::henriette_name#0 henriette_name = (string) "henriette"
(byte) main::jesper_id
(const byte) main::jesper_id#0 jesper_id = (byte) 4
(byte[$10]) main::jesper_name
(const byte[$10]) main::jesper_name#0 jesper_name = (string) "jesper"
(void()) print_person((byte) print_person::person_id , (byte[$10]) print_person::person_name)
(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 reg byte y 22.0
(byte) print_person::i#2 reg byte y 11.0
(struct Person) print_person::person
(byte) print_person::person_id
(byte) print_person::person_id#2 reg byte x 2.0
(byte[$10]) print_person::person_name
(byte[$10]) print_person::person_name#4 person_name zp ZP_WORD:2 2.2
reg byte x [ print_person::person_id#2 ]
reg byte y [ idx#13 idx#16 ]
zp ZP_WORD:2 [ print_person::person_name#4 ]
reg byte y [ print_person::i#2 print_person::i#1 ]
reg byte x [ idx#14 idx#5 idx#6 ]
reg byte x [ idx#4 ]