1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-02-07 20:31:32 +00:00

Added missing struct-ptr fragments. Added padding to initialization of fixed size arrays with to few elements in the initializer. Closes #311

This commit is contained in:
jespergravgaard 2019-09-09 23:01:04 +02:00
parent d6ad2c3b9b
commit 5fe5c9f84b
34 changed files with 4869 additions and 99 deletions

View File

@ -0,0 +1,8 @@
stx $fd
lda ({z1}),y
sta $fe
iny
lda ({z1}),y
sta $ff
ldy $fd
lda ($fe),y

View File

@ -0,0 +1,7 @@
lda ({z1}),y
sta $fe
iny
lda ({z1}),y
sta $ff
ldy {z2}
lda ($fe),y

View File

@ -0,0 +1,10 @@
stx $fd
lda ({z1}),y
sta $fe
iny
lda ({z1}),y
sta $ff
ldy $fd
lda ($fe),y
cmp #{c1}
bne {la1}

View File

@ -0,0 +1,9 @@
lda ({z1}),y
sta $fe
iny
lda ({z1}),y
sta $ff
ldy {z2}
lda ($fe),y
cmp #{c1}
bne {la1}

View File

@ -36,7 +36,9 @@ public class AsmDataFill implements AsmLine {
@Override
public String getAsm() {
StringBuilder asm = new StringBuilder();
asm.append(label + ": ");
if(label!=null) {
asm.append(label + ": ");
}
asm.append(".fill ");
asm.append(sizeAsm);
asm.append(", ");

View File

@ -0,0 +1,37 @@
package dk.camelot64.kickc.model.values;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.symbols.ProgramScope;
import dk.camelot64.kickc.model.symbols.StructDefinition;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeIntegerFixed;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import java.util.LinkedHashMap;
/**
* Factory usable for creating the default "zero" values for all types.
*/
public class ZeroConstantValues {
public static ConstantValue zeroValue(SymbolType type, ProgramScope programScope) {
if(type instanceof SymbolTypeStruct) {
SymbolTypeStruct typeStruct = (SymbolTypeStruct) type;
LinkedHashMap<VariableRef, ConstantValue> zeroValues = new LinkedHashMap<>();
StructDefinition structDefinition = typeStruct.getStructDefinition(programScope);
for(Variable memberVar : structDefinition.getAllVariables(false)) {
zeroValues.put(memberVar.getRef(), zeroValue(memberVar.getType(), programScope));
}
return new ConstantStructValue(typeStruct, zeroValues);
} else if(type instanceof SymbolTypeIntegerFixed) {
return new ConstantInteger(0L, type);
} else if(type instanceof SymbolTypePointer) {
return new ConstantPointer(0L, ((SymbolTypePointer) type).getElementType());
} else {
throw new InternalError("Unhandled type " + type);
}
}
}

View File

@ -50,7 +50,7 @@ public class Pass3AssertArrayLengths extends Pass2SsaAssertion {
}
} else if(constantValue instanceof ConstantArrayList) {
Integer assignedSizeVal = ((ConstantArrayList) constantValue).getElements().size();
if(!assignedSizeVal.equals(declaredSizeInt)) {
if(assignedSizeVal > declaredSizeInt) {
throw new CompileError("Error! Array length mismatch " + constantVar.toString(getProgram()));
}
} else if(constantValue instanceof ConstantArrayKickAsm) {
@ -59,7 +59,7 @@ public class Pass3AssertArrayLengths extends Pass2SsaAssertion {
ConstantLiteral constantLiteral = constantValue.calculateLiteral(getScope());
if(constantLiteral instanceof ConstantString) {
Integer assignedSizeVal = ((ConstantString) constantLiteral).getString().length();
if(!assignedSizeVal.equals(declaredSizeInt)) {
if(assignedSizeVal > declaredSizeInt) {
throw new CompileError("Error! Array length mismatch " + constantVar.toString(getProgram()));
}
} else if(constantLiteral instanceof ConstantPointer) {

View File

@ -467,6 +467,18 @@ public class Pass4CodeGeneration {
addChunkData(asmDataChunk, element, scopeRef);
asm.addDataNumeric(null, asmDataChunk);
}
// Pad output to match declared size (if larger than the data list)
int dataSize = constantArrayList.getElements().size();
Integer declaredSize = getArrayDeclaredSize(constantVar);
if(declaredSize!=null && declaredSize>dataSize) {
int padding = declaredSize - dataSize;
ConstantStructValue zeroStructValue = (ConstantStructValue) ZeroConstantValues.zeroValue(elementType, program.getScope());
for(int i=0; i<padding; i++) {
AsmProgram.AsmDataNumericChunk asmDataChunk = new AsmProgram.AsmDataNumericChunk();
addChunkData(asmDataChunk, zeroStructValue, scopeRef);
asm.addDataNumeric(null, asmDataChunk);
}
}
} else if(elementType instanceof SymbolTypeArray) {
// Constant array of sub-arrays
throw new InternalError("Array of array not supported");
@ -478,6 +490,31 @@ public class Pass4CodeGeneration {
addChunkData(asmDataChunk, element, scopeRef);
}
asm.addDataNumeric(asmName, asmDataChunk);
// Pad output to match declared size (if larger than the data list)
int dataSize = constantArrayList.getElements().size();
Integer declaredSize = getArrayDeclaredSize(constantVar);
if(declaredSize!=null && declaredSize>dataSize) {
int padding = declaredSize-dataSize;
AsmDataNumeric.Type dataType;
if(SymbolType.BYTE.equals(elementType)) {
dataType = AsmDataNumeric.Type.BYTE;
} else if(SymbolType.SBYTE.equals(elementType)) {
dataType = AsmDataNumeric.Type.BYTE;
} else if(SymbolType.WORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.WORD;
} else if(SymbolType.SWORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.WORD;
} else if(SymbolType.DWORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.DWORD;
} else if(SymbolType.SDWORD.equals(elementType)) {
dataType = AsmDataNumeric.Type.DWORD;
} else if(elementType instanceof SymbolTypePointer) {
dataType = AsmDataNumeric.Type.WORD;
} else {
throw new InternalError("Unhandled constant array element type " + constantArrayList.toString(program));
}
asm.addDataFilled(null, dataType, Integer.toString(padding), padding, "0");
}
}
} else if(constantValue instanceof ConstantArrayFilled) {
ConstantArrayFilled constantArrayFilled = (ConstantArrayFilled) constantValue;
@ -549,8 +586,16 @@ public class Pass4CodeGeneration {
ensureEncoding(asm, constantValue);
String asmConstant = AsmFormat.getAsmConstant(program, constantValue, 99, scopeRef);
asm.addDataString(AsmFormat.asmFix(asmName), asmConstant);
int dataSize = ((ConstantString) literal).getString().length();
if(((ConstantString) literal).isZeroTerminated()) {
asm.addDataNumeric(null, AsmDataNumeric.Type.BYTE, Collections.singletonList(AsmFormat.getAsmNumber(0L)));
dataSize++;
}
// Pad output to match declared size (if larger than the data list)
Integer declaredSize = getArrayDeclaredSize(constantVar);
if(declaredSize!=null && declaredSize>dataSize) {
int padding = declaredSize-dataSize;
asm.addDataFilled(null, AsmDataNumeric.Type.BYTE, Integer.toString(padding), padding, "0");
}
added.add(asmName);
}
@ -562,6 +607,29 @@ public class Pass4CodeGeneration {
}
}
/**
* Get the declared size of an array variable.
* @param constantVar The array variable
* @return The declared size. Null if the type is not array or no size is declared.
*/
private Integer getArrayDeclaredSize(ConstantVar constantVar) {
SymbolType constantType = constantVar.getType();
if(constantType instanceof SymbolTypeArray) {
RValue declaredSize = ((SymbolTypeArray) constantType).getSize();
if(declaredSize != null) {
if(!(declaredSize instanceof ConstantValue)) {
throw new CompileError("Error! Array declared size is not constant " + constantType.toString());
}
ConstantLiteral declaredSizeVal = ((ConstantValue) declaredSize).calculateLiteral(getScope());
if(!(declaredSizeVal instanceof ConstantInteger)) {
throw new CompileError("Error! Array declared size is not integer " + constantType.toString());
}
return ((ConstantInteger) declaredSizeVal).getInteger().intValue();
}
}
return null;
}
/**
* Fill the data of a constant value into a data chunk

View File

@ -35,10 +35,10 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testOs51() throws IOException, URISyntaxException {
compileAndCompare("complex/unit5/os5.1", log().verboseSSAOptimize());
}
//@Test
//public void testOs51() throws IOException, URISyntaxException {
// compileAndCompare("complex/unit5/os5.1", log().verboseSSAOptimize());
//}
@Test
public void testCpu6502() throws IOException, URISyntaxException {
@ -649,6 +649,26 @@ public class TestPrograms {
}
*/
//@Test
//public void testStructPtr31() throws IOException, URISyntaxException {
// compileAndCompare("struct-ptr-31");
//}
@Test
public void testStructPtr30() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-30");
}
@Test
public void testStructPtr29() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-29");
}
@Test
public void testStructPtr28() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-28");
}
@Test
public void testStructPtr26() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-26");
@ -821,6 +841,11 @@ public class TestPrograms {
assertError("struct-err-0", "Unknown struct type");
}
@Test
public void testStruct12() throws IOException, URISyntaxException {
compileAndCompare("struct-12");
}
@Test
public void testStruct11() throws IOException, URISyntaxException {
compileAndCompare("struct-11");
@ -2578,6 +2603,11 @@ public class TestPrograms {
compileAndCompare("test-multiply-16bit");
}
@Test
public void testArraysInitShort() throws IOException, URISyntaxException {
compileAndCompare("arrays-init-short");
}
@Test
public void testArraysInit() throws IOException, URISyntaxException {
compileAndCompare("arrays-init");
@ -3187,6 +3217,7 @@ public class TestPrograms {
private void testFile(String fileName, Integer upliftCombinations, CompileLog compileLog) throws IOException, URISyntaxException {
System.out.println("Testing output for " + fileName);
Compiler compiler = new Compiler();
//compiler.setWarnFragmentMissing(true);
compiler.setAsmFragmentBaseFolder(new File("src/main/fragment/").toPath());
compiler.setAsmFragmentCacheFolder(null);
if(compileLog != null) {

View File

@ -1,4 +1,4 @@
byte[3] b = { 1, 2 };
byte[3] b = { 1, 2, 3, 4, 5 };
void main() {
byte* SCREEN = $400;

View File

@ -0,0 +1,13 @@
// Test a short array initializer - the rest should be zero-filled
char[16] msg1 ="camelot";
char[16] msg2 = { 'c', 'm', 'l' };
const char* SCREEN = 0x400;
void main() {
for(char i=0;msg1[i];i++)
SCREEN[i] = msg1[i];
for(char i=0;msg2[i];i++)
(SCREEN+40)[i] = msg2[i];
}

34
src/test/kc/struct-12.kc Normal file
View File

@ -0,0 +1,34 @@
// Example of a struct containing an array
// Works because the struct is only handled as a value
struct Person {
char id;
char[64] name;
};
void main() {
struct Person jesper;
jesper.id = 4;
jesper.name = "jesper";
print_person(jesper);
struct Person henriette;
henriette.id = 7;
henriette.name = "repsej";
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

@ -0,0 +1,31 @@
// 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
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

@ -0,0 +1,34 @@
// Example of a struct containing a pointer
struct Person {
char id;
char* name;
};
char* name1 = "jesper";
char* name2 = "repsej";
struct Person[2] persons = {
{ 4, name1 },
{ 7, name2 }
};
void main() {
print_person(&persons[0]);
print_person(&persons[1]);
}
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

@ -0,0 +1,24 @@
// Test a struct array initialized with to few members (zero-filled for the rest)
struct Point {
char x;
int y;
};
struct Point[4] points = { { 1, 2111 }, { 3, 4222 } };
void main() {
for ( char i: 0..3) {
print(points[i]);
}
}
const char* SCREEN = 0x0400;
char idx = 0;
void print(struct Point p) {
SCREEN[idx++] = p.x;
SCREEN[idx++] = <p.y;
SCREEN[idx++] = >p.y;
SCREEN[idx++] = ' ';
}

View File

@ -0,0 +1,34 @@
// Example of a struct containing an array
// Fails with an exception because the initializers do not work properly - and the memory layout is wrong
// https://gitlab.com/camelot/kickc/issues/274
// https://gitlab.com/camelot/kickc/issues/312
struct Person {
char id;
char[16] name;
};
struct Person[] persons = {
{ 4, "jesper" },
{ 7, "henriette" }
};
void main() {
print_person(persons);
print_person(persons+1);
}
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

@ -1042,9 +1042,8 @@ processChars: {
iny
lda (processing),y
sta !+ +2
txa
!:
sta $ffff
stx $ffff
// Enable the sprite
lda SPRITES_ENABLE
ora.z bitmask

View File

@ -7120,9 +7120,8 @@ processChars: {
iny
lda (processing),y
sta !+ +2
txa
!:
sta $ffff
stx $ffff
// [266] *((const byte*) SPRITES_ENABLE#0) ← *((const byte*) SPRITES_ENABLE#0) | (byte) processChars::bitmask#0 -- _deref_pbuc1=_deref_pbuc1_bor_vbuz1
// Enable the sprite
lda SPRITES_ENABLE
@ -8057,142 +8056,142 @@ Uplift Scope [setupRasterIrq]
Uplift Scope [irqTop]
Uplift Scope [irqBottom]
Uplifting [atan2_16] best 1280029 combination reg byte y [ atan2_16::shift#2 atan2_16::shift#5 atan2_16::shift#1 ] zp ZP_WORD:44 [ atan2_16::yd#5 atan2_16::yd#3 atan2_16::yd#10 atan2_16::yd#1 atan2_16::yd#2 ] zp ZP_WORD:46 [ atan2_16::xd#5 atan2_16::xd#3 atan2_16::xd#10 atan2_16::xd#1 atan2_16::xd#2 ] zp ZP_WORD:39 [ atan2_16::angle#6 atan2_16::angle#12 atan2_16::angle#13 atan2_16::angle#2 atan2_16::angle#3 ] zp ZP_WORD:34 [ atan2_16::yi#3 atan2_16::yi#8 atan2_16::yi#0 atan2_16::yi#16 atan2_16::$2 atan2_16::yi#1 atan2_16::yi#2 ] zp ZP_WORD:36 [ atan2_16::xi#3 atan2_16::xi#8 atan2_16::xi#0 atan2_16::xi#13 atan2_16::$7 atan2_16::xi#1 atan2_16::xi#2 ] reg byte a [ atan2_16::$24 ] reg byte a [ atan2_16::$23 ] reg byte x [ atan2_16::i#2 atan2_16::i#1 ] zp ZP_WORD:146 [ atan2_16::return#2 ] zp ZP_WORD:41 [ atan2_16::return#0 atan2_16::angle#5 atan2_16::angle#11 atan2_16::angle#1 atan2_16::angle#4 ] zp ZP_WORD:142 [ atan2_16::x#0 ] zp ZP_WORD:144 [ atan2_16::y#0 ]
Uplifting [atan2_16] best 1280009 combination reg byte y [ atan2_16::shift#2 atan2_16::shift#5 atan2_16::shift#1 ] zp ZP_WORD:44 [ atan2_16::yd#5 atan2_16::yd#3 atan2_16::yd#10 atan2_16::yd#1 atan2_16::yd#2 ] zp ZP_WORD:46 [ atan2_16::xd#5 atan2_16::xd#3 atan2_16::xd#10 atan2_16::xd#1 atan2_16::xd#2 ] zp ZP_WORD:39 [ atan2_16::angle#6 atan2_16::angle#12 atan2_16::angle#13 atan2_16::angle#2 atan2_16::angle#3 ] zp ZP_WORD:34 [ atan2_16::yi#3 atan2_16::yi#8 atan2_16::yi#0 atan2_16::yi#16 atan2_16::$2 atan2_16::yi#1 atan2_16::yi#2 ] zp ZP_WORD:36 [ atan2_16::xi#3 atan2_16::xi#8 atan2_16::xi#0 atan2_16::xi#13 atan2_16::$7 atan2_16::xi#1 atan2_16::xi#2 ] reg byte a [ atan2_16::$24 ] reg byte a [ atan2_16::$23 ] reg byte x [ atan2_16::i#2 atan2_16::i#1 ] zp ZP_WORD:146 [ atan2_16::return#2 ] zp ZP_WORD:41 [ atan2_16::return#0 atan2_16::angle#5 atan2_16::angle#11 atan2_16::angle#1 atan2_16::angle#4 ] zp ZP_WORD:142 [ atan2_16::x#0 ] zp ZP_WORD:144 [ atan2_16::y#0 ]
Limited combination testing to 100 combinations of 144 possible.
Uplifting [getCharToProcess] best 1266696 combination reg byte x [ getCharToProcess::return_dist#1 getCharToProcess::return_dist#5 getCharToProcess::return_dist#6 getCharToProcess::dist#0 ] zp ZP_BYTE:20 [ getCharToProcess::closest_dist#2 getCharToProcess::closest_dist#8 getCharToProcess::closest_dist#10 getCharToProcess::closest_dist#12 ] zp ZP_BYTE:22 [ getCharToProcess::closest_y#7 getCharToProcess::closest_y#9 getCharToProcess::return_y#1 getCharToProcess::return_y#7 ] zp ZP_BYTE:21 [ getCharToProcess::closest_x#7 getCharToProcess::closest_x#9 getCharToProcess::return_x#1 getCharToProcess::return_x#7 ] zp ZP_BYTE:19 [ getCharToProcess::x#2 getCharToProcess::x#1 ] zp ZP_BYTE:18 [ getCharToProcess::y#7 getCharToProcess::y#1 ] zp ZP_WORD:16 [ getCharToProcess::dist_line#6 getCharToProcess::dist_line#0 getCharToProcess::dist_line#1 ] zp ZP_WORD:14 [ getCharToProcess::screen_line#4 getCharToProcess::screen_line#0 getCharToProcess::screen_line#1 ] zp ZP_BYTE:63 [ getCharToProcess::return_x#0 ] zp ZP_BYTE:64 [ getCharToProcess::return_y#0 ] zp ZP_BYTE:65 [ getCharToProcess::return_dist#0 ] zp ZP_WORD:127 [ getCharToProcess::$12 ] zp ZP_WORD:129 [ getCharToProcess::$13 ] zp ZP_WORD:131 [ getCharToProcess::$9 ] zp ZP_WORD:133 [ getCharToProcess::$10 ] zp ZP_WORD:125 [ getCharToProcess::$8 ]
Uplifting [getCharToProcess] best 1266676 combination reg byte x [ getCharToProcess::return_dist#1 getCharToProcess::return_dist#5 getCharToProcess::return_dist#6 getCharToProcess::dist#0 ] zp ZP_BYTE:20 [ getCharToProcess::closest_dist#2 getCharToProcess::closest_dist#8 getCharToProcess::closest_dist#10 getCharToProcess::closest_dist#12 ] zp ZP_BYTE:22 [ getCharToProcess::closest_y#7 getCharToProcess::closest_y#9 getCharToProcess::return_y#1 getCharToProcess::return_y#7 ] zp ZP_BYTE:21 [ getCharToProcess::closest_x#7 getCharToProcess::closest_x#9 getCharToProcess::return_x#1 getCharToProcess::return_x#7 ] zp ZP_BYTE:19 [ getCharToProcess::x#2 getCharToProcess::x#1 ] zp ZP_BYTE:18 [ getCharToProcess::y#7 getCharToProcess::y#1 ] zp ZP_WORD:16 [ getCharToProcess::dist_line#6 getCharToProcess::dist_line#0 getCharToProcess::dist_line#1 ] zp ZP_WORD:14 [ getCharToProcess::screen_line#4 getCharToProcess::screen_line#0 getCharToProcess::screen_line#1 ] zp ZP_BYTE:63 [ getCharToProcess::return_x#0 ] zp ZP_BYTE:64 [ getCharToProcess::return_y#0 ] zp ZP_BYTE:65 [ getCharToProcess::return_dist#0 ] zp ZP_WORD:127 [ getCharToProcess::$12 ] zp ZP_WORD:129 [ getCharToProcess::$13 ] zp ZP_WORD:131 [ getCharToProcess::$9 ] zp ZP_WORD:133 [ getCharToProcess::$10 ] zp ZP_WORD:125 [ getCharToProcess::$8 ]
Limited combination testing to 100 combinations of 46656 possible.
Uplifting [init_angle_screen] best 1265096 combination zp ZP_BYTE:33 [ init_angle_screen::xb#2 init_angle_screen::xb#1 ] reg byte a [ init_angle_screen::$3 ] reg byte a [ init_angle_screen::$4 ] reg byte a [ init_angle_screen::$7 ] zp ZP_WORD:148 [ init_angle_screen::angle_w#0 ] zp ZP_WORD:150 [ init_angle_screen::$11 ] zp ZP_BYTE:153 [ init_angle_screen::$13 ] zp ZP_BYTE:154 [ init_angle_screen::$14 ] zp ZP_BYTE:155 [ init_angle_screen::$15 ] zp ZP_BYTE:32 [ init_angle_screen::x#2 init_angle_screen::x#1 ] zp ZP_BYTE:152 [ init_angle_screen::ang_w#0 ] zp ZP_WORD:140 [ init_angle_screen::yw#0 ] zp ZP_WORD:137 [ init_angle_screen::xw#0 ] zp ZP_BYTE:27 [ init_angle_screen::y#5 init_angle_screen::y#1 ] zp ZP_WORD:30 [ init_angle_screen::screen_bottomline#6 init_angle_screen::screen_bottomline#0 init_angle_screen::screen_bottomline#1 ] zp ZP_WORD:28 [ init_angle_screen::screen_topline#6 init_angle_screen::screen_topline#0 init_angle_screen::screen_topline#1 ] zp ZP_WORD:56 [ init_angle_screen::screen#0 ]
Uplifting [init_angle_screen] best 1265076 combination zp ZP_BYTE:33 [ init_angle_screen::xb#2 init_angle_screen::xb#1 ] reg byte a [ init_angle_screen::$3 ] reg byte a [ init_angle_screen::$4 ] reg byte a [ init_angle_screen::$7 ] zp ZP_WORD:148 [ init_angle_screen::angle_w#0 ] zp ZP_WORD:150 [ init_angle_screen::$11 ] zp ZP_BYTE:153 [ init_angle_screen::$13 ] zp ZP_BYTE:154 [ init_angle_screen::$14 ] zp ZP_BYTE:155 [ init_angle_screen::$15 ] zp ZP_BYTE:32 [ init_angle_screen::x#2 init_angle_screen::x#1 ] zp ZP_BYTE:152 [ init_angle_screen::ang_w#0 ] zp ZP_WORD:140 [ init_angle_screen::yw#0 ] zp ZP_WORD:137 [ init_angle_screen::xw#0 ] zp ZP_BYTE:27 [ init_angle_screen::y#5 init_angle_screen::y#1 ] zp ZP_WORD:30 [ init_angle_screen::screen_bottomline#6 init_angle_screen::screen_bottomline#0 init_angle_screen::screen_bottomline#1 ] zp ZP_WORD:28 [ init_angle_screen::screen_topline#6 init_angle_screen::screen_topline#0 init_angle_screen::screen_topline#1 ] zp ZP_WORD:56 [ init_angle_screen::screen#0 ]
Limited combination testing to 100 combinations of 65536 possible.
Uplifting [main] best 1264856 combination zp ZP_WORD:4 [ main::dst#2 main::dst#0 main::dst#1 ] zp ZP_WORD:2 [ main::src#2 main::src#1 ] reg byte a [ main::$27 ] reg byte a [ main::$28 ] reg byte a [ main::$29 ] reg byte a [ main::$30 ] zp ZP_BYTE:68 [ main::center_dist#0 ] zp ZP_BYTE:6 [ main::i#2 main::i#1 ] zp ZP_BYTE:62 [ main::$17 ] zp ZP_BYTE:66 [ main::center_x#0 ] zp ZP_BYTE:67 [ main::center_y#0 ]
Uplifting [main] best 1264836 combination zp ZP_WORD:4 [ main::dst#2 main::dst#0 main::dst#1 ] zp ZP_WORD:2 [ main::src#2 main::src#1 ] reg byte a [ main::$27 ] reg byte a [ main::$28 ] reg byte a [ main::$29 ] reg byte a [ main::$30 ] zp ZP_BYTE:68 [ main::center_dist#0 ] zp ZP_BYTE:6 [ main::i#2 main::i#1 ] zp ZP_BYTE:62 [ main::$17 ] zp ZP_BYTE:66 [ main::center_x#0 ] zp ZP_BYTE:67 [ main::center_y#0 ]
Limited combination testing to 100 combinations of 147456 possible.
Uplifting [initSprites] best 1264736 combination zp ZP_WORD:24 [ initSprites::sp#2 initSprites::sp#1 ] reg byte x [ initSprites::i#2 initSprites::i#1 ]
Uplifting [] best 1264736 combination zp ZP_WORD:48 [ heap_head#5 heap_head#1 ] zp ZP_WORD:54 [ SCREEN_DIST#0 ] zp ZP_WORD:52 [ SCREEN_COPY#0 ]
Uplifting [malloc] best 1264736 combination zp ZP_WORD:158 [ malloc::mem#0 ]
Uplifting [RADIX] best 1264736 combination
Uplifting [ProcessingChar] best 1264736 combination
Uplifting [ProcessingSprite] best 1264736 combination
Uplifting [ProcessingSprite::$0] best 1264736 combination
Uplifting [setupRasterIrq] best 1264736 combination
Uplifting [irqTop] best 1264736 combination
Uplifting [irqBottom] best 1264736 combination
Uplifting [initSprites] best 1264716 combination zp ZP_WORD:24 [ initSprites::sp#2 initSprites::sp#1 ] reg byte x [ initSprites::i#2 initSprites::i#1 ]
Uplifting [] best 1264716 combination zp ZP_WORD:48 [ heap_head#5 heap_head#1 ] zp ZP_WORD:54 [ SCREEN_DIST#0 ] zp ZP_WORD:52 [ SCREEN_COPY#0 ]
Uplifting [malloc] best 1264716 combination zp ZP_WORD:158 [ malloc::mem#0 ]
Uplifting [RADIX] best 1264716 combination
Uplifting [ProcessingChar] best 1264716 combination
Uplifting [ProcessingSprite] best 1264716 combination
Uplifting [ProcessingSprite::$0] best 1264716 combination
Uplifting [setupRasterIrq] best 1264716 combination
Uplifting [irqTop] best 1264716 combination
Uplifting [irqBottom] best 1264716 combination
Attempting to uplift remaining variables inzp ZP_BYTE:20 [ getCharToProcess::closest_dist#2 getCharToProcess::closest_dist#8 getCharToProcess::closest_dist#10 getCharToProcess::closest_dist#12 ]
Uplifting [getCharToProcess] best 1264736 combination zp ZP_BYTE:20 [ getCharToProcess::closest_dist#2 getCharToProcess::closest_dist#8 getCharToProcess::closest_dist#10 getCharToProcess::closest_dist#12 ]
Uplifting [getCharToProcess] best 1264716 combination zp ZP_BYTE:20 [ getCharToProcess::closest_dist#2 getCharToProcess::closest_dist#8 getCharToProcess::closest_dist#10 getCharToProcess::closest_dist#12 ]
Attempting to uplift remaining variables inzp ZP_BYTE:22 [ getCharToProcess::closest_y#7 getCharToProcess::closest_y#9 getCharToProcess::return_y#1 getCharToProcess::return_y#7 ]
Uplifting [getCharToProcess] best 1264736 combination zp ZP_BYTE:22 [ getCharToProcess::closest_y#7 getCharToProcess::closest_y#9 getCharToProcess::return_y#1 getCharToProcess::return_y#7 ]
Uplifting [getCharToProcess] best 1264716 combination zp ZP_BYTE:22 [ getCharToProcess::closest_y#7 getCharToProcess::closest_y#9 getCharToProcess::return_y#1 getCharToProcess::return_y#7 ]
Attempting to uplift remaining variables inzp ZP_BYTE:8 [ startProcessing::freeIdx#2 startProcessing::freeIdx#8 startProcessing::i#2 startProcessing::i#1 ]
Uplifting [startProcessing] best 1264736 combination zp ZP_BYTE:8 [ startProcessing::freeIdx#2 startProcessing::freeIdx#8 startProcessing::i#2 startProcessing::i#1 ]
Uplifting [startProcessing] best 1264716 combination zp ZP_BYTE:8 [ startProcessing::freeIdx#2 startProcessing::freeIdx#8 startProcessing::i#2 startProcessing::i#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:71 [ startProcessing::$42 ]
Uplifting [startProcessing] best 1258736 combination reg byte a [ startProcessing::$42 ]
Uplifting [startProcessing] best 1258716 combination reg byte a [ startProcessing::$42 ]
Attempting to uplift remaining variables inzp ZP_BYTE:72 [ startProcessing::$43 ]
Uplifting [startProcessing] best 1252736 combination reg byte a [ startProcessing::$43 ]
Uplifting [startProcessing] best 1252716 combination reg byte a [ startProcessing::$43 ]
Attempting to uplift remaining variables inzp ZP_BYTE:73 [ startProcessing::$44 ]
Uplifting [startProcessing] best 1246736 combination reg byte a [ startProcessing::$44 ]
Uplifting [startProcessing] best 1246716 combination reg byte a [ startProcessing::$44 ]
Attempting to uplift remaining variables inzp ZP_BYTE:74 [ startProcessing::$45 ]
Uplifting [startProcessing] best 1240736 combination reg byte a [ startProcessing::$45 ]
Uplifting [startProcessing] best 1240716 combination reg byte a [ startProcessing::$45 ]
Attempting to uplift remaining variables inzp ZP_BYTE:75 [ startProcessing::$30 ]
Uplifting [startProcessing] best 1236736 combination reg byte a [ startProcessing::$30 ]
Uplifting [startProcessing] best 1236716 combination reg byte a [ startProcessing::$30 ]
Attempting to uplift remaining variables inzp ZP_BYTE:21 [ getCharToProcess::closest_x#7 getCharToProcess::closest_x#9 getCharToProcess::return_x#1 getCharToProcess::return_x#7 ]
Uplifting [getCharToProcess] best 1236736 combination zp ZP_BYTE:21 [ getCharToProcess::closest_x#7 getCharToProcess::closest_x#9 getCharToProcess::return_x#1 getCharToProcess::return_x#7 ]
Uplifting [getCharToProcess] best 1236716 combination zp ZP_BYTE:21 [ getCharToProcess::closest_x#7 getCharToProcess::closest_x#9 getCharToProcess::return_x#1 getCharToProcess::return_x#7 ]
Attempting to uplift remaining variables inzp ZP_BYTE:19 [ getCharToProcess::x#2 getCharToProcess::x#1 ]
Uplifting [getCharToProcess] best 1218736 combination reg byte y [ getCharToProcess::x#2 getCharToProcess::x#1 ]
Uplifting [getCharToProcess] best 1218716 combination reg byte y [ getCharToProcess::x#2 getCharToProcess::x#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:7 [ startProcessing::freeIdx#6 startProcessing::freeIdx#7 ]
Uplifting [startProcessing] best 1217836 combination reg byte x [ startProcessing::freeIdx#6 startProcessing::freeIdx#7 ]
Uplifting [startProcessing] best 1217816 combination reg byte x [ startProcessing::freeIdx#6 startProcessing::freeIdx#7 ]
Attempting to uplift remaining variables inzp ZP_BYTE:33 [ init_angle_screen::xb#2 init_angle_screen::xb#1 ]
Uplifting [init_angle_screen] best 1217836 combination zp ZP_BYTE:33 [ init_angle_screen::xb#2 init_angle_screen::xb#1 ]
Uplifting [init_angle_screen] best 1217816 combination zp ZP_BYTE:33 [ init_angle_screen::xb#2 init_angle_screen::xb#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:13 [ startProcessing::i1#2 startProcessing::i1#1 ]
Uplifting [startProcessing] best 1216936 combination reg byte x [ startProcessing::i1#2 startProcessing::i1#1 ]
Uplifting [startProcessing] best 1216916 combination reg byte x [ startProcessing::i1#2 startProcessing::i1#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:153 [ init_angle_screen::$13 ]
Uplifting [init_angle_screen] best 1216336 combination reg byte a [ init_angle_screen::$13 ]
Uplifting [init_angle_screen] best 1216316 combination reg byte a [ init_angle_screen::$13 ]
Attempting to uplift remaining variables inzp ZP_BYTE:154 [ init_angle_screen::$14 ]
Uplifting [init_angle_screen] best 1215936 combination reg byte a [ init_angle_screen::$14 ]
Uplifting [init_angle_screen] best 1215916 combination reg byte a [ init_angle_screen::$14 ]
Attempting to uplift remaining variables inzp ZP_BYTE:155 [ init_angle_screen::$15 ]
Uplifting [init_angle_screen] best 1215336 combination reg byte a [ init_angle_screen::$15 ]
Uplifting [init_angle_screen] best 1215316 combination reg byte a [ init_angle_screen::$15 ]
Attempting to uplift remaining variables inzp ZP_BYTE:18 [ getCharToProcess::y#7 getCharToProcess::y#1 ]
Uplifting [getCharToProcess] best 1215336 combination zp ZP_BYTE:18 [ getCharToProcess::y#7 getCharToProcess::y#1 ]
Uplifting [getCharToProcess] best 1215316 combination zp ZP_BYTE:18 [ getCharToProcess::y#7 getCharToProcess::y#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:32 [ init_angle_screen::x#2 init_angle_screen::x#1 ]
Uplifting [init_angle_screen] best 1215336 combination zp ZP_BYTE:32 [ init_angle_screen::x#2 init_angle_screen::x#1 ]
Uplifting [init_angle_screen] best 1215316 combination zp ZP_BYTE:32 [ init_angle_screen::x#2 init_angle_screen::x#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:152 [ init_angle_screen::ang_w#0 ]
Uplifting [init_angle_screen] best 1215336 combination zp ZP_BYTE:152 [ init_angle_screen::ang_w#0 ]
Uplifting [init_angle_screen] best 1215316 combination zp ZP_BYTE:152 [ init_angle_screen::ang_w#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:51 [ processChars::numActive#10 processChars::numActive#3 processChars::numActive#1 ]
Uplifting [processChars] best 1215336 combination zp ZP_BYTE:51 [ processChars::numActive#10 processChars::numActive#3 processChars::numActive#1 ]
Uplifting [processChars] best 1215316 combination zp ZP_BYTE:51 [ processChars::numActive#10 processChars::numActive#3 processChars::numActive#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:68 [ main::center_dist#0 ]
Uplifting [main] best 1215276 combination reg byte a [ main::center_dist#0 ]
Uplifting [main] best 1215256 combination reg byte a [ main::center_dist#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:160 [ processChars::$67 ]
Uplifting [processChars] best 1215216 combination reg byte a [ processChars::$67 ]
Uplifting [processChars] best 1215196 combination reg byte a [ processChars::$67 ]
Attempting to uplift remaining variables inzp ZP_BYTE:161 [ processChars::$68 ]
Uplifting [processChars] best 1215156 combination reg byte a [ processChars::$68 ]
Uplifting [processChars] best 1215136 combination reg byte a [ processChars::$68 ]
Attempting to uplift remaining variables inzp ZP_BYTE:162 [ processChars::$69 ]
Uplifting [processChars] best 1215096 combination reg byte a [ processChars::$69 ]
Uplifting [processChars] best 1215076 combination reg byte a [ processChars::$69 ]
Attempting to uplift remaining variables inzp ZP_BYTE:163 [ processChars::$70 ]
Uplifting [processChars] best 1215036 combination reg byte a [ processChars::$70 ]
Uplifting [processChars] best 1215016 combination reg byte a [ processChars::$70 ]
Attempting to uplift remaining variables inzp ZP_BYTE:164 [ processChars::$37 ]
Uplifting [processChars] best 1214976 combination reg byte a [ processChars::$37 ]
Uplifting [processChars] best 1214956 combination reg byte a [ processChars::$37 ]
Attempting to uplift remaining variables inzp ZP_BYTE:170 [ processChars::$11 ]
Uplifting [processChars] best 1214916 combination reg byte a [ processChars::$11 ]
Uplifting [processChars] best 1214896 combination reg byte a [ processChars::$11 ]
Attempting to uplift remaining variables inzp ZP_BYTE:171 [ processChars::$12 ]
Uplifting [processChars] best 1214856 combination reg byte a [ processChars::$12 ]
Uplifting [processChars] best 1214836 combination reg byte a [ processChars::$12 ]
Attempting to uplift remaining variables inzp ZP_BYTE:173 [ processChars::$14 ]
Uplifting [processChars] best 1214796 combination reg byte a [ processChars::$14 ]
Uplifting [processChars] best 1214776 combination reg byte a [ processChars::$14 ]
Attempting to uplift remaining variables inzp ZP_BYTE:179 [ processChars::$26 ]
Uplifting [processChars] best 1214756 combination reg byte a [ processChars::$26 ]
Uplifting [processChars] best 1214736 combination reg byte a [ processChars::$26 ]
Attempting to uplift remaining variables inzp ZP_BYTE:180 [ processChars::xchar#0 ]
Uplifting [processChars] best 1214696 combination reg byte a [ processChars::xchar#0 ]
Uplifting [processChars] best 1214676 combination reg byte a [ processChars::xchar#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:181 [ processChars::$38 ]
Uplifting [processChars] best 1214656 combination reg byte a [ processChars::$38 ]
Uplifting [processChars] best 1214636 combination reg byte a [ processChars::$38 ]
Attempting to uplift remaining variables inzp ZP_BYTE:182 [ processChars::$30 ]
Uplifting [processChars] best 1214616 combination reg byte a [ processChars::$30 ]
Uplifting [processChars] best 1214596 combination reg byte a [ processChars::$30 ]
Attempting to uplift remaining variables inzp ZP_BYTE:183 [ processChars::ychar#0 ]
Uplifting [processChars] best 1214556 combination reg byte a [ processChars::ychar#0 ]
Uplifting [processChars] best 1214536 combination reg byte a [ processChars::ychar#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:184 [ processChars::$39 ]
Uplifting [processChars] best 1214516 combination reg byte a [ processChars::$39 ]
Uplifting [processChars] best 1214496 combination reg byte a [ processChars::$39 ]
Attempting to uplift remaining variables inzp ZP_BYTE:185 [ processChars::$33 ]
Uplifting [processChars] best 1214456 combination reg byte a [ processChars::$33 ]
Uplifting [processChars] best 1214436 combination reg byte a [ processChars::$33 ]
Attempting to uplift remaining variables inzp ZP_BYTE:27 [ init_angle_screen::y#5 init_angle_screen::y#1 ]
Uplifting [init_angle_screen] best 1214456 combination zp ZP_BYTE:27 [ init_angle_screen::y#5 init_angle_screen::y#1 ]
Uplifting [init_angle_screen] best 1214436 combination zp ZP_BYTE:27 [ init_angle_screen::y#5 init_angle_screen::y#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:6 [ main::i#2 main::i#1 ]
Uplifting [main] best 1214456 combination zp ZP_BYTE:6 [ main::i#2 main::i#1 ]
Uplifting [main] best 1214436 combination zp ZP_BYTE:6 [ main::i#2 main::i#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:50 [ processChars::i#10 processChars::i#1 ]
Uplifting [processChars] best 1214456 combination zp ZP_BYTE:50 [ processChars::i#10 processChars::i#1 ]
Uplifting [processChars] best 1214436 combination zp ZP_BYTE:50 [ processChars::i#10 processChars::i#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:62 [ main::$17 ]
Uplifting [main] best 1214296 combination reg byte x [ main::$17 ]
Uplifting [main] best 1214276 combination reg byte x [ main::$17 ]
Attempting to uplift remaining variables inzp ZP_BYTE:63 [ getCharToProcess::return_x#0 ]
Uplifting [getCharToProcess] best 1214236 combination reg byte y [ getCharToProcess::return_x#0 ]
Uplifting [getCharToProcess] best 1214216 combination reg byte y [ getCharToProcess::return_x#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:64 [ getCharToProcess::return_y#0 ]
Uplifting [getCharToProcess] best 1214176 combination reg byte a [ getCharToProcess::return_y#0 ]
Uplifting [getCharToProcess] best 1214156 combination reg byte a [ getCharToProcess::return_y#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:65 [ getCharToProcess::return_dist#0 ]
Uplifting [getCharToProcess] best 1214136 combination reg byte x [ getCharToProcess::return_dist#0 ]
Uplifting [getCharToProcess] best 1214116 combination reg byte x [ getCharToProcess::return_dist#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:172 [ processChars::$17 ]
Uplifting [processChars] best 1214066 combination reg byte x [ processChars::$17 ]
Uplifting [processChars] best 1214046 combination reg byte x [ processChars::$17 ]
Attempting to uplift remaining variables inzp ZP_BYTE:66 [ main::center_x#0 ]
Uplifting [main] best 1214006 combination reg byte y [ main::center_x#0 ]
Uplifting [main] best 1213986 combination reg byte y [ main::center_x#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:67 [ main::center_y#0 ]
Uplifting [main] best 1214006 combination zp ZP_BYTE:67 [ main::center_y#0 ]
Uplifting [main] best 1213986 combination zp ZP_BYTE:67 [ main::center_y#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:120 [ startProcessing::$50 ]
Uplifting [startProcessing] best 1214000 combination reg byte a [ startProcessing::$50 ]
Uplifting [startProcessing] best 1213980 combination reg byte a [ startProcessing::$50 ]
Attempting to uplift remaining variables inzp ZP_BYTE:121 [ startProcessing::$51 ]
Uplifting [startProcessing] best 1213994 combination reg byte a [ startProcessing::$51 ]
Uplifting [startProcessing] best 1213974 combination reg byte a [ startProcessing::$51 ]
Attempting to uplift remaining variables inzp ZP_BYTE:122 [ startProcessing::$52 ]
Uplifting [startProcessing] best 1213988 combination reg byte a [ startProcessing::$52 ]
Uplifting [startProcessing] best 1213968 combination reg byte a [ startProcessing::$52 ]
Attempting to uplift remaining variables inzp ZP_BYTE:123 [ startProcessing::$53 ]
Uplifting [startProcessing] best 1213982 combination reg byte a [ startProcessing::$53 ]
Uplifting [startProcessing] best 1213962 combination reg byte a [ startProcessing::$53 ]
Attempting to uplift remaining variables inzp ZP_BYTE:176 [ processChars::ypos#0 ]
Uplifting [processChars] best 1213982 combination zp ZP_BYTE:176 [ processChars::ypos#0 ]
Uplifting [processChars] best 1213962 combination zp ZP_BYTE:176 [ processChars::ypos#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:124 [ startProcessing::$31 ]
Uplifting [startProcessing] best 1213957 combination reg byte x [ startProcessing::$31 ]
Uplifting [startProcessing] best 1213937 combination reg byte x [ startProcessing::$31 ]
Attempting to uplift remaining variables inzp ZP_BYTE:167 [ processChars::bitmask#0 ]
Uplifting [processChars] best 1213957 combination zp ZP_BYTE:167 [ processChars::bitmask#0 ]
Uplifting [processChars] best 1213937 combination zp ZP_BYTE:167 [ processChars::bitmask#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:95 [ startProcessing::ch#0 ]
Uplifting [startProcessing] best 1213951 combination reg byte a [ startProcessing::ch#0 ]
Uplifting [startProcessing] best 1213931 combination reg byte a [ startProcessing::ch#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:117 [ startProcessing::$22 ]
Uplifting [startProcessing] best 1213945 combination reg byte a [ startProcessing::$22 ]
Uplifting [startProcessing] best 1213925 combination reg byte a [ startProcessing::$22 ]
Attempting to uplift remaining variables inzp ZP_BYTE:69 [ startProcessing::center_x#0 ]
Uplifting [startProcessing] best 1213945 combination zp ZP_BYTE:69 [ startProcessing::center_x#0 ]
Uplifting [startProcessing] best 1213925 combination zp ZP_BYTE:69 [ startProcessing::center_x#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:116 [ startProcessing::spritePtr#0 ]
Uplifting [startProcessing] best 1213945 combination zp ZP_BYTE:116 [ startProcessing::spritePtr#0 ]
Uplifting [startProcessing] best 1213925 combination zp ZP_BYTE:116 [ startProcessing::spritePtr#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:70 [ startProcessing::center_y#0 ]
Uplifting [startProcessing] best 1213945 combination zp ZP_BYTE:70 [ startProcessing::center_y#0 ]
Uplifting [startProcessing] best 1213925 combination zp ZP_BYTE:70 [ startProcessing::center_y#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:88 [ startProcessing::spriteCol#0 ]
Uplifting [startProcessing] best 1213945 combination zp ZP_BYTE:88 [ startProcessing::spriteCol#0 ]
Uplifting [startProcessing] best 1213925 combination zp ZP_BYTE:88 [ startProcessing::spriteCol#0 ]
Coalescing zero page register [ zp ZP_WORD:9 [ startProcessing::chargenData#2 startProcessing::chargenData#0 startProcessing::chargenData#1 ] ] with [ zp ZP_WORD:98 [ startProcessing::$9 ] ] - score: 1
Coalescing zero page register [ zp ZP_WORD:11 [ startProcessing::spriteData#2 startProcessing::spriteData#0 startProcessing::spriteData#1 ] ] with [ zp ZP_WORD:93 [ startProcessing::$6 ] ] - score: 1
Coalescing zero page register [ zp ZP_WORD:30 [ init_angle_screen::screen_bottomline#6 init_angle_screen::screen_bottomline#0 init_angle_screen::screen_bottomline#1 ] ] with [ zp ZP_WORD:56 [ init_angle_screen::screen#0 ] ] - score: 1
@ -9953,9 +9952,8 @@ processChars: {
iny
lda (processing),y
sta !+ +2
txa
!:
sta $ffff
stx $ffff
// [266] *((const byte*) SPRITES_ENABLE#0) ← *((const byte*) SPRITES_ENABLE#0) | (byte) processChars::bitmask#0 -- _deref_pbuc1=_deref_pbuc1_bor_vbuz1
// Enable the sprite
lda SPRITES_ENABLE
@ -10542,21 +10540,21 @@ Removing instruction ldy #OFFSET_STRUCT_PROCESSINGSPRITE_STATUS
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Fixing long branch [458] bne b2 to beq
Fixing long branch [873] beq b12 to bne
Fixing long branch [1217] bne b1 to beq
Fixing long branch [1216] bne b1 to beq
Fixing long branch [234] bne b3 to beq
Fixing long branch [240] beq b8 to bne
Fixing long branch [503] beq b11 to bne
Fixing long branch [773] bpl b1 to bmi
Fixing long branch [785] bpl b4 to bmi
Fixing long branch [1030] beq b2 to bne
Fixing long branch [1091] bne b4 to beq
Fixing long branch [1125] bcc b6 to bcs
Fixing long branch [1132] bcc b6 to bcs
Fixing long branch [1139] bcc b6 to bcs
Fixing long branch [1146] bcc b6 to bcs
Fixing long branch [1154] bcc b6 to bcs
Fixing long branch [1161] bcc b6 to bcs
Fixing long branch [1169] bcc b6 to bcs
Fixing long branch [1090] bne b4 to beq
Fixing long branch [1124] bcc b6 to bcs
Fixing long branch [1131] bcc b6 to bcs
Fixing long branch [1138] bcc b6 to bcs
Fixing long branch [1145] bcc b6 to bcs
Fixing long branch [1153] bcc b6 to bcs
Fixing long branch [1160] bcc b6 to bcs
Fixing long branch [1168] bcc b6 to bcs
FINAL SYMBOL TABLE
(label) @1
@ -11159,7 +11157,7 @@ reg byte a [ processChars::$33 ]
FINAL ASSEMBLER
Score: 1113942
Score: 1113922
// File Comments
// Clears start screen throwing around the letters (by turning them into sprites)
@ -12813,9 +12811,8 @@ processChars: {
iny
lda (processing),y
sta !+ +2
txa
!:
sta $ffff
stx $ffff
// *SPRITES_ENABLE |= bitmask
// [266] *((const byte*) SPRITES_ENABLE#0) ← *((const byte*) SPRITES_ENABLE#0) | (byte) processChars::bitmask#0 -- _deref_pbuc1=_deref_pbuc1_bor_vbuz1
// Enable the sprite

View File

@ -0,0 +1,61 @@
// Example of a struct containing an array
// Works because the struct is only handled as a value
.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 57, 0
henriette_name: .text "repsej"
.byte 0
.fill 57, 0
}
// print_person(byte register(X) person_id, byte[$40] 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[$40]) print_person::person_name#4 ← phi( main/(const byte[$40]) main::jesper_name#1 main::@1/(const byte[$40]) main::henriette_name#1 )
[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#1 main::@1/(const byte) main::henriette_id#1 )
[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[$40]) 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[$40]) 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

927
src/test/ref/struct-12.log Normal file
View File

@ -0,0 +1,927 @@
Created struct value member variable (byte) main::jesper_id
Created struct value member variable (byte[$40]) 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[$40]) 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[$40]) 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[$40]) print_person::person_name)
Adding struct value member variable default initializer (byte) main::jesper_id ← (byte) 0
Adding struct value member variable default initializer (byte[$40]) main::jesper_name ← { fill( $40, 0) }
Converted procedure struct value parameter to member unwinding in call (void~) main::$0 ← call print_person (byte) main::jesper_id (byte[$40]) main::jesper_name
Adding struct value member variable default initializer (byte) main::henriette_id ← (byte) 0
Adding struct value member variable default initializer (byte[$40]) main::henriette_name ← { fill( $40, 0) }
Converted procedure struct value parameter to member unwinding in call (void~) main::$1 ← call print_person (byte) main::henriette_id (byte[$40]) main::henriette_name
Replacing struct member reference (struct Person) main::jesper.id with member unwinding reference (byte) main::jesper_id
Replacing struct member reference (struct Person) main::jesper.name with member unwinding reference (byte[$40]) main::jesper_name
Replacing struct member reference (struct Person) main::henriette.id with member unwinding reference (byte) main::henriette_id
Replacing struct member reference (struct Person) main::henriette.name with member unwinding reference (byte[$40]) 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[$40]) print_person::person_name
Replacing struct member reference (struct Person) print_person::person.name with member unwinding reference (byte[$40]) print_person::person_name
Warning! Adding boolean cast to non-boolean condition *((byte[$40]) print_person::person_name + (byte) print_person::i)
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 ← (byte) 0
(byte[$40]) main::jesper_name#0 ← { fill( $40, 0) }
(byte) main::jesper_id#1 ← (number) 4
(byte[$40]) main::jesper_name#1 ← (const string) main::$2
(byte) print_person::person_id#0 ← (byte) main::jesper_id#1
(byte[$40]) print_person::person_name#0 ← (byte[$40]) main::jesper_name#1
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 ← (byte) 0
(byte[$40]) main::henriette_name#0 ← { fill( $40, 0) }
(byte) main::henriette_id#1 ← (number) 7
(byte[$40]) main::henriette_name#1 ← (const string) main::$3
(byte) print_person::person_id#1 ← (byte) main::henriette_id#1
(byte[$40]) print_person::person_name#1 ← (byte[$40]) main::henriette_name#1
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[$40]) print_person::person_name#4 ← phi( main/(byte[$40]) print_person::person_name#0 main::@1/(byte[$40]) 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[$40]) print_person::person_name#2 ← phi( print_person/(byte[$40]) print_person::person_name#4 print_person::@2/(byte[$40]) print_person::person_name#3 )
(bool~) print_person::$0 ← (number) 0 != *((byte[$40]) 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[$40]) print_person::person_name#3 ← phi( print_person::@1/(byte[$40]) print_person::person_name#2 )
*((byte*) SCREEN#0 + (byte) idx#14) ← *((byte[$40]) 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[$40]) 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) "repsej"
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::henriette_id
(byte) main::henriette_id#0
(byte) main::henriette_id#1
(byte[$40]) main::henriette_name
(byte[$40]) main::henriette_name#0
(byte[$40]) main::henriette_name#1
(byte) main::jesper_id
(byte) main::jesper_id#0
(byte) main::jesper_id#1
(byte[$40]) main::jesper_name
(byte[$40]) main::jesper_name#0
(byte[$40]) main::jesper_name#1
(void()) print_person((byte) print_person::person_id , (byte[$40]) 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[$40]) print_person::person_name
(byte[$40]) print_person::person_name#0
(byte[$40]) print_person::person_name#1
(byte[$40]) print_person::person_name#2
(byte[$40]) print_person::person_name#3
(byte[$40]) print_person::person_name#4
Adding number conversion cast (unumber) 4 in (byte) main::jesper_id#1 ← (number) 4
Adding number conversion cast (unumber) 7 in (byte) main::henriette_id#1 ← (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[$40]) print_person::person_name#2 + (byte) print_person::i#2)
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte) main::jesper_id#1 ← (unumber)(number) 4
Inlining cast (byte) main::henriette_id#1 ← (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[$40]) print_person::person_name#2 = (byte[$40]) 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[$40]) print_person::person_name#2 (byte[$40]) print_person::person_name#4
Identical Phi Values (byte) idx#17 (byte) idx#1
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) print_person::$0 [33] if((byte) 0!=*((byte[$40]) print_person::person_name#4 + (byte) print_person::i#2)) goto print_person::@2
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [2] (byte[$40]) main::jesper_name#0 ← { fill( $40, 0) }
Constant right-side identified [11] (byte[$40]) main::henriette_name#0 ← { fill( $40, 0) }
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::jesper_id#0 = 0
Constant (const byte[$40]) main::jesper_name#0 = { fill( $40, 0) }
Constant (const byte) main::jesper_id#1 = 4
Constant (const byte[$40]) main::jesper_name#1 = main::$2
Constant (const byte) main::henriette_id#0 = 0
Constant (const byte[$40]) main::henriette_name#0 = { fill( $40, 0) }
Constant (const byte) main::henriette_id#1 = 7
Constant (const byte[$40]) main::henriette_name#1 = 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#1
Constant (const byte[$40]) print_person::person_name#0 = main::jesper_name#1
Constant (const byte) print_person::person_id#1 = main::henriette_id#1
Constant (const byte[$40]) print_person::person_name#1 = main::henriette_name#1
Successful SSA optimization Pass2ConstantIdentification
Eliminating unused constant (const byte) main::jesper_id#0
Eliminating unused constant (const byte[$40]) main::jesper_name#0
Eliminating unused constant (const byte) main::henriette_id#0
Eliminating unused constant (const byte[$40]) main::henriette_name#0
Successful SSA optimization PassNEliminateUnusedVars
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[$40]) print_person::person_name#0
Inlining constant with var siblings (const byte) print_person::person_id#1
Inlining constant with var siblings (const byte[$40]) 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#1
Constant inlined print_person::person_id#0 = (const byte) main::jesper_id#1
Constant inlined main::$2 = (const byte[$40]) main::jesper_name#1
Constant inlined print_person::i#0 = (byte) 0
Constant inlined print_person::person_name#1 = (const byte[$40]) main::henriette_name#1
Constant inlined main::$3 = (const byte[$40]) main::henriette_name#1
Constant inlined $0 = (const byte[]) DIGIT#0
Constant inlined print_person::person_name#0 = (const byte[$40]) main::jesper_name#1
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[$40]) print_person::person_name#4 ← phi( main/(const byte[$40]) main::jesper_name#1 main::@1/(const byte[$40]) main::henriette_name#1 )
[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#1 main::@1/(const byte) main::henriette_id#1 )
[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[$40]) 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[$40]) 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[$40]) 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[$40]) main::henriette_name
(byte) main::jesper_id
(byte[$40]) main::jesper_name
(void()) print_person((byte) print_person::person_id , (byte[$40]) 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[$40]) print_person::person_name
(byte[$40]) 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
// Works because the struct is only handled as a value
// 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[$40]) print_person::person_name#4 = (const byte[$40]) main::jesper_name#1 [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#1 [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[$40]) print_person::person_name#4 = (const byte[$40]) main::henriette_name#1 [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#1 [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 57, 0
henriette_name: .text "repsej"
.byte 0
.fill 57, 0
}
// print_person
// print_person(byte zeropage(2) person_id, byte[$40] 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[$40]) 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[$40]) 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[$40]) 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[$40]) 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[$40]) 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[$40]) 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
// Works because the struct is only handled as a value
// 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[$40]) print_person::person_name#4 = (const byte[$40]) main::jesper_name#1 [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#1 [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[$40]) print_person::person_name#4 = (const byte[$40]) main::henriette_name#1 [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#1 [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 57, 0
henriette_name: .text "repsej"
.byte 0
.fill 57, 0
}
// print_person
// print_person(byte register(X) person_id, byte[$40] 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[$40]) 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[$40]) 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[$40]) 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#1 henriette_id = (byte) 7
(byte[$40]) main::henriette_name
(const byte[$40]) main::henriette_name#1 henriette_name = (string) "repsej"
(byte) main::jesper_id
(const byte) main::jesper_id#1 jesper_id = (byte) 4
(byte[$40]) main::jesper_name
(const byte[$40]) main::jesper_name#1 jesper_name = (string) "jesper"
(void()) print_person((byte) print_person::person_id , (byte[$40]) 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[$40]) print_person::person_name
(byte[$40]) 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
// Works because the struct is only handled as a value
// 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[$40]) print_person::person_name#4 = (const byte[$40]) main::jesper_name#1 [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#1 [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[$40]) print_person::person_name#4 = (const byte[$40]) main::henriette_name#1 [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#1 [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 57, 0
henriette_name: .text "repsej"
.byte 0
.fill 57, 0
}
// print_person
// print_person(byte register(X) person_id, byte[$40] 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[$40]) 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[$40]) 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[$40]) 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#1 henriette_id = (byte) 7
(byte[$40]) main::henriette_name
(const byte[$40]) main::henriette_name#1 henriette_name = (string) "repsej"
(byte) main::jesper_id
(const byte) main::jesper_id#1 jesper_id = (byte) 4
(byte[$40]) main::jesper_name
(const byte[$40]) main::jesper_name#1 jesper_name = (string) "jesper"
(void()) print_person((byte) print_person::person_id , (byte[$40]) 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[$40]) print_person::person_name
(byte[$40]) 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 ]

View File

@ -0,0 +1,88 @@
// 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"
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
main: {
.label jesper_id = 5
.label jesper_name = 6
.label henriette_id = 8
.label henriette_name = 9
lda #4
sta.z jesper_id
lda #<_4
sta.z jesper_name
lda #>_4
sta.z jesper_name+1
ldx #0
lda #<jesper_id
sta.z print_person.person
lda #>jesper_id
sta.z print_person.person+1
jsr print_person
lda #7
sta.z henriette_id
lda #<_5
sta.z henriette_name
lda #>_5
sta.z henriette_name+1
lda #<henriette_id
sta.z print_person.person
lda #>henriette_id
sta.z print_person.person+1
jsr print_person
rts
_4: .text "jesper"
.byte 0
_5: .text "henriette"
.byte 0
}
// print_person(struct Person* zeropage(2) person)
print_person: {
.label i = 4
.label person = 2
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
inx
lda #' '
sta SCREEN,x
inx
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
lda #' '
sta SCREEN,x
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
}
DIGIT: .text "0123456789"
.byte 0

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,76 @@
// Example of a struct containing a pointer
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_PERSON = 3
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
main: {
ldx #0
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
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: {
.label i = 4
.label person = 2
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
inx
lda #' '
sta SCREEN,x
inx
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
lda #' '
sta SCREEN,x
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
}
name1: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
.word name1
.byte 7
.word name2

View File

@ -0,0 +1,45 @@
@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) 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#0 main::@1/(const struct Person[2]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON )
[10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#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**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (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**)(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
to:print_person::@1

View File

@ -0,0 +1,959 @@
Fixing pointer array-indexing *((struct Person[2]) persons + (number) 0)
Fixing pointer array-indexing *((struct Person[2]) persons + (number) 1)
Rewriting struct pointer member access *((struct Person*) print_person::person).id
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 } }
to:@1
main: scope:[main] from @2
(byte) idx#18 ← phi( @2/(byte) idx#20 )
(number~) main::$4 ← (number) 0 * (const byte) SIZEOF_STRUCT_PERSON
(struct Person*~) main::$0 ← & *((struct Person[2]) persons#0 + (number~) main::$4)
(struct Person*) print_person::person#0 ← (struct Person*~) main::$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
(number~) main::$5 ← (number) 1 * (const byte) SIZEOF_STRUCT_PERSON
(struct Person*~) main::$2 ← & *((struct Person[2]) persons#0 + (number~) main::$5)
(struct Person*) print_person::person#1 ← (struct Person*~) main::$2
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) $2
to:@2
print_person: scope:[print_person] from main main::@1
(byte) idx#13 ← phi( main/(byte) idx#18 main::@1/(byte) idx#0 )
(struct Person*) print_person::person#2 ← phi( main/(struct Person*) print_person::person#0 main::@1/(struct Person*) print_person::person#1 )
(byte*) print_person::$0 ← (byte*)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_ID
*((byte*) SCREEN#0 + (byte) idx#13) ← *((byte[]) DIGIT#0 + *((byte*) print_person::$0))
(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 )
(struct Person*) print_person::person#3 ← phi( print_person/(struct Person*) print_person::person#2 print_person::@2/(struct Person*) print_person::person#4 )
(byte**) print_person::$1 ← (byte**)(struct Person*) print_person::person#3 + (const byte) OFFSET_STRUCT_PERSON_NAME
(bool~) print_person::$3 ← (number) 0 != *(*((byte**) print_person::$1) + (byte) print_person::i#2)
if((bool~) print_person::$3) 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 )
(struct Person*) print_person::person#4 ← phi( print_person::@1/(struct Person*) print_person::person#3 )
(byte**) print_person::$2 ← (byte**)(struct Person*) print_person::person#4 + (const byte) OFFSET_STRUCT_PERSON_NAME
*((byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte**) print_person::$2) + (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) "jesper"
(const string) $1 = (string) "repsej"
(const string) $2 = (string) "0123456789"
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(byte[]) DIGIT
(byte[]) DIGIT#0
(const byte) OFFSET_STRUCT_PERSON_ID = (byte) 0
(const byte) OFFSET_STRUCT_PERSON_NAME = (byte) 1
(byte) Person::id
(byte*) Person::name
(byte*) SCREEN
(byte*) SCREEN#0
(const byte) SIZEOF_STRUCT_PERSON = (byte) 3
(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()
(struct Person*~) main::$0
(struct Person*~) main::$2
(number~) main::$4
(number~) main::$5
(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)
(byte*) print_person::$0
(byte**) print_person::$1
(byte**) print_person::$2
(bool~) print_person::$3
(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
(struct Person*) print_person::person#0
(struct Person*) print_person::person#1
(struct Person*) print_person::person#2
(struct Person*) print_person::person#3
(struct Person*) print_person::person#4
Adding number conversion cast (unumber) 0 in (number~) main::$4 ← (number) 0 * (const byte) SIZEOF_STRUCT_PERSON
Adding number conversion cast (unumber) main::$4 in (number~) main::$4 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_PERSON
Adding number conversion cast (unumber) 1 in (number~) main::$5 ← (number) 1 * (const byte) SIZEOF_STRUCT_PERSON
Adding number conversion cast (unumber) main::$5 in (number~) main::$5 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_PERSON
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 } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
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 integer cast 0
Simplifying constant integer cast 1
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) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$4 ← (byte) 0 * (const byte) SIZEOF_STRUCT_PERSON
Inferred type updated to byte in (unumber~) main::$5 ← (byte) 1 * (const byte) SIZEOF_STRUCT_PERSON
Alias (struct Person*) print_person::person#0 = (struct Person*~) main::$0
Alias (byte) idx#0 = (byte) idx#10
Alias (struct Person*) print_person::person#1 = (struct Person*~) main::$2
Alias (byte) idx#1 = (byte) idx#11 (byte) idx#12 (byte) idx#2
Alias (struct Person*) print_person::person#3 = (struct Person*) print_person::person#4
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 (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
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
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
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) name1#0 = $0
Constant (const byte*) name2#0 = $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
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)
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))
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 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
Successful SSA optimization Pass2ConstantRValueConsolidation
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 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 $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
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 4 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 4 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) 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#0 main::@1/(const struct Person[2]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON )
[10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#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**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (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**)(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
to:print_person::@1
VARIABLE REGISTER WEIGHTS
(byte[]) DIGIT
(byte) Person::id
(byte*) 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*) name1
(byte*) name2
(struct Person[2]) persons
(void()) print_person((struct Person*) print_person::person)
(byte) print_person::i
(byte) print_person::i#1 22.0
(byte) print_person::i#2 11.0
(struct Person*) print_person::person
(struct Person*) print_person::person#2
Initial phi equivalence classes
[ print_person::person#2 ]
[ idx#13 idx#16 ]
[ 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#2 ]
[ idx#13 idx#16 ]
[ print_person::i#2 print_person::i#1 ]
[ idx#14 idx#5 idx#6 ]
[ idx#4 ]
Allocated zp ZP_WORD:2 [ print_person::person#2 ]
Allocated zp ZP_BYTE:4 [ idx#13 idx#16 ]
Allocated zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ]
Allocated zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ]
Allocated zp ZP_BYTE:7 [ idx#4 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Example of a struct containing a pointer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = 3
.const OFFSET_STRUCT_PERSON_NAME = 1
.label SCREEN = $400
.label idx = 7
.label idx_5 = 6
.label idx_6 = 6
.label idx_13 = 4
.label idx_14 = 6
.label idx_16 = 4
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuz1=vbuc1
lda #0
sta.z idx_13
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[2]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
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) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[2]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON [phi:main::@1->print_person#1] -- pssz1=pssc1
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
jmp breturn
// main::@return
breturn:
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label i = 5
.label person = 2
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_(_deref_pbuz2)
ldx.z idx_13
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
// [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**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2)) goto print_person::@2 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1
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
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**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuz1=(pptz2_derefidx_vbuc2)_derefidx_vbuz3
ldx.z idx_14
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
// [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
name1: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
.word name1
.byte 7
.word name2
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
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ idx#13 idx#16 ]
Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:5 [ print_person::person#2 idx#4 ] main:2::print_person:7 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ idx#4 ]
Statement [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 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:6 [ 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**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y
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
Statement [12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte) ' ' [ print_person::person#2 idx#4 ] ( main:2::print_person:5 [ print_person::person#2 idx#4 ] main:2::print_person:7 [ print_person::person#2 idx#4 ] ) always clobbers reg byte a
Statement [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 [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y
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**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) [ print_person::person#2 print_person::i#2 idx#14 ] ( main:2::print_person:5 [ print_person::person#2 print_person::i#2 idx#14 ] main:2::print_person:7 [ print_person::person#2 print_person::i#2 idx#14 ] ) always clobbers reg byte a reg byte y
Potential registers zp ZP_WORD:2 [ print_person::person#2 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_BYTE:4 [ idx#13 idx#16 ] : zp ZP_BYTE:4 , reg byte x ,
Potential registers zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] : zp ZP_BYTE:5 , reg byte x ,
Potential registers zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] : zp ZP_BYTE:6 , reg byte x ,
Potential registers zp ZP_BYTE:7 [ idx#4 ] : zp ZP_BYTE:7 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [print_person] 33: zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] 0: zp ZP_WORD:2 [ print_person::person#2 ]
Uplift Scope [] 24.75: zp ZP_BYTE:6 [ idx#14 idx#5 idx#6 ] 4: zp ZP_BYTE:4 [ idx#13 idx#16 ] 3: zp ZP_BYTE:7 [ idx#4 ]
Uplift Scope [Person]
Uplift Scope [main]
Uplifting [print_person] best 1091 combination zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ] zp ZP_WORD:2 [ print_person::person#2 ]
Uplifting [] best 1001 combination reg byte x [ idx#14 idx#5 idx#6 ] reg byte x [ idx#13 idx#16 ] reg byte x [ idx#4 ]
Uplifting [Person] best 1001 combination
Uplifting [main] best 1001 combination
Attempting to uplift remaining variables inzp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ]
Uplifting [print_person] best 1001 combination zp ZP_BYTE:5 [ print_person::i#2 print_person::i#1 ]
Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:4 [ print_person::i#2 print_person::i#1 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Example of a struct containing a pointer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = 3
.const OFFSET_STRUCT_PERSON_NAME = 1
.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: {
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
print_person_from_main:
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1
ldx #0
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[2]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
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) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[2]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON [phi:main::@1->print_person#1] -- pssz1=pssc1
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
jmp breturn
// main::@return
breturn:
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label i = 4
.label person = 2
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1)
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx
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] -- vbuz1=vbuc1
lda #0
sta.z i
jmp b1
// print_person::@1
b1:
// [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 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1
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
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 -- vbuxx=_inc_vbuxx
inx
jmp breturn
// print_person::@return
breturn:
// [18] return
rts
// print_person::@2
b2:
// [19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=(pptz1_derefidx_vbuc2)_derefidx_vbuz2
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
// [20] (byte) idx#6 ← ++ (byte) idx#14 -- vbuxx=_inc_vbuxx
inx
// [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
name1: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
.word name1
.byte 7
.word name2
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"
(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1
(byte) Person::id
(byte*) Person::name
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_PERSON 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
(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 } }
(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 ZP_BYTE:4 22.0
(byte) print_person::i#2 i zp ZP_BYTE:4 11.0
(struct Person*) print_person::person
(struct Person*) print_person::person#2 person zp ZP_WORD:2
zp ZP_WORD:2 [ print_person::person#2 ]
reg byte x [ idx#13 idx#16 ]
zp ZP_BYTE:4 [ 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: 920
// File Comments
// Example of a struct containing a pointer
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const SIZEOF_STRUCT_PERSON = 3
.const OFFSET_STRUCT_PERSON_NAME = 1
.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: {
// print_person(&persons[0])
// [5] call print_person
// [9] phi from main to print_person [phi:main->print_person]
// [9] phi (byte) idx#13 = (byte) 0 [phi:main->print_person#0] -- vbuxx=vbuc1
ldx #0
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[2]) persons#0 [phi:main->print_person#1] -- pssz1=pssc1
lda #<persons
sta.z print_person.person
lda #>persons
sta.z print_person.person+1
jsr print_person
// [6] phi from main to main::@1 [phi:main->main::@1]
// main::@1
// print_person(&persons[1])
// [7] call print_person
// [9] phi from main::@1 to print_person [phi:main::@1->print_person]
// [9] phi (byte) idx#13 = (byte) idx#16 [phi:main::@1->print_person#0] -- register_copy
// [9] phi (struct Person*) print_person::person#2 = (const struct Person[2]) persons#0+(byte) 1*(const byte) SIZEOF_STRUCT_PERSON [phi:main::@1->print_person#1] -- pssz1=pssc1
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
// main::@return
// }
// [8] return
rts
}
// print_person
// print_person(struct Person* zeropage(2) person)
print_person: {
.label i = 4
.label person = 2
// SCREEN[idx++] = DIGIT[person->id]
// [10] *((const byte*) SCREEN#0 + (byte) idx#13) ← *((const byte[]) DIGIT#0 + *((byte*)(struct Person*) print_person::person#2)) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_(_deref_pbuz1)
ldy #0
lda (person),y
tay
lda DIGIT,y
sta SCREEN,x
// SCREEN[idx++] = DIGIT[person->id];
// [11] (byte) idx#4 ← ++ (byte) idx#13 -- vbuxx=_inc_vbuxx
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] -- vbuz1=vbuc1
lda #0
sta.z i
// print_person::@1
b1:
// for(byte i=0; person->name[i]; i++)
// [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 -- vbuc1_neq_(pptz1_derefidx_vbuc2)_derefidx_vbuz2_then_la1
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
// 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 -- vbuxx=_inc_vbuxx
inx
// print_person::@return
// }
// [18] return
rts
// print_person::@2
b2:
// SCREEN[idx++] = person->name[i]
// [19] *((const byte*) SCREEN#0 + (byte) idx#14) ← *(*((byte**)(struct Person*) print_person::person#2 + (const byte) OFFSET_STRUCT_PERSON_NAME) + (byte) print_person::i#2) -- pbuc1_derefidx_vbuxx=(pptz1_derefidx_vbuc2)_derefidx_vbuz2
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
// 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 -- vbuz1=_inc_vbuz1
inc.z i
// [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
name1: .text "jesper"
.byte 0
name2: .text "repsej"
.byte 0
DIGIT: .text "0123456789"
.byte 0
persons:
.byte 4
.word name1
.byte 7
.word name2

View File

@ -0,0 +1,43 @@
(label) @1
(label) @begin
(label) @end
(byte[]) DIGIT
(const byte[]) DIGIT#0 DIGIT = (string) "0123456789"
(const byte) OFFSET_STRUCT_PERSON_NAME OFFSET_STRUCT_PERSON_NAME = (byte) 1
(byte) Person::id
(byte*) Person::name
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(const byte) SIZEOF_STRUCT_PERSON 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
(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 } }
(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 ZP_BYTE:4 22.0
(byte) print_person::i#2 i zp ZP_BYTE:4 11.0
(struct Person*) print_person::person
(struct Person*) print_person::person#2 person zp ZP_WORD:2
zp ZP_WORD:2 [ print_person::person#2 ]
reg byte x [ idx#13 idx#16 ]
zp ZP_BYTE:4 [ print_person::i#2 print_person::i#1 ]
reg byte x [ idx#14 idx#5 idx#6 ]
reg byte x [ idx#4 ]

View File

@ -0,0 +1,59 @@
// Test a struct array initialized with to few members (zero-filled for the rest)
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const OFFSET_STRUCT_POINT_Y = 1
.label SCREEN = $400
.label idx = 2
main: {
lda #0
sta.z idx
tax
b1:
txa
asl
stx.z $ff
clc
adc.z $ff
tay
lda points,y
sta.z print.p_x
lda points+OFFSET_STRUCT_POINT_Y,y
sta.z print.p_y
lda points+OFFSET_STRUCT_POINT_Y+1,y
sta.z print.p_y+1
jsr print
inx
cpx #4
bne b1
rts
}
// print(byte zeropage(3) p_x, signed word zeropage(4) p_y)
print: {
.label p_x = 3
.label p_y = 4
lda.z p_x
ldy.z idx
sta SCREEN,y
iny
lda.z p_y
sta SCREEN,y
iny
lda.z p_y+1
sta SCREEN,y
iny
lda #' '
sta SCREEN,y
iny
sty.z idx
rts
}
points:
.byte 1
.word $83f
.byte 3
.word $107e
.byte 0
.word 0
.byte 0
.word 0

View File

@ -0,0 +1,43 @@
@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()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) idx#14 ← phi( main/(byte) 0 main::@2/(byte) idx#12 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] (byte) main::$5 ← (byte) main::i#2 << (byte) 1
[7] (byte~) main::$2 ← (byte) main::$5 + (byte) main::i#2
[8] (byte) print::p_x#0 ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$2)
[9] (signed word) print::p_y#0 ← *((signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$2)
[10] call print
to:main::@2
main::@2: scope:[main] from main::@1
[11] (byte) main::i#1 ← ++ (byte) main::i#2
[12] if((byte) main::i#1!=(byte) 4) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@2
[13] return
to:@return
print: scope:[print] from main::@1
[14] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) print::p_x#0
[15] (byte) idx#3 ← ++ (byte) idx#14
[16] (byte~) print::$0 ← < (signed word) print::p_y#0
[17] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte~) print::$0
[18] (byte) idx#4 ← ++ (byte) idx#3
[19] (byte~) print::$1 ← > (signed word) print::p_y#0
[20] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte~) print::$1
[21] (byte) idx#5 ← ++ (byte) idx#4
[22] *((const byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' '
[23] (byte) idx#12 ← ++ (byte) idx#5
to:print::@return
print::@return: scope:[print] from print
[24] return
to:@return

View File

@ -0,0 +1,865 @@
Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i)
Created struct value member variable (byte) print::p_x
Created struct value member variable (signed word) print::p_y
Converted struct value to member variables (struct Point) print::p
Converted procedure struct value parameter to member unwinding (void()) print((byte) print::p_x , (signed word) print::p_y)
Converted procedure struct value parameter to member unwinding in call (void~) main::$0 ← call print *((byte*) main::$3 + (byte~) main::$2) *((signed word*) main::$4 + (byte~) main::$2)
Replacing struct member reference (struct Point) print::p.x with member unwinding reference (byte) print::p_x
Replacing struct member reference (struct Point) print::p.y with member unwinding reference (signed word) print::p_y
Replacing struct member reference (struct Point) print::p.y with member unwinding reference (signed word) print::p_y
Culled Empty Block (label) main::@2
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(struct Point[4]) points#0 ← { { (number) 1, (number) $83f }, { (number) 3, (number) $107e } }
to:@1
main: scope:[main] from @2
(byte) idx#16 ← phi( @2/(byte) idx#15 )
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@3
(byte) idx#14 ← phi( main/(byte) idx#16 main::@3/(byte) idx#0 )
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 )
(byte~) main::$2 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
(byte) print::p_x#0 ← *((byte*) main::$3 + (byte~) main::$2)
(signed word) print::p_y#0 ← *((signed word*) main::$4 + (byte~) main::$2)
call print
to:main::@3
main::@3: scope:[main] from main::@1
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
(byte) idx#9 ← phi( main::@1/(byte) idx#7 )
(byte) idx#0 ← (byte) idx#9
(byte*) main::$3 ← (byte*)(struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X
(signed word*) main::$4 ← (signed word*)(struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y
(byte) main::i#1 ← (byte) main::i#3 + rangenext(0,3)
(bool~) main::$1 ← (byte) main::i#1 != rangelast(0,3)
if((bool~) main::$1) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@3
(byte) idx#10 ← phi( main::@3/(byte) idx#0 )
(byte) idx#1 ← (byte) idx#10
return
to:@return
@1: scope:[] from @begin
(byte*) SCREEN#0 ← ((byte*)) (number) $400
(byte) idx#2 ← (number) 0
to:@2
print: scope:[print] from main::@1
(signed word) print::p_y#1 ← phi( main::@1/(signed word) print::p_y#0 )
(byte) idx#11 ← phi( main::@1/(byte) idx#14 )
(byte) print::p_x#1 ← phi( main::@1/(byte) print::p_x#0 )
*((byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#1
(byte) idx#3 ← ++ (byte) idx#11
(byte~) print::$0 ← < (signed word) print::p_y#1
*((byte*) SCREEN#0 + (byte) idx#3) ← (byte~) print::$0
(byte) idx#4 ← ++ (byte) idx#3
(byte~) print::$1 ← > (signed word) print::p_y#1
*((byte*) SCREEN#0 + (byte) idx#4) ← (byte~) print::$1
(byte) idx#5 ← ++ (byte) idx#4
*((byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' '
(byte) idx#6 ← ++ (byte) idx#5
to:print::@return
print::@return: scope:[print] from print
(byte) idx#12 ← phi( print/(byte) idx#6 )
(byte) idx#7 ← (byte) idx#12
return
to:@return
@2: scope:[] from @1
(byte) idx#15 ← phi( @1/(byte) idx#2 )
call main
to:@3
@3: scope:[] from @2
(byte) idx#13 ← phi( @2/(byte) idx#1 )
(byte) idx#8 ← (byte) idx#13
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_X = (byte) 0
(const byte) OFFSET_STRUCT_POINT_Y = (byte) 1
(byte) Point::x
(signed word) Point::y
(byte*) SCREEN
(byte*) SCREEN#0
(const byte) SIZEOF_STRUCT_POINT = (byte) 3
(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#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(bool~) main::$1
(byte~) main::$2
(byte*) main::$3
(signed word*) main::$4
(label) main::@1
(label) main::@3
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
(struct Point[4]) points
(struct Point[4]) points#0
(void()) print((byte) print::p_x , (signed word) print::p_y)
(byte~) print::$0
(byte~) print::$1
(label) print::@return
(struct Point) print::p
(byte) print::p_x
(byte) print::p_x#0
(byte) print::p_x#1
(signed word) print::p_y
(signed word) print::p_y#0
(signed word) print::p_y#1
Adding number conversion cast (unumber) 0 in (byte) idx#2 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Added casts to value list in (struct Point[4]) points#0 ← (struct Point[4]){ (struct Point){ (byte)(number) 1, (signed word)(number) $83f }, (struct Point){ (byte)(number) 3, (signed word)(number) $107e } }
Successful SSA optimization PassNAddInitializerValueListTypeCasts
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) idx#2 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast 1
Simplifying constant integer cast $83f
Simplifying constant integer cast 3
Simplifying constant integer cast $107e
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (byte) main::i#2 = (byte) main::i#3
Alias (byte) idx#0 = (byte) idx#9 (byte) idx#10 (byte) idx#1
Alias (byte) idx#12 = (byte) idx#6 (byte) idx#7
Alias (byte) idx#15 = (byte) idx#2
Alias (byte) idx#13 = (byte) idx#8
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#16 (byte) idx#15
Identical Phi Values (byte) idx#0 (byte) idx#12
Identical Phi Values (byte) print::p_x#1 (byte) print::p_x#0
Identical Phi Values (byte) idx#11 (byte) idx#14
Identical Phi Values (signed word) print::p_y#1 (signed word) print::p_y#0
Identical Phi Values (byte) idx#13 (byte) idx#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$1 [14] if((byte) main::i#1!=rangelast(0,3)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Identified constant from value list (struct Point) { x: (byte) 1, y: (signed word) $83f }
Identified constant from value list (struct Point) { x: (byte) 3, y: (signed word) $107e }
Successful SSA optimization Pass2ConstantInitializerValueLists
Identified constant from value list (struct Point[4]) { { x: (byte) 1, y: (signed word) $83f }, { x: (byte) 3, y: (signed word) $107e } }
Successful SSA optimization Pass2ConstantInitializerValueLists
Constant (const struct Point[4]) points#0 = { { x: 1, y: $83f }, { x: 3, y: $107e } }
Constant (const byte) main::i#0 = 0
Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const byte) idx#15 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte*)points#0 in [10] (byte*) main::$3 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X
Constant value identified (signed word*)points#0 in [11] (signed word*) main::$4 ← (signed word*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y
Successful SSA optimization Pass2ConstantValues
Resolved ranged next value [12] main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value [14] if(main::i#1!=rangelast(0,3)) goto main::@1 to (number) 4
Simplifying expression containing zero (byte*)points#0 in [10] (byte*) main::$3 ← (byte*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_X
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X
Successful SSA optimization PassNEliminateUnusedVars
Adding number conversion cast (unumber) 4 in if((byte) main::i#1!=(number) 4) goto main::@1
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 4
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 4
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant right-side identified [6] (signed word*) main::$4 ← (signed word*)(const struct Point[4]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) main::$3 = (byte*)points#0
Constant (const signed word*) main::$4 = (signed word*)points#0+OFFSET_STRUCT_POINT_Y
Successful SSA optimization Pass2ConstantIdentification
Rewriting multiplication to use shift and addition[1] (byte~) main::$2 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
Inlining constant with var siblings (const byte) main::i#0
Inlining constant with var siblings (const byte) idx#15
Constant inlined main::i#0 = (byte) 0
Constant inlined main::$3 = (byte*)(const struct Point[4]) points#0
Constant inlined main::$4 = (signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y
Constant inlined idx#15 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Alias (byte~) main::$2 = (byte) main::$6
Successful SSA optimization Pass2AliasElimination
Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT
Successful SSA optimization PassNEliminateUnusedVars
Added new block during phi lifting main::@4(between main::@3 and main::@1)
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
CALL GRAPH
Calls in [] to main:3
Calls in [main] to print:12
Created 2 initial phi equivalence classes
Coalesced [16] main::i#4 ← main::i#1
Coalesced [17] idx#17 ← idx#12
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Culled Empty Block (label) main::@4
Renumbering block @2 to @1
Renumbering block main::@3 to main::@2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@2
[5] (byte) idx#14 ← phi( main/(byte) 0 main::@2/(byte) idx#12 )
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
[6] (byte) main::$5 ← (byte) main::i#2 << (byte) 1
[7] (byte~) main::$2 ← (byte) main::$5 + (byte) main::i#2
[8] (byte) print::p_x#0 ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$2)
[9] (signed word) print::p_y#0 ← *((signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$2)
[10] call print
to:main::@2
main::@2: scope:[main] from main::@1
[11] (byte) main::i#1 ← ++ (byte) main::i#2
[12] if((byte) main::i#1!=(byte) 4) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@2
[13] return
to:@return
print: scope:[print] from main::@1
[14] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) print::p_x#0
[15] (byte) idx#3 ← ++ (byte) idx#14
[16] (byte~) print::$0 ← < (signed word) print::p_y#0
[17] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte~) print::$0
[18] (byte) idx#4 ← ++ (byte) idx#3
[19] (byte~) print::$1 ← > (signed word) print::p_y#0
[20] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte~) print::$1
[21] (byte) idx#5 ← ++ (byte) idx#4
[22] *((const byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' '
[23] (byte) idx#12 ← ++ (byte) idx#5
to:print::@return
print::@return: scope:[print] from print
[24] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) Point::x
(signed word) Point::y
(byte*) SCREEN
(byte) idx
(byte) idx#12 2.6
(byte) idx#14 2.5
(byte) idx#3 2.0
(byte) idx#4 2.0
(byte) idx#5 3.0
(void()) main()
(byte~) main::$2 16.5
(byte) main::$5 22.0
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#2 7.333333333333333
(struct Point[4]) points
(void()) print((byte) print::p_x , (signed word) print::p_y)
(byte~) print::$0 4.0
(byte~) print::$1 4.0
(struct Point) print::p
(byte) print::p_x
(byte) print::p_x#0 6.5
(signed word) print::p_y
(signed word) print::p_y#0 2.5
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
[ idx#14 idx#12 ]
Added variable main::$5 to zero page equivalence class [ main::$5 ]
Added variable main::$2 to zero page equivalence class [ main::$2 ]
Added variable print::p_x#0 to zero page equivalence class [ print::p_x#0 ]
Added variable print::p_y#0 to zero page equivalence class [ print::p_y#0 ]
Added variable idx#3 to zero page equivalence class [ idx#3 ]
Added variable print::$0 to zero page equivalence class [ print::$0 ]
Added variable idx#4 to zero page equivalence class [ idx#4 ]
Added variable print::$1 to zero page equivalence class [ print::$1 ]
Added variable idx#5 to zero page equivalence class [ idx#5 ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ idx#14 idx#12 ]
[ main::$5 ]
[ main::$2 ]
[ print::p_x#0 ]
[ print::p_y#0 ]
[ idx#3 ]
[ print::$0 ]
[ idx#4 ]
[ print::$1 ]
[ idx#5 ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_BYTE:3 [ idx#14 idx#12 ]
Allocated zp ZP_BYTE:4 [ main::$5 ]
Allocated zp ZP_BYTE:5 [ main::$2 ]
Allocated zp ZP_BYTE:6 [ print::p_x#0 ]
Allocated zp ZP_WORD:7 [ print::p_y#0 ]
Allocated zp ZP_BYTE:9 [ idx#3 ]
Allocated zp ZP_BYTE:10 [ print::$0 ]
Allocated zp ZP_BYTE:11 [ idx#4 ]
Allocated zp ZP_BYTE:12 [ print::$1 ]
Allocated zp ZP_BYTE:13 [ idx#5 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test a struct array initialized with to few members (zero-filled for the rest)
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_POINT_Y = 1
.label SCREEN = $400
.label idx = 9
.label idx_4 = $b
.label idx_5 = $d
.label idx_12 = 3
.label idx_14 = 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: {
.label _2 = 5
.label i = 2
.label _5 = 4
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) idx#14 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z idx_14
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta.z i
jmp b1
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
b1_from_b2:
// [5] phi (byte) idx#14 = (byte) idx#12 [phi:main::@2->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy
jmp b1
// main::@1
b1:
// [6] (byte) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda.z i
asl
sta.z _5
// [7] (byte~) main::$2 ← (byte) main::$5 + (byte) main::i#2 -- vbuz1=vbuz2_plus_vbuz3
lda.z _5
clc
adc.z i
sta.z _2
// [8] (byte) print::p_x#0 ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$2) -- vbuz1=pbuc1_derefidx_vbuz2
ldy.z _2
lda points,y
sta.z print.p_x
// [9] (signed word) print::p_y#0 ← *((signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$2) -- vwsz1=pwsc1_derefidx_vbuz2
ldy.z _2
lda points+OFFSET_STRUCT_POINT_Y,y
sta.z print.p_y
lda points+OFFSET_STRUCT_POINT_Y+1,y
sta.z print.p_y+1
// [10] call print
jsr print
jmp b2
// main::@2
b2:
// [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #4
cmp.z i
bne b1_from_b2
jmp breturn
// main::@return
breturn:
// [13] return
rts
}
// print
// print(byte zeropage(6) p_x, signed word zeropage(7) p_y)
print: {
.label _0 = $a
.label _1 = $c
.label p_x = 6
.label p_y = 7
// [14] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2
lda.z p_x
ldy.z idx_14
sta SCREEN,y
// [15] (byte) idx#3 ← ++ (byte) idx#14 -- vbuz1=_inc_vbuz2
ldy.z idx_14
iny
sty.z idx
// [16] (byte~) print::$0 ← < (signed word) print::p_y#0 -- vbuz1=_lo_vwsz2
lda.z p_y
sta.z _0
// [17] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte~) print::$0 -- pbuc1_derefidx_vbuz1=vbuz2
lda.z _0
ldy.z idx
sta SCREEN,y
// [18] (byte) idx#4 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz2
ldy.z idx
iny
sty.z idx_4
// [19] (byte~) print::$1 ← > (signed word) print::p_y#0 -- vbuz1=_hi_vwsz2
lda.z p_y+1
sta.z _1
// [20] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte~) print::$1 -- pbuc1_derefidx_vbuz1=vbuz2
lda.z _1
ldy.z idx_4
sta SCREEN,y
// [21] (byte) idx#5 ← ++ (byte) idx#4 -- vbuz1=_inc_vbuz2
ldy.z idx_4
iny
sty.z idx_5
// [22] *((const byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy.z idx_5
sta SCREEN,y
// [23] (byte) idx#12 ← ++ (byte) idx#5 -- vbuz1=_inc_vbuz2
ldy.z idx_5
iny
sty.z idx_12
jmp breturn
// print::@return
breturn:
// [24] return
rts
}
// File Data
points:
.byte 1
.word $83f
.byte 3
.word $107e
.byte 0
.word 0
.byte 0
.word 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] (byte) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 idx#14 main::$5 ] ( main:2 [ main::i#2 idx#14 main::$5 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ idx#14 idx#12 ]
Statement [7] (byte~) main::$2 ← (byte) main::$5 + (byte) main::i#2 [ main::i#2 idx#14 main::$2 ] ( main:2 [ main::i#2 idx#14 main::$2 ] ) always clobbers reg byte a
Statement [9] (signed word) print::p_y#0 ← *((signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$2) [ main::i#2 idx#14 print::p_x#0 print::p_y#0 ] ( main:2 [ main::i#2 idx#14 print::p_x#0 print::p_y#0 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ print::p_x#0 ]
Statement [14] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) print::p_x#0 [ idx#14 print::p_y#0 ] ( main:2::print:10 [ main::i#2 idx#14 print::p_y#0 ] ) always clobbers reg byte a
Statement [16] (byte~) print::$0 ← < (signed word) print::p_y#0 [ print::p_y#0 idx#3 print::$0 ] ( main:2::print:10 [ main::i#2 print::p_y#0 idx#3 print::$0 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:9 [ idx#3 ]
Statement [19] (byte~) print::$1 ← > (signed word) print::p_y#0 [ idx#4 print::$1 ] ( main:2::print:10 [ main::i#2 idx#4 print::$1 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:11 [ idx#4 ]
Statement [22] *((const byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' ' [ idx#5 ] ( main:2::print:10 [ main::i#2 idx#5 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:13 [ idx#5 ]
Statement [6] (byte) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 idx#14 main::$5 ] ( main:2 [ main::i#2 idx#14 main::$5 ] ) always clobbers reg byte a
Statement [7] (byte~) main::$2 ← (byte) main::$5 + (byte) main::i#2 [ main::i#2 idx#14 main::$2 ] ( main:2 [ main::i#2 idx#14 main::$2 ] ) always clobbers reg byte a
Statement [9] (signed word) print::p_y#0 ← *((signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$2) [ main::i#2 idx#14 print::p_x#0 print::p_y#0 ] ( main:2 [ main::i#2 idx#14 print::p_x#0 print::p_y#0 ] ) always clobbers reg byte a
Statement [14] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) print::p_x#0 [ idx#14 print::p_y#0 ] ( main:2::print:10 [ main::i#2 idx#14 print::p_y#0 ] ) always clobbers reg byte a
Statement [16] (byte~) print::$0 ← < (signed word) print::p_y#0 [ print::p_y#0 idx#3 print::$0 ] ( main:2::print:10 [ main::i#2 print::p_y#0 idx#3 print::$0 ] ) always clobbers reg byte a
Statement [19] (byte~) print::$1 ← > (signed word) print::p_y#0 [ idx#4 print::$1 ] ( main:2::print:10 [ main::i#2 idx#4 print::$1 ] ) always clobbers reg byte a
Statement [22] *((const byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' ' [ idx#5 ] ( main:2::print:10 [ main::i#2 idx#5 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ idx#14 idx#12 ] : zp ZP_BYTE:3 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:4 [ main::$5 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:5 [ main::$2 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:6 [ print::p_x#0 ] : zp ZP_BYTE:6 , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:7 [ print::p_y#0 ] : zp ZP_WORD:7 ,
Potential registers zp ZP_BYTE:9 [ idx#3 ] : zp ZP_BYTE:9 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:10 [ print::$0 ] : zp ZP_BYTE:10 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:11 [ idx#4 ] : zp ZP_BYTE:11 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:12 [ print::$1 ] : zp ZP_BYTE:12 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:13 [ idx#5 ] : zp ZP_BYTE:13 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 23.83: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:4 [ main::$5 ] 16.5: zp ZP_BYTE:5 [ main::$2 ]
Uplift Scope [print] 6.5: zp ZP_BYTE:6 [ print::p_x#0 ] 4: zp ZP_BYTE:10 [ print::$0 ] 4: zp ZP_BYTE:12 [ print::$1 ] 2.5: zp ZP_WORD:7 [ print::p_y#0 ]
Uplift Scope [] 5.1: zp ZP_BYTE:3 [ idx#14 idx#12 ] 3: zp ZP_BYTE:13 [ idx#5 ] 2: zp ZP_BYTE:9 [ idx#3 ] 2: zp ZP_BYTE:11 [ idx#4 ]
Uplift Scope [Point]
Uplifting [main] best 794 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$5 ] reg byte y [ main::$2 ]
Uplifting [print] best 782 combination zp ZP_BYTE:6 [ print::p_x#0 ] reg byte a [ print::$0 ] reg byte a [ print::$1 ] zp ZP_WORD:7 [ print::p_y#0 ]
Uplifting [] best 755 combination zp ZP_BYTE:3 [ idx#14 idx#12 ] reg byte y [ idx#5 ] reg byte y [ idx#3 ] reg byte y [ idx#4 ]
Uplifting [Point] best 755 combination
Attempting to uplift remaining variables inzp ZP_BYTE:6 [ print::p_x#0 ]
Uplifting [print] best 755 combination zp ZP_BYTE:6 [ print::p_x#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:3 [ idx#14 idx#12 ]
Uplifting [] best 755 combination zp ZP_BYTE:3 [ idx#14 idx#12 ]
Allocated (was zp ZP_BYTE:3) zp ZP_BYTE:2 [ idx#14 idx#12 ]
Allocated (was zp ZP_BYTE:6) zp ZP_BYTE:3 [ print::p_x#0 ]
Allocated (was zp ZP_WORD:7) zp ZP_WORD:4 [ print::p_y#0 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test a struct array initialized with to few members (zero-filled for the rest)
// Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_POINT_Y = 1
.label SCREEN = $400
.label idx = 2
// @begin
bbegin:
// [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
// @1
b1:
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
// [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
// @end
bend:
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
// [5] phi (byte) idx#14 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z idx
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
ldx #0
jmp b1
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
b1_from_b2:
// [5] phi (byte) idx#14 = (byte) idx#12 [phi:main::@2->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy
jmp b1
// main::@1
b1:
// [6] (byte) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [7] (byte~) main::$2 ← (byte) main::$5 + (byte) main::i#2 -- vbuyy=vbuaa_plus_vbuxx
stx.z $ff
clc
adc.z $ff
tay
// [8] (byte) print::p_x#0 ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$2) -- vbuz1=pbuc1_derefidx_vbuyy
lda points,y
sta.z print.p_x
// [9] (signed word) print::p_y#0 ← *((signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$2) -- vwsz1=pwsc1_derefidx_vbuyy
lda points+OFFSET_STRUCT_POINT_Y,y
sta.z print.p_y
lda points+OFFSET_STRUCT_POINT_Y+1,y
sta.z print.p_y+1
// [10] call print
jsr print
jmp b2
// main::@2
b2:
// [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #4
bne b1_from_b2
jmp breturn
// main::@return
breturn:
// [13] return
rts
}
// print
// print(byte zeropage(3) p_x, signed word zeropage(4) p_y)
print: {
.label p_x = 3
.label p_y = 4
// [14] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2
lda.z p_x
ldy.z idx
sta SCREEN,y
// [15] (byte) idx#3 ← ++ (byte) idx#14 -- vbuyy=_inc_vbuz1
ldy.z idx
iny
// [16] (byte~) print::$0 ← < (signed word) print::p_y#0 -- vbuaa=_lo_vwsz1
lda.z p_y
// [17] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte~) print::$0 -- pbuc1_derefidx_vbuyy=vbuaa
sta SCREEN,y
// [18] (byte) idx#4 ← ++ (byte) idx#3 -- vbuyy=_inc_vbuyy
iny
// [19] (byte~) print::$1 ← > (signed word) print::p_y#0 -- vbuaa=_hi_vwsz1
lda.z p_y+1
// [20] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte~) print::$1 -- pbuc1_derefidx_vbuyy=vbuaa
sta SCREEN,y
// [21] (byte) idx#5 ← ++ (byte) idx#4 -- vbuyy=_inc_vbuyy
iny
// [22] *((const byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' ' -- pbuc1_derefidx_vbuyy=vbuc2
lda #' '
sta SCREEN,y
// [23] (byte) idx#12 ← ++ (byte) idx#5 -- vbuz1=_inc_vbuyy
iny
sty.z idx
jmp breturn
// print::@return
breturn:
// [24] return
rts
}
// File Data
points:
.byte 1
.word $83f
.byte 3
.word $107e
.byte 0
.word 0
.byte 0
.word 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp breturn
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction ldx #0 with TAX
Removing instruction ldy.z idx
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label b1_from_b2 with b1
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction b2:
Removing instruction breturn:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1
(byte) Point::x
(signed word) Point::y
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx
(byte) idx#12 idx zp ZP_BYTE:2 2.6
(byte) idx#14 idx zp ZP_BYTE:2 2.5
(byte) idx#3 reg byte y 2.0
(byte) idx#4 reg byte y 2.0
(byte) idx#5 reg byte y 3.0
(void()) main()
(byte~) main::$2 reg byte y 16.5
(byte) main::$5 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 7.333333333333333
(struct Point[4]) points
(const struct Point[4]) points#0 points = { { x: (byte) 1, y: (signed word) $83f }, { x: (byte) 3, y: (signed word) $107e } }
(void()) print((byte) print::p_x , (signed word) print::p_y)
(byte~) print::$0 reg byte a 4.0
(byte~) print::$1 reg byte a 4.0
(label) print::@return
(struct Point) print::p
(byte) print::p_x
(byte) print::p_x#0 p_x zp ZP_BYTE:3 6.5
(signed word) print::p_y
(signed word) print::p_y#0 p_y zp ZP_WORD:4 2.5
reg byte x [ main::i#2 main::i#1 ]
zp ZP_BYTE:2 [ idx#14 idx#12 ]
reg byte a [ main::$5 ]
reg byte y [ main::$2 ]
zp ZP_BYTE:3 [ print::p_x#0 ]
zp ZP_WORD:4 [ print::p_y#0 ]
reg byte y [ idx#3 ]
reg byte a [ print::$0 ]
reg byte y [ idx#4 ]
reg byte a [ print::$1 ]
reg byte y [ idx#5 ]
FINAL ASSEMBLER
Score: 617
// File Comments
// Test a struct array initialized with to few members (zero-filled for the rest)
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_POINT_Y = 1
.label SCREEN = $400
.label idx = 2
// @begin
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) idx#14 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z idx
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1
tax
// [5] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
// [5] phi (byte) idx#14 = (byte) idx#12 [phi:main::@2->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy
// main::@1
b1:
// print(points[i])
// [6] (byte) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
// [7] (byte~) main::$2 ← (byte) main::$5 + (byte) main::i#2 -- vbuyy=vbuaa_plus_vbuxx
stx.z $ff
clc
adc.z $ff
tay
// [8] (byte) print::p_x#0 ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$2) -- vbuz1=pbuc1_derefidx_vbuyy
lda points,y
sta.z print.p_x
// [9] (signed word) print::p_y#0 ← *((signed word*)(const struct Point[4]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$2) -- vwsz1=pwsc1_derefidx_vbuyy
lda points+OFFSET_STRUCT_POINT_Y,y
sta.z print.p_y
lda points+OFFSET_STRUCT_POINT_Y+1,y
sta.z print.p_y+1
// [10] call print
jsr print
// main::@2
// for ( char i: 0..3)
// [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #4
bne b1
// main::@return
// }
// [13] return
rts
}
// print
// print(byte zeropage(3) p_x, signed word zeropage(4) p_y)
print: {
.label p_x = 3
.label p_y = 4
// SCREEN[idx++] = p.x
// [14] *((const byte*) SCREEN#0 + (byte) idx#14) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2
lda.z p_x
ldy.z idx
sta SCREEN,y
// SCREEN[idx++] = p.x;
// [15] (byte) idx#3 ← ++ (byte) idx#14 -- vbuyy=_inc_vbuz1
iny
// <p.y
// [16] (byte~) print::$0 ← < (signed word) print::p_y#0 -- vbuaa=_lo_vwsz1
lda.z p_y
// SCREEN[idx++] = <p.y
// [17] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte~) print::$0 -- pbuc1_derefidx_vbuyy=vbuaa
sta SCREEN,y
// SCREEN[idx++] = <p.y;
// [18] (byte) idx#4 ← ++ (byte) idx#3 -- vbuyy=_inc_vbuyy
iny
// >p.y
// [19] (byte~) print::$1 ← > (signed word) print::p_y#0 -- vbuaa=_hi_vwsz1
lda.z p_y+1
// SCREEN[idx++] = >p.y
// [20] *((const byte*) SCREEN#0 + (byte) idx#4) ← (byte~) print::$1 -- pbuc1_derefidx_vbuyy=vbuaa
sta SCREEN,y
// SCREEN[idx++] = >p.y;
// [21] (byte) idx#5 ← ++ (byte) idx#4 -- vbuyy=_inc_vbuyy
iny
// SCREEN[idx++] = ' '
// [22] *((const byte*) SCREEN#0 + (byte) idx#5) ← (byte) ' ' -- pbuc1_derefidx_vbuyy=vbuc2
lda #' '
sta SCREEN,y
// SCREEN[idx++] = ' ';
// [23] (byte) idx#12 ← ++ (byte) idx#5 -- vbuz1=_inc_vbuyy
iny
sty.z idx
// print::@return
// }
// [24] return
rts
}
// File Data
points:
.byte 1
.word $83f
.byte 3
.word $107e
.byte 0
.word 0
.byte 0
.word 0

View File

@ -0,0 +1,46 @@
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1
(byte) Point::x
(signed word) Point::y
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx
(byte) idx#12 idx zp ZP_BYTE:2 2.6
(byte) idx#14 idx zp ZP_BYTE:2 2.5
(byte) idx#3 reg byte y 2.0
(byte) idx#4 reg byte y 2.0
(byte) idx#5 reg byte y 3.0
(void()) main()
(byte~) main::$2 reg byte y 16.5
(byte) main::$5 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 7.333333333333333
(struct Point[4]) points
(const struct Point[4]) points#0 points = { { x: (byte) 1, y: (signed word) $83f }, { x: (byte) 3, y: (signed word) $107e } }
(void()) print((byte) print::p_x , (signed word) print::p_y)
(byte~) print::$0 reg byte a 4.0
(byte~) print::$1 reg byte a 4.0
(label) print::@return
(struct Point) print::p
(byte) print::p_x
(byte) print::p_x#0 p_x zp ZP_BYTE:3 6.5
(signed word) print::p_y
(signed word) print::p_y#0 p_y zp ZP_WORD:4 2.5
reg byte x [ main::i#2 main::i#1 ]
zp ZP_BYTE:2 [ idx#14 idx#12 ]
reg byte a [ main::$5 ]
reg byte y [ main::$2 ]
zp ZP_BYTE:3 [ print::p_x#0 ]
zp ZP_WORD:4 [ print::p_y#0 ]
reg byte y [ idx#3 ]
reg byte a [ print::$0 ]
reg byte y [ idx#4 ]
reg byte a [ print::$1 ]
reg byte y [ idx#5 ]