1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-27 04:49:27 +00:00

Implemented struct pointer dereference rewriting. Simple pointers to structs are now working.

This commit is contained in:
jespergravgaard 2019-06-10 14:56:25 +02:00
parent 3d8443d62b
commit 7daf36a811
18 changed files with 1509 additions and 9 deletions

View File

@ -0,0 +1,4 @@
lda #<{c1}
sta {z1}
lda #>{c1}
sta {z1}+1

View File

@ -168,7 +168,7 @@ public class Compiler {
new Pass1AssertReturn(program).execute(); new Pass1AssertReturn(program).execute();
new Pass1AssertUsedVars(program).execute(); new Pass1AssertUsedVars(program).execute();
new PassNSizeOfSimplification(program).execute(); new PassNSizeOfSimplification(program).execute(); // Needed to eliminate sizeof() referencing pointer value variables
new Pass1UnwindStructValues(program).execute(); new Pass1UnwindStructValues(program).execute();
if(getLog().isVerbosePass1CreateSsa()) { if(getLog().isVerbosePass1CreateSsa()) {
@ -178,7 +178,9 @@ public class Compiler {
new Pass1FixLValuesLoHi(program).execute(); new Pass1FixLValuesLoHi(program).execute();
new Pass1AssertNoLValueIntermediate(program).execute(); new Pass1AssertNoLValueIntermediate(program).execute();
new Pass1PointerSizeofFix(program).execute(); new Pass1PointerSizeofFix(program).execute(); // After this point in the code all pointer math is byte-based
new PassNStructPointerRewriting(program).execute();
new PassNAddBooleanCasts(program).execute(); new PassNAddBooleanCasts(program).execute();
new PassNAddTypeConversionAssignment(program).execute(); new PassNAddTypeConversionAssignment(program).execute();
new Pass1EarlyConstantIdentification(program).execute(); new Pass1EarlyConstantIdentification(program).execute();
@ -281,7 +283,6 @@ public class Compiler {
optimizations.add(new Pass2ConstantIfs(program)); optimizations.add(new Pass2ConstantIfs(program));
optimizations.add(new Pass2ConstantStringConsolidation(program)); optimizations.add(new Pass2ConstantStringConsolidation(program));
optimizations.add(new Pass2RangeResolving(program)); optimizations.add(new Pass2RangeResolving(program));
//optimizations.add(new Pass2BooleanizeConditions(program));
optimizations.add(new Pass2ComparisonOptimization(program)); optimizations.add(new Pass2ComparisonOptimization(program));
optimizations.add(new Pass2InlineDerefIdx(program)); optimizations.add(new Pass2InlineDerefIdx(program));
optimizations.add(new Pass2DeInlineWordDerefIdx(program)); optimizations.add(new Pass2DeInlineWordDerefIdx(program));

View File

@ -99,7 +99,7 @@ public class AsmFragmentInstance {
StructMemberRef structMemberRef = (StructMemberRef) boundValue; StructMemberRef structMemberRef = (StructMemberRef) boundValue;
StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef); StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef);
Variable structMember = structDefinition.getMember(structMemberRef.getMemberName()); Variable structMember = structDefinition.getMember(structMemberRef.getMemberName());
int memberByteOffset = structDefinition.getMemberByteOffset(structMember); long memberByteOffset = structDefinition.getMemberByteOffset(structMember);
VariableRef struct = (VariableRef) structMemberRef.getStruct(); VariableRef struct = (VariableRef) structMemberRef.getStruct();
Variable structVar = program.getScope().getVariable( struct); Variable structVar = program.getScope().getVariable( struct);
Registers.RegisterZpStruct structRegister = (Registers.RegisterZpStruct) structVar.getAllocation(); Registers.RegisterZpStruct structRegister = (Registers.RegisterZpStruct) structVar.getAllocation();

View File

@ -309,7 +309,7 @@ public class AsmFragmentInstanceSpecFactory {
StructMemberRef structMemberRef = (StructMemberRef) value; StructMemberRef structMemberRef = (StructMemberRef) value;
StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef); StructDefinition structDefinition = program.getScope().getStructDefinition(structMemberRef);
Variable structMember = structDefinition.getMember(structMemberRef.getMemberName()); Variable structMember = structDefinition.getMember(structMemberRef.getMemberName());
int memberByteOffset = structDefinition.getMemberByteOffset(structMember); long memberByteOffset = structDefinition.getMemberByteOffset(structMember);
RValue struct = structMemberRef.getStruct(); RValue struct = structMemberRef.getStruct();
if(struct instanceof VariableRef) { if(struct instanceof VariableRef) {

View File

@ -159,8 +159,8 @@ public class Registers {
super(zp); super(zp);
} }
public RegisterZpStructMember getMemberRegister(int memberByteOffset) { public RegisterZpStructMember getMemberRegister(long memberByteOffset) {
return new RegisterZpStructMember(getZp()+memberByteOffset); return new RegisterZpStructMember((int) (getZp()+memberByteOffset));
} }
@Override @Override

View File

@ -37,8 +37,8 @@ public class StructDefinition extends Scope {
* @param member The member to find offset for * @param member The member to find offset for
* @return The byte offset of the start of the member data * @return The byte offset of the start of the member data
*/ */
public int getMemberByteOffset(Variable member) { public long getMemberByteOffset(Variable member) {
int byteOffset=0; long byteOffset=0;
for(Variable structMember : getAllVariables(false)) { for(Variable structMember : getAllVariables(false)) {
if(structMember.equals(member)) { if(structMember.equals(member)) {
break; break;

View File

@ -0,0 +1,96 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeInference;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
import dk.camelot64.kickc.model.values.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Rewrite access to member of dereferenced struct (*ptr_struct).x to reference the member directly *((*typeof_x)(ptr_struct+OFFSET_STRUCT_AAA_X))
*/
public class PassNStructPointerRewriting extends Pass2SsaOptimization {
public PassNStructPointerRewriting(Program program) {
super(program);
}
@Override
public boolean step() {
AtomicBoolean modified = new AtomicBoolean(false);
ProgramValueIterator.execute(getProgram(), (programValue, currentStmt, stmtIt, currentBlock) -> {
if(programValue.get() instanceof StructMemberRef) {
StructMemberRef structMemberRef = (StructMemberRef) programValue.get();
RValue struct = structMemberRef.getStruct();
if(struct instanceof PointerDereferenceSimple) {
RValue structPointer = ((PointerDereferenceSimple) struct).getPointer();
// We have a match for (*ptr_struct).x
SymbolType structType = SymbolTypeInference.inferType(getScope(), struct);
if(!(structType instanceof SymbolTypeStruct)) {
throw new CompileError("Accessing member of a non-struct ", currentStmt.getSource());
}
StructDefinition structDefinition = ((SymbolTypeStruct) structType).getStructDefinition(getScope());
ConstantRef memberOffsetConstant = getMemberOffsetConstant(getScope(), structDefinition, structMemberRef.getMemberName());
SymbolType memberType = SymbolTypeInference.inferType(getScope(), structMemberRef);
getLog().append("Rewriting struct pointer member access " + programValue.get().toString(getProgram()));
// Cast struct pointer to the type of the member
CastValue structTypedPointer = new CastValue(new SymbolTypePointer(memberType), structPointer);
// Create temporary variable to hold pointer to member ($1)
Scope scope = getScope().getScope(currentBlock.getScope());
VariableIntermediate memberAddress = scope.addVariableIntermediate();
memberAddress.setType(new SymbolTypePointer(memberType));
// Add statement $1 = ptr_struct + OFFSET_STRUCT_NAME_MEMBER
stmtIt.previous();
stmtIt.add(new StatementAssignment(memberAddress.getRef(), structTypedPointer, Operators.PLUS, memberOffsetConstant, currentStmt.getSource(), currentStmt.getComments()));
stmtIt.next();
// Replace (*ptr_struct).x with *($1)
programValue.set(new PointerDereferenceSimple(memberAddress.getRef()));
modified.set(true);
}
}
});
return modified.get();
}
/**
* Get the constant variable containing the (byte) index of a specific member
*
* @param programScope The program scope (used for finding/adding the constant).
* @param structDefinition The struct
* @param memberName The name of the struct member
* @return The constant variable
*/
private static ConstantRef getMemberOffsetConstant(ProgramScope programScope, StructDefinition structDefinition, String memberName) {
String typeConstName = getMemberOffsetConstantName(structDefinition, memberName);
ConstantVar memberOffsetConstant = programScope.getConstant(typeConstName);
if(memberOffsetConstant == null) {
// Constant not found - create it
Variable memberDef = structDefinition.getMember(memberName);
long memberByteOffset = structDefinition.getMemberByteOffset(memberDef);
memberOffsetConstant = new ConstantVar(typeConstName, programScope, SymbolType.BYTE, new ConstantInteger(memberByteOffset & 0xff, SymbolType.BYTE));
programScope.add(memberOffsetConstant);
}
return memberOffsetConstant.getRef();
}
/**
* Get the name of the constant variable containing the (byte) index of a specific member in a struct
*
* @param structDefinition The struct
* @param memberName The name of the struct member
* @return The name of the constant
*/
private static String getMemberOffsetConstantName(StructDefinition structDefinition, String memberName) {
return "OFFSET_" + structDefinition.getType().getTypeName().toUpperCase().replace(" ", "_") + "_" + memberName.toUpperCase();
}
}

View File

@ -35,6 +35,16 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
@Test
public void testStructPtr4() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-4");
}
@Test
public void testStructPtr3() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-3");
}
@Test @Test
public void testStructPtr2() throws IOException, URISyntaxException { public void testStructPtr2() throws IOException, URISyntaxException {
compileAndCompare("struct-ptr-2", log()); compileAndCompare("struct-ptr-2", log());

View File

@ -0,0 +1,17 @@
// Minimal struct - accessing pointer to struct in memory
struct Point {
byte x;
byte y;
};
struct Point* points = 0x1000;
void main() {
const byte* SCREEN = 0x0400;
SCREEN[0] = (*points).x;
SCREEN[1] = (*points).y;
points++;
SCREEN[2] = (*points).x;
SCREEN[3] = (*points).y;
}

View File

@ -0,0 +1,30 @@
// Minimal struct - accessing pointer to struct in memory in a loop
struct Point {
byte x;
byte y;
};
struct Point* POINTS = 0x1000;
void main() {
// Fill points
struct Point* points = POINTS;
for( byte i: 0..3) {
(*points).x = i;
(*points).y = i+5;
points++;
}
// Print points
const byte* SCREEN = 0x0400;
byte idx = 0;
points = POINTS;
for( byte i: 0..3) {
SCREEN[idx++] = (*points).x;
SCREEN[idx++] = (*points).y;
SCREEN[idx++] = ' ';
points++;
}
}

View File

@ -0,0 +1,18 @@
// Minimal struct - accessing pointer to struct in memory
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
main: {
.label SCREEN = $400
lda $1000
sta SCREEN
lda $1000+OFFSET_STRUCT_POINT_Y
sta SCREEN+1
lda $1000+SIZEOF_STRUCT_POINT
sta SCREEN+2
lda $1000+SIZEOF_STRUCT_POINT+OFFSET_STRUCT_POINT_Y
sta SCREEN+3
rts
}

View File

@ -0,0 +1,18 @@
@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] *((const byte*) main::SCREEN#0) ← *((byte*)(struct Point*) 4096)
[5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(struct Point*) 4096+(const byte) OFFSET_STRUCT_POINT_Y)
[6] *((const byte*) main::SCREEN#0+(byte) 2) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT)
[7] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT+(const byte) OFFSET_STRUCT_POINT_Y)
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return

View File

@ -0,0 +1,360 @@
Fixing pointer increment (struct Point*) points ← ++ (struct Point*) points
Rewriting struct pointer member access *((struct Point*) points).x
Rewriting struct pointer member access *((struct Point*) points).y
Rewriting struct pointer member access *((struct Point*) points).x
Rewriting struct pointer member access *((struct Point*) points).y
Adding pointer type conversion cast (struct Point*) points in (struct Point*) points ← (number) $1000
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(struct Point*) points#0 ← ((struct Point*)) (number) $1000
to:@1
main: scope:[main] from @1
(struct Point*) points#4 ← phi( @1/(struct Point*) points#7 )
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
(byte*) main::$0 ← (byte*)(struct Point*) points#4 + (const byte) OFFSET_STRUCT_POINT_X
*((byte*) main::SCREEN#0 + (number) 0) ← *((byte*) main::$0)
(byte*) main::$1 ← (byte*)(struct Point*) points#4 + (const byte) OFFSET_STRUCT_POINT_Y
*((byte*) main::SCREEN#0 + (number) 1) ← *((byte*) main::$1)
(struct Point*) points#1 ← (struct Point*) points#4 + (const byte) SIZEOF_STRUCT_POINT
(byte*) main::$2 ← (byte*)(struct Point*) points#1 + (const byte) OFFSET_STRUCT_POINT_X
*((byte*) main::SCREEN#0 + (number) 2) ← *((byte*) main::$2)
(byte*) main::$3 ← (byte*)(struct Point*) points#1 + (const byte) OFFSET_STRUCT_POINT_Y
*((byte*) main::SCREEN#0 + (number) 3) ← *((byte*) main::$3)
to:main::@return
main::@return: scope:[main] from main
(struct Point*) points#5 ← phi( main/(struct Point*) points#1 )
(struct Point*) points#2 ← (struct Point*) points#5
return
to:@return
@1: scope:[] from @begin
(struct Point*) points#7 ← phi( @begin/(struct Point*) points#0 )
call main
to:@2
@2: scope:[] from @1
(struct Point*) points#6 ← phi( @1/(struct Point*) points#2 )
(struct Point*) points#3 ← (struct Point*) points#6
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_X = (byte) 0
(const byte) OFFSET_STRUCT_POINT_Y = (byte) 1
(byte) Point::x
(byte) Point::y
(const byte) SIZEOF_STRUCT_POINT = (byte) 2
(void()) main()
(byte*) main::$0
(byte*) main::$1
(byte*) main::$2
(byte*) main::$3
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(struct Point*) points
(struct Point*) points#0
(struct Point*) points#1
(struct Point*) points#2
(struct Point*) points#3
(struct Point*) points#4
(struct Point*) points#5
(struct Point*) points#6
(struct Point*) points#7
Adding number conversion cast (unumber) 0 in *((byte*) main::SCREEN#0 + (number) 0) ← *((byte*) main::$0)
Adding number conversion cast (unumber) 1 in *((byte*) main::SCREEN#0 + (number) 1) ← *((byte*) main::$1)
Adding number conversion cast (unumber) 2 in *((byte*) main::SCREEN#0 + (number) 2) ← *((byte*) main::$2)
Adding number conversion cast (unumber) 3 in *((byte*) main::SCREEN#0 + (number) 3) ← *((byte*) main::$3)
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (struct Point*) points#0 ← (struct Point*)(number) $1000
Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (struct Point*) 4096
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 2
Simplifying constant integer cast 3
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 2
Finalized unsigned number type (byte) 3
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (struct Point*) points#1 = (struct Point*) points#5 (struct Point*) points#2
Alias (struct Point*) points#0 = (struct Point*) points#7
Alias (struct Point*) points#3 = (struct Point*) points#6
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (struct Point*) points#4 (struct Point*) points#0
Identical Phi Values (struct Point*) points#3 (struct Point*) points#1
Successful SSA optimization Pass2IdenticalPhiElimination
Constant (const struct Point*) points#0 = (struct Point*) 4096
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte*)points#0 in [3] (byte*) main::$0 ← (byte*)(const struct Point*) points#0 + (const byte) OFFSET_STRUCT_POINT_X
Constant value identified (byte*)points#0 in [5] (byte*) main::$1 ← (byte*)(const struct Point*) points#0 + (const byte) OFFSET_STRUCT_POINT_Y
Successful SSA optimization Pass2ConstantValues
Converting *(pointer+n) to pointer[n] [4] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*) main::$0) -- *((byte*)points#0 + OFFSET_STRUCT_POINT_X)
Converting *(pointer+n) to pointer[n] [6] *((const byte*) main::SCREEN#0 + (byte) 1) ← *((byte*) main::$1) -- *((byte*)points#0 + OFFSET_STRUCT_POINT_Y)
Converting *(pointer+n) to pointer[n] [9] *((const byte*) main::SCREEN#0 + (byte) 2) ← *((byte*) main::$2) -- *((byte*)points#1 + OFFSET_STRUCT_POINT_X)
Converting *(pointer+n) to pointer[n] [11] *((const byte*) main::SCREEN#0 + (byte) 3) ← *((byte*) main::$3) -- *((byte*)points#1 + OFFSET_STRUCT_POINT_Y)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)points#0 in [3] (byte*) main::$0 ← (byte*)(const struct Point*) points#0 + (const byte) OFFSET_STRUCT_POINT_X
Simplifying expression containing zero (byte*)points#0 in [4] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*)(const struct Point*) points#0 + (const byte) OFFSET_STRUCT_POINT_X)
Simplifying expression containing zero main::SCREEN#0 in [4] *((const byte*) main::SCREEN#0 + (byte) 0) ← *((byte*)(const struct Point*) points#0)
Simplifying expression containing zero (byte*)points#1 in [8] (byte*) main::$2 ← (byte*)(struct Point*) points#1 + (const byte) OFFSET_STRUCT_POINT_X
Simplifying expression containing zero (byte*)points#1 in [9] *((const byte*) main::SCREEN#0 + (byte) 2) ← *((byte*)(struct Point*) points#1 + (const byte) OFFSET_STRUCT_POINT_X)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte*) main::$0 and assignment [0] (byte*) main::$0 ← (byte*)(const struct Point*) points#0
Eliminating unused variable (byte*) main::$1 and assignment [2] (byte*) main::$1 ← (byte*)(const struct Point*) points#0 + (const byte) OFFSET_STRUCT_POINT_Y
Eliminating unused variable (byte*) main::$2 and assignment [5] (byte*) main::$2 ← (byte*)(struct Point*) points#1
Eliminating unused variable (byte*) main::$3 and assignment [7] (byte*) main::$3 ← (byte*)(struct Point*) points#1 + (const byte) OFFSET_STRUCT_POINT_Y
Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [2] (struct Point*) points#1 ← (const struct Point*) points#0 + (const byte) SIZEOF_STRUCT_POINT
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const struct Point*) points#1 = points#0+SIZEOF_STRUCT_POINT
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte*)points#1 in [3] *((const byte*) main::SCREEN#0 + (byte) 2) ← *((byte*)(const struct Point*) points#1)
Constant value identified (byte*)points#1 in [4] *((const byte*) main::SCREEN#0 + (byte) 3) ← *((byte*)(const struct Point*) points#1 + (const byte) OFFSET_STRUCT_POINT_Y)
Successful SSA optimization Pass2ConstantValues
Inlining constant with different constant siblings (const struct Point*) points#0
Inlining constant with different constant siblings (const struct Point*) points#1
Constant inlined points#0 = (struct Point*) 4096
Constant inlined points#1 = (struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *((byte*)(struct Point*) 4096+OFFSET_STRUCT_POINT_Y)
Consolidated array index constant in *(main::SCREEN#0+1)
Consolidated array index constant in *(main::SCREEN#0+2)
Consolidated array index constant in *((byte*)(struct Point*) 4096+SIZEOF_STRUCT_POINT+OFFSET_STRUCT_POINT_Y)
Consolidated array index constant in *(main::SCREEN#0+3)
Successful SSA optimization Pass2ConstantAdditionElimination
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
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] *((const byte*) main::SCREEN#0) ← *((byte*)(struct Point*) 4096)
[5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(struct Point*) 4096+(const byte) OFFSET_STRUCT_POINT_Y)
[6] *((const byte*) main::SCREEN#0+(byte) 2) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT)
[7] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT+(const byte) OFFSET_STRUCT_POINT_Y)
to:main::@return
main::@return: scope:[main] from main
[8] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) Point::x
(byte) Point::y
(void()) main()
(byte*) main::SCREEN
(struct Point*) points
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
//SEG0 File Comments
// Minimal struct - accessing pointer to struct in memory
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← *((byte*)(struct Point*) 4096) -- _deref_pbuc1=_deref_pbuc2
lda $1000
sta SCREEN
//SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(struct Point*) 4096+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
lda $1000+OFFSET_STRUCT_POINT_Y
sta SCREEN+1
//SEG12 [6] *((const byte*) main::SCREEN#0+(byte) 2) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2
lda $1000+SIZEOF_STRUCT_POINT
sta SCREEN+2
//SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
lda $1000+SIZEOF_STRUCT_POINT+OFFSET_STRUCT_POINT_Y
sta SCREEN+3
jmp breturn
//SEG14 main::@return
breturn:
//SEG15 [8] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] *((const byte*) main::SCREEN#0) ← *((byte*)(struct Point*) 4096) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(struct Point*) 4096+(const byte) OFFSET_STRUCT_POINT_Y) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN#0+(byte) 2) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT+(const byte) OFFSET_STRUCT_POINT_Y) [ ] ( main:2 [ ] ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [Point]
Uplift Scope [main]
Uplift Scope []
Uplifting [Point] best 53 combination
Uplifting [main] best 53 combination
Uplifting [] best 53 combination
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Minimal struct - accessing pointer to struct in memory
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← *((byte*)(struct Point*) 4096) -- _deref_pbuc1=_deref_pbuc2
lda $1000
sta SCREEN
//SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(struct Point*) 4096+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
lda $1000+OFFSET_STRUCT_POINT_Y
sta SCREEN+1
//SEG12 [6] *((const byte*) main::SCREEN#0+(byte) 2) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2
lda $1000+SIZEOF_STRUCT_POINT
sta SCREEN+2
//SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
lda $1000+SIZEOF_STRUCT_POINT+OFFSET_STRUCT_POINT_Y
sta SCREEN+3
jmp breturn
//SEG14 main::@return
breturn:
//SEG15 [8] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1
(byte) Point::x
(byte) Point::y
(const byte) SIZEOF_STRUCT_POINT SIZEOF_STRUCT_POINT = (byte) 2
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(struct Point*) points
FINAL ASSEMBLER
Score: 38
//SEG0 File Comments
// Minimal struct - accessing pointer to struct in memory
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
//SEG8 @end
//SEG9 main
main: {
.label SCREEN = $400
//SEG10 [4] *((const byte*) main::SCREEN#0) ← *((byte*)(struct Point*) 4096) -- _deref_pbuc1=_deref_pbuc2
lda $1000
sta SCREEN
//SEG11 [5] *((const byte*) main::SCREEN#0+(byte) 1) ← *((byte*)(struct Point*) 4096+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
lda $1000+OFFSET_STRUCT_POINT_Y
sta SCREEN+1
//SEG12 [6] *((const byte*) main::SCREEN#0+(byte) 2) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT) -- _deref_pbuc1=_deref_pbuc2
lda $1000+SIZEOF_STRUCT_POINT
sta SCREEN+2
//SEG13 [7] *((const byte*) main::SCREEN#0+(byte) 3) ← *((byte*)(struct Point*) 4096+(const byte) SIZEOF_STRUCT_POINT+(const byte) OFFSET_STRUCT_POINT_Y) -- _deref_pbuc1=_deref_pbuc2
lda $1000+SIZEOF_STRUCT_POINT+OFFSET_STRUCT_POINT_Y
sta SCREEN+3
//SEG14 main::@return
//SEG15 [8] return
rts
}

View File

@ -0,0 +1 @@
program

View File

@ -0,0 +1,70 @@
// Minimal struct - accessing pointer to struct in memory in a loop
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
.label POINTS = $1000
main: {
// Print points
.label SCREEN = $400
.label points = 2
.label points_3 = 4
.label i1 = 6
.label points_5 = 4
ldx #0
lda #<POINTS
sta points
lda #>POINTS
sta points+1
b1:
txa
ldy #0
sta (points),y
txa
clc
adc #5
ldy #OFFSET_STRUCT_POINT_Y
sta (points),y
lda #SIZEOF_STRUCT_POINT
clc
adc points
sta points
bcc !+
inc points+1
!:
inx
cpx #4
bne b1
lda #0
sta i1
tax
lda #<POINTS
sta points_5
lda #>POINTS
sta points_5+1
b2:
ldy #0
lda (points_5),y
sta SCREEN,x
inx
ldy #OFFSET_STRUCT_POINT_Y
lda (points_5),y
sta SCREEN,x
inx
lda #' '
sta SCREEN,x
inx
lda #SIZEOF_STRUCT_POINT
clc
adc points_3
sta points_3
bcc !+
inc points_3+1
!:
inc i1
lda #4
cmp i1
bne b2
rts
}

View File

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

View File

@ -0,0 +1,835 @@
Fixing pointer increment (struct Point*) main::points ← ++ (struct Point*) main::points
Fixing pointer increment (struct Point*) main::points ← ++ (struct Point*) main::points
Rewriting struct pointer member access *((struct Point*) main::points).x
Rewriting struct pointer member access *((struct Point*) main::points).y
Rewriting struct pointer member access *((struct Point*) main::points).x
Rewriting struct pointer member access *((struct Point*) main::points).y
Adding pointer type conversion cast (struct Point*) POINTS in (struct Point*) POINTS ← (number) $1000
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
Identified constant variable (struct Point*) POINTS
Culled Empty Block (label) main::@4
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(struct Point*) POINTS#0 ← ((struct Point*)) (number) $1000
to:@1
main: scope:[main] from @1
(struct Point*) main::points#0 ← (struct Point*) POINTS#0
(byte) main::i#0 ← (byte) 0
to:main::@1
main::@1: scope:[main] from main main::@1
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@1/(byte) main::i#1 )
(struct Point*) main::points#4 ← phi( main/(struct Point*) main::points#0 main::@1/(struct Point*) main::points#1 )
(byte*) main::$3 ← (byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_X
*((byte*) main::$3) ← (byte) main::i#2
(number~) main::$0 ← (byte) main::i#2 + (number) 5
(byte*) main::$4 ← (byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y
*((byte*) main::$4) ← (number~) main::$0
(struct Point*) main::points#1 ← (struct Point*) main::points#4 + (const byte) SIZEOF_STRUCT_POINT
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,3)
(bool~) main::$1 ← (byte) main::i#1 != rangelast(0,3)
if((bool~) main::$1) goto main::@1
to:main::@2
main::@2: scope:[main] from main::@1
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
(byte) main::idx#0 ← (number) 0
(struct Point*) main::points#2 ← (struct Point*) POINTS#0
(byte) main::i1#0 ← (byte) 0
to:main::@3
main::@3: scope:[main] from main::@2 main::@3
(byte) main::i1#2 ← phi( main::@2/(byte) main::i1#0 main::@3/(byte) main::i1#1 )
(byte) main::idx#4 ← phi( main::@2/(byte) main::idx#0 main::@3/(byte) main::idx#3 )
(struct Point*) main::points#5 ← phi( main::@2/(struct Point*) main::points#2 main::@3/(struct Point*) main::points#3 )
(byte*) main::$5 ← (byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_X
*((byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*) main::$5)
(byte) main::idx#1 ← ++ (byte) main::idx#4
(byte*) main::$6 ← (byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y
*((byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*) main::$6)
(byte) main::idx#2 ← ++ (byte) main::idx#1
*((byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' '
(byte) main::idx#3 ← ++ (byte) main::idx#2
(struct Point*) main::points#3 ← (struct Point*) main::points#5 + (const byte) SIZEOF_STRUCT_POINT
(byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,3)
(bool~) main::$2 ← (byte) main::i1#1 != rangelast(0,3)
if((bool~) main::$2) goto main::@3
to:main::@return
main::@return: scope:[main] from main::@3
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
to:@end
@end: scope:[] from @2
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_POINT_X = (byte) 0
(const byte) OFFSET_STRUCT_POINT_Y = (byte) 1
(struct Point*) POINTS
(struct Point*) POINTS#0
(byte) Point::x
(byte) Point::y
(const byte) SIZEOF_STRUCT_POINT = (byte) 2
(void()) main()
(number~) main::$0
(bool~) main::$1
(bool~) main::$2
(byte*) main::$3
(byte*) main::$4
(byte*) main::$5
(byte*) main::$6
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i1
(byte) main::i1#0
(byte) main::i1#1
(byte) main::i1#2
(byte) main::idx
(byte) main::idx#0
(byte) main::idx#1
(byte) main::idx#2
(byte) main::idx#3
(byte) main::idx#4
(struct Point*) main::points
(struct Point*) main::points#0
(struct Point*) main::points#1
(struct Point*) main::points#2
(struct Point*) main::points#3
(struct Point*) main::points#4
(struct Point*) main::points#5
Adding number conversion cast (unumber) 5 in (number~) main::$0 ← (byte) main::i#2 + (number) 5
Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::i#2 + (unumber)(number) 5
Adding number conversion cast (unumber) 0 in (byte) main::idx#0 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (struct Point*) POINTS#0 ← (struct Point*)(number) $1000
Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) main::idx#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (struct Point*) 4096
Simplifying constant integer cast 5
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 5
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 + (byte) 5
Simple Condition (bool~) main::$1 [12] if((byte) main::i#1!=rangelast(0,3)) goto main::@1
Simple Condition (bool~) main::$2 [29] if((byte) main::i1#1!=rangelast(0,3)) goto main::@3
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const struct Point*) POINTS#0 = (struct Point*) 4096
Constant (const byte) main::i#0 = 0
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
Constant (const byte) main::idx#0 = 0
Constant (const byte) main::i1#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const struct Point*) main::points#0 = POINTS#0
Constant (const struct Point*) main::points#2 = POINTS#0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value [10] main::i#1 ← ++ main::i#2 to ++
Resolved ranged comparison value [12] if(main::i#1!=rangelast(0,3)) goto main::@1 to (number) 4
Resolved ranged next value [27] main::i1#1 ← ++ main::i1#2 to ++
Resolved ranged comparison value [29] if(main::i1#1!=rangelast(0,3)) goto main::@3 to (number) 4
Converting *(pointer+n) to pointer[n] [5] *((byte*) main::$3) ← (byte) main::i#2 -- *((byte*)main::points#4 + OFFSET_STRUCT_POINT_X)
Converting *(pointer+n) to pointer[n] [8] *((byte*) main::$4) ← (byte~) main::$0 -- *((byte*)main::points#4 + OFFSET_STRUCT_POINT_Y)
Converting *(pointer+n) to pointer[n] [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*) main::$5) -- *((byte*)main::points#5 + OFFSET_STRUCT_POINT_X)
Converting *(pointer+n) to pointer[n] [22] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*) main::$6) -- *((byte*)main::points#5 + OFFSET_STRUCT_POINT_Y)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)main::points#4 in [4] (byte*) main::$3 ← (byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_X
Simplifying expression containing zero (byte*)main::points#4 in [5] *((byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_X) ← (byte) main::i#2
Simplifying expression containing zero (byte*)main::points#5 in [18] (byte*) main::$5 ← (byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_X
Simplifying expression containing zero (byte*)main::points#5 in [19] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_X)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte*) main::$3 and assignment [1] (byte*) main::$3 ← (byte*)(struct Point*) main::points#4
Eliminating unused variable (byte*) main::$4 and assignment [4] (byte*) main::$4 ← (byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y
Eliminating unused variable (byte*) main::$5 and assignment [10] (byte*) main::$5 ← (byte*)(struct Point*) main::points#5
Eliminating unused variable (byte*) main::$6 and assignment [13] (byte*) main::$6 ← (byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y
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
Adding number conversion cast (unumber) 4 in if((byte) main::i1#1!=(number) 4) goto main::@3
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant integer cast 4
Simplifying constant integer cast 4
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 4
Finalized unsigned number type (byte) 4
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inlining constant with var siblings (const byte) main::i#0
Inlining constant with var siblings (const byte) main::idx#0
Inlining constant with var siblings (const byte) main::i1#0
Inlining constant with var siblings (const struct Point*) main::points#0
Inlining constant with var siblings (const struct Point*) main::points#2
Constant inlined main::points#2 = (const struct Point*) POINTS#0
Constant inlined main::i#0 = (byte) 0
Constant inlined main::i1#0 = (byte) 0
Constant inlined main::idx#0 = (byte) 0
Constant inlined main::points#0 = (const struct Point*) POINTS#0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@5(between main::@1 and main::@1)
Added new block during phi lifting main::@6(between main::@3 and main::@3)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@2
CALL GRAPH
Calls in [] to main:2
Created 5 initial phi equivalence classes
Coalesced [25] main::points#7 ← main::points#3
Coalesced [26] main::idx#5 ← main::idx#3
Coalesced [27] main::i1#3 ← main::i1#1
Coalesced [28] main::points#6 ← main::points#1
Coalesced [29] main::i#3 ← main::i#1
Coalesced down to 5 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@2
Culled Empty Block (label) main::@6
Culled Empty Block (label) main::@5
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::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[5] (struct Point*) main::points#4 ← phi( main/(const struct Point*) POINTS#0 main::@1/(struct Point*) main::points#1 )
[6] *((byte*)(struct Point*) main::points#4) ← (byte) main::i#2
[7] (byte~) main::$0 ← (byte) main::i#2 + (byte) 5
[8] *((byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y) ← (byte~) main::$0
[9] (struct Point*) main::points#1 ← (struct Point*) main::points#4 + (const byte) SIZEOF_STRUCT_POINT
[10] (byte) main::i#1 ← ++ (byte) main::i#2
[11] if((byte) main::i#1!=(byte) 4) goto main::@1
to:main::@2
main::@2: scope:[main] from main::@1 main::@2
[12] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 )
[12] (byte) main::idx#4 ← phi( main::@1/(byte) 0 main::@2/(byte) main::idx#3 )
[12] (struct Point*) main::points#5 ← phi( main::@1/(const struct Point*) POINTS#0 main::@2/(struct Point*) main::points#3 )
[13] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5)
[14] (byte) main::idx#1 ← ++ (byte) main::idx#4
[15] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y)
[16] (byte) main::idx#2 ← ++ (byte) main::idx#1
[17] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' '
[18] (byte) main::idx#3 ← ++ (byte) main::idx#2
[19] (struct Point*) main::points#3 ← (struct Point*) main::points#5 + (const byte) SIZEOF_STRUCT_POINT
[20] (byte) main::i1#1 ← ++ (byte) main::i1#2
[21] if((byte) main::i1#1!=(byte) 4) goto main::@2
to:main::@return
main::@return: scope:[main] from main::@2
[22] return
to:@return
VARIABLE REGISTER WEIGHTS
(struct Point*) POINTS
(byte) Point::x
(byte) Point::y
(void()) main()
(byte~) main::$0 22.0
(byte*) main::SCREEN
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#2 8.8
(byte) main::i1
(byte) main::i1#1 16.5
(byte) main::i1#2 2.75
(byte) main::idx
(byte) main::idx#1 16.5
(byte) main::idx#2 16.5
(byte) main::idx#3 5.5
(byte) main::idx#4 16.5
(struct Point*) main::points
(struct Point*) main::points#1 7.333333333333333
(struct Point*) main::points#3 7.333333333333333
(struct Point*) main::points#4 5.5
(struct Point*) main::points#5 3.142857142857143
Initial phi equivalence classes
[ main::points#4 main::points#1 ]
[ main::i#2 main::i#1 ]
[ main::points#5 main::points#3 ]
[ main::idx#4 main::idx#3 ]
[ main::i1#2 main::i1#1 ]
Added variable main::$0 to zero page equivalence class [ main::$0 ]
Added variable main::idx#1 to zero page equivalence class [ main::idx#1 ]
Added variable main::idx#2 to zero page equivalence class [ main::idx#2 ]
Complete equivalence classes
[ main::points#4 main::points#1 ]
[ main::i#2 main::i#1 ]
[ main::points#5 main::points#3 ]
[ main::idx#4 main::idx#3 ]
[ main::i1#2 main::i1#1 ]
[ main::$0 ]
[ main::idx#1 ]
[ main::idx#2 ]
Allocated zp ZP_WORD:2 [ main::points#4 main::points#1 ]
Allocated zp ZP_BYTE:4 [ main::i#2 main::i#1 ]
Allocated zp ZP_WORD:5 [ main::points#5 main::points#3 ]
Allocated zp ZP_BYTE:7 [ main::idx#4 main::idx#3 ]
Allocated zp ZP_BYTE:8 [ main::i1#2 main::i1#1 ]
Allocated zp ZP_BYTE:9 [ main::$0 ]
Allocated zp ZP_BYTE:10 [ main::idx#1 ]
Allocated zp ZP_BYTE:11 [ main::idx#2 ]
INITIAL ASM
//SEG0 File Comments
// Minimal struct - accessing pointer to struct in memory in a loop
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
.label POINTS = $1000
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
// Print points
.label SCREEN = $400
.label _0 = 9
.label points = 2
.label i = 4
.label idx = $a
.label idx_2 = $b
.label idx_3 = 7
.label points_3 = 5
.label i1 = 8
.label points_5 = 5
.label idx_4 = 7
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG13 [5] phi (struct Point*) main::points#4 = (const struct Point*) POINTS#0 [phi:main->main::@1#1] -- pssz1=pssc1
lda #<POINTS
sta points
lda #>POINTS
sta points+1
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (struct Point*) main::points#4 = (struct Point*) main::points#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] *((byte*)(struct Point*) main::points#4) ← (byte) main::i#2 -- _deref_pbuz1=vbuz2
lda i
ldy #0
sta (points),y
//SEG19 [7] (byte~) main::$0 ← (byte) main::i#2 + (byte) 5 -- vbuz1=vbuz2_plus_vbuc1
lax i
axs #-[5]
stx _0
//SEG20 [8] *((byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y) ← (byte~) main::$0 -- pbuz1_derefidx_vbuc1=vbuz2
lda _0
ldy #OFFSET_STRUCT_POINT_Y
sta (points),y
//SEG21 [9] (struct Point*) main::points#1 ← (struct Point*) main::points#4 + (const byte) SIZEOF_STRUCT_POINT -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_POINT
clc
adc points
sta points
bcc !+
inc points+1
!:
//SEG22 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG23 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #4
cmp i
bne b1_from_b1
//SEG24 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
//SEG25 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1
lda #0
sta i1
//SEG26 [12] phi (byte) main::idx#4 = (byte) 0 [phi:main::@1->main::@2#1] -- vbuz1=vbuc1
lda #0
sta idx_4
//SEG27 [12] phi (struct Point*) main::points#5 = (const struct Point*) POINTS#0 [phi:main::@1->main::@2#2] -- pssz1=pssc1
lda #<POINTS
sta points_5
lda #>POINTS
sta points_5+1
jmp b2
//SEG28 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
b2_from_b2:
//SEG29 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
//SEG30 [12] phi (byte) main::idx#4 = (byte) main::idx#3 [phi:main::@2->main::@2#1] -- register_copy
//SEG31 [12] phi (struct Point*) main::points#5 = (struct Point*) main::points#3 [phi:main::@2->main::@2#2] -- register_copy
jmp b2
//SEG32 main::@2
b2:
//SEG33 [13] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5) -- pbuc1_derefidx_vbuz1=_deref_pbuz2
ldx idx_4
ldy #0
lda (points_5),y
sta SCREEN,x
//SEG34 [14] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuz1=_inc_vbuz2
ldy idx_4
iny
sty idx
//SEG35 [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuc2
ldx idx
ldy #OFFSET_STRUCT_POINT_Y
lda (points_5),y
sta SCREEN,x
//SEG36 [16] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuz1=_inc_vbuz2
ldy idx
iny
sty idx_2
//SEG37 [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' -- pbuc1_derefidx_vbuz1=vbuc2
lda #' '
ldy idx_2
sta SCREEN,y
//SEG38 [18] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuz1=_inc_vbuz2
ldy idx_2
iny
sty idx_3
//SEG39 [19] (struct Point*) main::points#3 ← (struct Point*) main::points#5 + (const byte) SIZEOF_STRUCT_POINT -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_POINT
clc
adc points_3
sta points_3
bcc !+
inc points_3+1
!:
//SEG40 [20] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1
inc i1
//SEG41 [21] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuz1_neq_vbuc1_then_la1
lda #4
cmp i1
bne b2_from_b2
jmp breturn
//SEG42 main::@return
breturn:
//SEG43 [22] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] *((byte*)(struct Point*) main::points#4) ← (byte) main::i#2 [ main::points#4 main::i#2 ] ( main:2 [ main::points#4 main::i#2 ] ) always clobbers reg byte y
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ main::i#2 main::i#1 ]
Statement [8] *((byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y) ← (byte~) main::$0 [ main::points#4 main::i#2 ] ( main:2 [ main::points#4 main::i#2 ] ) always clobbers reg byte y
Statement [9] (struct Point*) main::points#1 ← (struct Point*) main::points#4 + (const byte) SIZEOF_STRUCT_POINT [ main::i#2 main::points#1 ] ( main:2 [ main::i#2 main::points#1 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::i#2 main::i#1 ]
Statement [13] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5) [ main::points#5 main::idx#4 main::i1#2 ] ( main:2 [ main::points#5 main::idx#4 main::i1#2 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ main::idx#4 main::idx#3 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:7 [ main::idx#4 main::idx#3 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ main::i1#2 main::i1#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:8 [ main::i1#2 main::i1#1 ]
Statement [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y) [ main::points#5 main::i1#2 main::idx#1 ] ( main:2 [ main::points#5 main::i1#2 main::idx#1 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:10 [ main::idx#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:10 [ main::idx#1 ]
Statement [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' [ main::points#5 main::i1#2 main::idx#2 ] ( main:2 [ main::points#5 main::i1#2 main::idx#2 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:11 [ main::idx#2 ]
Statement [19] (struct Point*) main::points#3 ← (struct Point*) main::points#5 + (const byte) SIZEOF_STRUCT_POINT [ main::i1#2 main::points#3 main::idx#3 ] ( main:2 [ main::i1#2 main::points#3 main::idx#3 ] ) always clobbers reg byte a
Statement [6] *((byte*)(struct Point*) main::points#4) ← (byte) main::i#2 [ main::points#4 main::i#2 ] ( main:2 [ main::points#4 main::i#2 ] ) always clobbers reg byte a reg byte y
Statement [7] (byte~) main::$0 ← (byte) main::i#2 + (byte) 5 [ main::points#4 main::i#2 main::$0 ] ( main:2 [ main::points#4 main::i#2 main::$0 ] ) always clobbers reg byte a
Statement [8] *((byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y) ← (byte~) main::$0 [ main::points#4 main::i#2 ] ( main:2 [ main::points#4 main::i#2 ] ) always clobbers reg byte y
Statement [9] (struct Point*) main::points#1 ← (struct Point*) main::points#4 + (const byte) SIZEOF_STRUCT_POINT [ main::i#2 main::points#1 ] ( main:2 [ main::i#2 main::points#1 ] ) always clobbers reg byte a
Statement [13] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5) [ main::points#5 main::idx#4 main::i1#2 ] ( main:2 [ main::points#5 main::idx#4 main::i1#2 ] ) always clobbers reg byte a reg byte y
Statement [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y) [ main::points#5 main::i1#2 main::idx#1 ] ( main:2 [ main::points#5 main::i1#2 main::idx#1 ] ) always clobbers reg byte a reg byte y
Statement [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' [ main::points#5 main::i1#2 main::idx#2 ] ( main:2 [ main::points#5 main::i1#2 main::idx#2 ] ) always clobbers reg byte a
Statement [19] (struct Point*) main::points#3 ← (struct Point*) main::points#5 + (const byte) SIZEOF_STRUCT_POINT [ main::i1#2 main::points#3 main::idx#3 ] ( main:2 [ main::i1#2 main::points#3 main::idx#3 ] ) always clobbers reg byte a
Potential registers zp ZP_WORD:2 [ main::points#4 main::points#1 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_BYTE:4 [ main::i#2 main::i#1 ] : zp ZP_BYTE:4 , reg byte x ,
Potential registers zp ZP_WORD:5 [ main::points#5 main::points#3 ] : zp ZP_WORD:5 ,
Potential registers zp ZP_BYTE:7 [ main::idx#4 main::idx#3 ] : zp ZP_BYTE:7 , reg byte x ,
Potential registers zp ZP_BYTE:8 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:8 , reg byte x ,
Potential registers zp ZP_BYTE:9 [ main::$0 ] : zp ZP_BYTE:9 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:10 [ main::idx#1 ] : zp ZP_BYTE:10 , reg byte x ,
Potential registers zp ZP_BYTE:11 [ main::idx#2 ] : zp ZP_BYTE:11 , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 25.3: zp ZP_BYTE:4 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:7 [ main::idx#4 main::idx#3 ] 22: zp ZP_BYTE:9 [ main::$0 ] 19.25: zp ZP_BYTE:8 [ main::i1#2 main::i1#1 ] 16.5: zp ZP_BYTE:10 [ main::idx#1 ] 16.5: zp ZP_BYTE:11 [ main::idx#2 ] 12.83: zp ZP_WORD:2 [ main::points#4 main::points#1 ] 10.48: zp ZP_WORD:5 [ main::points#5 main::points#3 ]
Uplift Scope [Point]
Uplift Scope []
Uplifting [main] best 1708 combination reg byte x [ main::i#2 main::i#1 ] reg byte x [ main::idx#4 main::idx#3 ] reg byte a [ main::$0 ] zp ZP_BYTE:8 [ main::i1#2 main::i1#1 ] reg byte x [ main::idx#1 ] zp ZP_BYTE:11 [ main::idx#2 ] zp ZP_WORD:2 [ main::points#4 main::points#1 ] zp ZP_WORD:5 [ main::points#5 main::points#3 ]
Limited combination testing to 100 combinations of 192 possible.
Uplifting [Point] best 1708 combination
Uplifting [] best 1708 combination
Attempting to uplift remaining variables inzp ZP_BYTE:8 [ main::i1#2 main::i1#1 ]
Uplifting [main] best 1708 combination zp ZP_BYTE:8 [ main::i1#2 main::i1#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:11 [ main::idx#2 ]
Uplifting [main] best 1618 combination reg byte x [ main::idx#2 ]
Allocated (was zp ZP_WORD:5) zp ZP_WORD:4 [ main::points#5 main::points#3 ]
Allocated (was zp ZP_BYTE:8) zp ZP_BYTE:6 [ main::i1#2 main::i1#1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Minimal struct - accessing pointer to struct in memory in a loop
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
.label POINTS = $1000
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
// Print points
.label SCREEN = $400
.label points = 2
.label points_3 = 4
.label i1 = 6
.label points_5 = 4
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG13 [5] phi (struct Point*) main::points#4 = (const struct Point*) POINTS#0 [phi:main->main::@1#1] -- pssz1=pssc1
lda #<POINTS
sta points
lda #>POINTS
sta points+1
jmp b1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
b1_from_b1:
//SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (struct Point*) main::points#4 = (struct Point*) main::points#1 [phi:main::@1->main::@1#1] -- register_copy
jmp b1
//SEG17 main::@1
b1:
//SEG18 [6] *((byte*)(struct Point*) main::points#4) ← (byte) main::i#2 -- _deref_pbuz1=vbuxx
txa
ldy #0
sta (points),y
//SEG19 [7] (byte~) main::$0 ← (byte) main::i#2 + (byte) 5 -- vbuaa=vbuxx_plus_vbuc1
txa
clc
adc #5
//SEG20 [8] *((byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y) ← (byte~) main::$0 -- pbuz1_derefidx_vbuc1=vbuaa
ldy #OFFSET_STRUCT_POINT_Y
sta (points),y
//SEG21 [9] (struct Point*) main::points#1 ← (struct Point*) main::points#4 + (const byte) SIZEOF_STRUCT_POINT -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_POINT
clc
adc points
sta points
bcc !+
inc points+1
!:
//SEG22 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG23 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #4
bne b1_from_b1
//SEG24 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
//SEG25 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1
lda #0
sta i1
//SEG26 [12] phi (byte) main::idx#4 = (byte) 0 [phi:main::@1->main::@2#1] -- vbuxx=vbuc1
ldx #0
//SEG27 [12] phi (struct Point*) main::points#5 = (const struct Point*) POINTS#0 [phi:main::@1->main::@2#2] -- pssz1=pssc1
lda #<POINTS
sta points_5
lda #>POINTS
sta points_5+1
jmp b2
//SEG28 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
b2_from_b2:
//SEG29 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
//SEG30 [12] phi (byte) main::idx#4 = (byte) main::idx#3 [phi:main::@2->main::@2#1] -- register_copy
//SEG31 [12] phi (struct Point*) main::points#5 = (struct Point*) main::points#3 [phi:main::@2->main::@2#2] -- register_copy
jmp b2
//SEG32 main::@2
b2:
//SEG33 [13] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5) -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (points_5),y
sta SCREEN,x
//SEG34 [14] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuxx=_inc_vbuxx
inx
//SEG35 [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_POINT_Y
lda (points_5),y
sta SCREEN,x
//SEG36 [16] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuxx=_inc_vbuxx
inx
//SEG37 [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
//SEG38 [18] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuxx=_inc_vbuxx
inx
//SEG39 [19] (struct Point*) main::points#3 ← (struct Point*) main::points#5 + (const byte) SIZEOF_STRUCT_POINT -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_POINT
clc
adc points_3
sta points_3
bcc !+
inc points_3+1
!:
//SEG40 [20] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1
inc i1
//SEG41 [21] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuz1_neq_vbuc1_then_la1
lda #4
cmp i1
bne b2_from_b2
jmp breturn
//SEG42 main::@return
breturn:
//SEG43 [22] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction ldx #0 with TAX
Replacing label b1_from_b1 with b1
Replacing label b2_from_b2 with b2
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b1:
Removing instruction b2_from_b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction b2_from_b1:
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
Removing instruction jmp b2
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
(struct Point*) POINTS
(const struct Point*) POINTS#0 POINTS = (struct Point*) 4096
(byte) Point::x
(byte) Point::y
(const byte) SIZEOF_STRUCT_POINT SIZEOF_STRUCT_POINT = (byte) 2
(void()) main()
(byte~) main::$0 reg byte a 22.0
(label) main::@1
(label) main::@2
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = (byte*) 1024
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#2 reg byte x 8.8
(byte) main::i1
(byte) main::i1#1 i1 zp ZP_BYTE:6 16.5
(byte) main::i1#2 i1 zp ZP_BYTE:6 2.75
(byte) main::idx
(byte) main::idx#1 reg byte x 16.5
(byte) main::idx#2 reg byte x 16.5
(byte) main::idx#3 reg byte x 5.5
(byte) main::idx#4 reg byte x 16.5
(struct Point*) main::points
(struct Point*) main::points#1 points zp ZP_WORD:2 7.333333333333333
(struct Point*) main::points#3 points#3 zp ZP_WORD:4 7.333333333333333
(struct Point*) main::points#4 points zp ZP_WORD:2 5.5
(struct Point*) main::points#5 points#5 zp ZP_WORD:4 3.142857142857143
zp ZP_WORD:2 [ main::points#4 main::points#1 ]
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:4 [ main::points#5 main::points#3 ]
reg byte x [ main::idx#4 main::idx#3 ]
zp ZP_BYTE:6 [ main::i1#2 main::i1#1 ]
reg byte a [ main::$0 ]
reg byte x [ main::idx#1 ]
reg byte x [ main::idx#2 ]
FINAL ASSEMBLER
Score: 1456
//SEG0 File Comments
// Minimal struct - accessing pointer to struct in memory in a loop
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.const SIZEOF_STRUCT_POINT = 2
.const OFFSET_STRUCT_POINT_Y = 1
.label POINTS = $1000
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main
main: {
// Print points
.label SCREEN = $400
.label points = 2
.label points_3 = 4
.label i1 = 6
.label points_5 = 4
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG13 [5] phi (struct Point*) main::points#4 = (const struct Point*) POINTS#0 [phi:main->main::@1#1] -- pssz1=pssc1
lda #<POINTS
sta points
lda #>POINTS
sta points+1
//SEG14 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
//SEG15 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
//SEG16 [5] phi (struct Point*) main::points#4 = (struct Point*) main::points#1 [phi:main::@1->main::@1#1] -- register_copy
//SEG17 main::@1
b1:
//SEG18 [6] *((byte*)(struct Point*) main::points#4) ← (byte) main::i#2 -- _deref_pbuz1=vbuxx
txa
ldy #0
sta (points),y
//SEG19 [7] (byte~) main::$0 ← (byte) main::i#2 + (byte) 5 -- vbuaa=vbuxx_plus_vbuc1
txa
clc
adc #5
//SEG20 [8] *((byte*)(struct Point*) main::points#4 + (const byte) OFFSET_STRUCT_POINT_Y) ← (byte~) main::$0 -- pbuz1_derefidx_vbuc1=vbuaa
ldy #OFFSET_STRUCT_POINT_Y
sta (points),y
//SEG21 [9] (struct Point*) main::points#1 ← (struct Point*) main::points#4 + (const byte) SIZEOF_STRUCT_POINT -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_POINT
clc
adc points
sta points
bcc !+
inc points+1
!:
//SEG22 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG23 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #4
bne b1
//SEG24 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
//SEG25 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1
lda #0
sta i1
//SEG26 [12] phi (byte) main::idx#4 = (byte) 0 [phi:main::@1->main::@2#1] -- vbuxx=vbuc1
tax
//SEG27 [12] phi (struct Point*) main::points#5 = (const struct Point*) POINTS#0 [phi:main::@1->main::@2#2] -- pssz1=pssc1
lda #<POINTS
sta points_5
lda #>POINTS
sta points_5+1
//SEG28 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
//SEG29 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
//SEG30 [12] phi (byte) main::idx#4 = (byte) main::idx#3 [phi:main::@2->main::@2#1] -- register_copy
//SEG31 [12] phi (struct Point*) main::points#5 = (struct Point*) main::points#3 [phi:main::@2->main::@2#2] -- register_copy
//SEG32 main::@2
b2:
//SEG33 [13] *((const byte*) main::SCREEN#0 + (byte) main::idx#4) ← *((byte*)(struct Point*) main::points#5) -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (points_5),y
sta SCREEN,x
//SEG34 [14] (byte) main::idx#1 ← ++ (byte) main::idx#4 -- vbuxx=_inc_vbuxx
inx
//SEG35 [15] *((const byte*) main::SCREEN#0 + (byte) main::idx#1) ← *((byte*)(struct Point*) main::points#5 + (const byte) OFFSET_STRUCT_POINT_Y) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_POINT_Y
lda (points_5),y
sta SCREEN,x
//SEG36 [16] (byte) main::idx#2 ← ++ (byte) main::idx#1 -- vbuxx=_inc_vbuxx
inx
//SEG37 [17] *((const byte*) main::SCREEN#0 + (byte) main::idx#2) ← (byte) ' ' -- pbuc1_derefidx_vbuxx=vbuc2
lda #' '
sta SCREEN,x
//SEG38 [18] (byte) main::idx#3 ← ++ (byte) main::idx#2 -- vbuxx=_inc_vbuxx
inx
//SEG39 [19] (struct Point*) main::points#3 ← (struct Point*) main::points#5 + (const byte) SIZEOF_STRUCT_POINT -- pssz1=pssz1_plus_vbuc1
lda #SIZEOF_STRUCT_POINT
clc
adc points_3
sta points_3
bcc !+
inc points_3+1
!:
//SEG40 [20] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1
inc i1
//SEG41 [21] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuz1_neq_vbuc1_then_la1
lda #4
cmp i1
bne b2
//SEG42 main::@return
//SEG43 [22] return
rts
}

View File

@ -0,0 +1 @@
program