mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-07 07:29:49 +00:00
Implemented struct value call parameter passing by unwinding.
This commit is contained in:
parent
c995a1bca1
commit
0dcd739507
@ -61,6 +61,9 @@ public class Procedure extends Scope {
|
||||
}
|
||||
}
|
||||
|
||||
public void setParameterNames(List<String> parameterNames) {
|
||||
this.parameterNames = parameterNames;
|
||||
}
|
||||
|
||||
public List<Comment> getComments() {
|
||||
return comments;
|
||||
|
@ -54,7 +54,7 @@ public class Pass1EarlyConstantIdentification extends Pass1Base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines whether a variale is a procedure parameter
|
||||
* Examines whether a variable is a procedure parameter
|
||||
* @param variableRef The variable
|
||||
* @return true if the variable is a procedure parameter
|
||||
*/
|
||||
|
@ -2,24 +2,22 @@ package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.Comment;
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.InternalError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.symbols.StructDefinition;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.symbols.VariableIntermediate;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.*;
|
||||
import dk.camelot64.kickc.model.types.SymbolTypeStruct;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.StructMemberRef;
|
||||
import dk.camelot64.kickc.model.values.StructZero;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/** Convert all struct values that are not used as pointers (address-of used or declared volatile) */
|
||||
/** Convert all struct values that are not used as pointers (address-of used or declared volatile) into variables representing each member */
|
||||
public class Pass1UnwindStructValues extends Pass1Base {
|
||||
|
||||
public Pass1UnwindStructValues(Program program) {
|
||||
@ -31,7 +29,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
boolean modified = false;
|
||||
|
||||
// Maps struct variable to map from member name to the variable
|
||||
Map<VariableRef, Map<String, VariableRef>> structMemberVariableMap = new LinkedHashMap<>();
|
||||
StructUnwinding structUnwinding = new StructUnwinding();
|
||||
|
||||
// Iterate through all scopes generating member-variables for each struct
|
||||
for(Variable variable : getScope().getAllVariables(true)) {
|
||||
@ -40,7 +38,7 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
// A non-volatile struct variable
|
||||
Scope scope = variable.getScope();
|
||||
StructDefinition structDefinition = ((SymbolTypeStruct) variable.getType()).getStructDefinition(getProgram().getScope());
|
||||
LinkedHashMap<String, VariableRef> memberVariables = new LinkedHashMap<>();
|
||||
StructUnwinding.VariableUnwinding variableUnwinding = structUnwinding.createVariableUnwinding(variable.getRef());
|
||||
for(Variable member : structDefinition.getAllVariables(false)) {
|
||||
Variable memberVariable;
|
||||
if(variable.getRef().isIntermediate()) {
|
||||
@ -48,14 +46,34 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
} else {
|
||||
memberVariable = scope.addVariable(variable.getLocalName() + "_" + member.getLocalName(), member.getType());
|
||||
}
|
||||
memberVariables.put(member.getLocalName(), memberVariable.getRef());
|
||||
variableUnwinding.setMemberUnwinding(member.getLocalName(), memberVariable.getRef());
|
||||
getLog().append("Created struct value member variable " + memberVariable.toString(getProgram()));
|
||||
}
|
||||
structMemberVariableMap.put(variable.getRef(), memberVariables);
|
||||
getLog().append("Converted struct value to member variables " + variable.toString(getProgram()));
|
||||
}
|
||||
}
|
||||
}
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
|
||||
ArrayList<String> unwoundParameterNames = new ArrayList<>();
|
||||
boolean procedureUnwound = false;
|
||||
for(Variable parameter : procedure.getParameters()) {
|
||||
if(parameter.getType() instanceof SymbolTypeStruct) {
|
||||
StructUnwinding.VariableUnwinding parameterUnwinding = structUnwinding.getVariableUnwinding(parameter.getRef());
|
||||
for(String memberName : parameterUnwinding.getMemberNames()) {
|
||||
unwoundParameterNames.add(parameterUnwinding.getMemberUnwinding(memberName).getLocalName());
|
||||
procedureUnwound = true;
|
||||
}
|
||||
} else {
|
||||
unwoundParameterNames.add(parameter.getLocalName());
|
||||
}
|
||||
}
|
||||
if(procedureUnwound) {
|
||||
procedure.setParameterNames(unwoundParameterNames);
|
||||
getLog().append("Converted procedure struct value parameter to member variables " + procedure.toString(getProgram()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unwind all references to full structs
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
@ -70,11 +88,11 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
// Assigning a struct!
|
||||
if(assignment.getOperator() == null && assignment.getrValue2() instanceof StructZero) {
|
||||
// Initializing a struct - unwind to assigning zero to each member!
|
||||
Map<String, VariableRef> memberVariables = structMemberVariableMap.get(assignedVar.getRef());
|
||||
if(memberVariables != null) {
|
||||
StructUnwinding.VariableUnwinding variableUnwinding = structUnwinding.getVariableUnwinding(assignedVar.getRef());
|
||||
if(variableUnwinding != null) {
|
||||
stmtIt.previous();
|
||||
for(String memberName : memberVariables.keySet()) {
|
||||
VariableRef memberVarRef = memberVariables.get(memberName);
|
||||
for(String memberName : variableUnwinding.getMemberNames()) {
|
||||
VariableRef memberVarRef = variableUnwinding.getMemberUnwinding(memberName);
|
||||
Variable memberVar = getScope().getVariable(memberVarRef);
|
||||
Statement initStmt = Pass0GenerateStatementSequence.createDefaultInitializationStatement(memberVarRef, memberVar.getType(), statement.getSource(), Comment.NO_COMMENTS);
|
||||
stmtIt.add(initStmt);
|
||||
@ -87,52 +105,147 @@ public class Pass1UnwindStructValues extends Pass1Base {
|
||||
Variable sourceVar = getScope().getVariable((VariableRef) assignment.getrValue2());
|
||||
if(sourceVar.getType().equals(assignedVar.getType())) {
|
||||
// Copying a struct - unwind to assigning each member!
|
||||
Map<String, VariableRef> assignedMemberVariables = structMemberVariableMap.get(assignedVar.getRef());
|
||||
Map<String, VariableRef> sourceMemberVariables = structMemberVariableMap.get(sourceVar.getRef());
|
||||
if(assignedMemberVariables != null && sourceMemberVariables!=null) {
|
||||
StructUnwinding.VariableUnwinding assignedMemberVariables = structUnwinding.getVariableUnwinding(assignedVar.getRef());
|
||||
StructUnwinding.VariableUnwinding sourceMemberVariables = structUnwinding.getVariableUnwinding(sourceVar.getRef());
|
||||
if(assignedMemberVariables != null && sourceMemberVariables != null) {
|
||||
stmtIt.previous();
|
||||
for(String memberName : assignedMemberVariables.keySet()) {
|
||||
VariableRef assignedMemberVarRef = assignedMemberVariables.get(memberName);
|
||||
VariableRef sourceMemberVarRef = sourceMemberVariables.get(memberName);
|
||||
for(String memberName : assignedMemberVariables.getMemberNames()) {
|
||||
VariableRef assignedMemberVarRef = assignedMemberVariables.getMemberUnwinding(memberName);
|
||||
VariableRef sourceMemberVarRef = sourceMemberVariables.getMemberUnwinding(memberName);
|
||||
Statement copyStmt = new StatementAssignment(assignedMemberVarRef, sourceMemberVarRef, statement.getSource(), Comment.NO_COMMENTS);
|
||||
stmtIt.add(copyStmt);
|
||||
getLog().append("Adding struct value member variable copy " + copyStmt.toString(getProgram(), false));
|
||||
}
|
||||
stmtIt.next();
|
||||
stmtIt.remove();
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Struct assignment not implemented yet " + statement.toString(getProgram(), false));
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Struct assignment not implemented yet " + statement.toString(getProgram(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(statement instanceof StatementCall) {
|
||||
StatementCall statementCall = (StatementCall) statement;
|
||||
Procedure procedure = getScope().getProcedure(statementCall.getProcedure());
|
||||
ArrayList<RValue> unwoundParameters = new ArrayList<>();
|
||||
boolean anyUnwound = false;
|
||||
for(RValue parameter : statementCall.getParameters()) {
|
||||
boolean unwound = false;
|
||||
if(parameter instanceof VariableRef) {
|
||||
Variable variable = getScope().getVariable((VariableRef) parameter);
|
||||
if(variable.getType() instanceof SymbolTypeStruct) {
|
||||
// Passing a struct variable - convert it to member variables
|
||||
StructUnwinding.VariableUnwinding variableUnwinding = structUnwinding.getVariableUnwinding((VariableRef) parameter);
|
||||
if(variableUnwinding!=null) {
|
||||
for(String memberName : variableUnwinding.getMemberNames()) {
|
||||
unwoundParameters.add(variableUnwinding.getMemberUnwinding(memberName));
|
||||
}
|
||||
unwound = true;
|
||||
anyUnwound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!unwound) {
|
||||
unwoundParameters.add(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
if(anyUnwound) {
|
||||
statementCall.setParameters(unwoundParameters);
|
||||
getLog().append("Converted procedure struct value parameter to member variables in call " + statementCall.toString(getProgram(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change all usages of members in statements
|
||||
// Change all usages of members inside statements
|
||||
ProgramValueIterator.execute(
|
||||
|
||||
getProgram(), (programValue,currentStmt,stmtIt,currentBlock)->
|
||||
|
||||
{
|
||||
if(programValue.get() instanceof StructMemberRef) {
|
||||
StructMemberRef structMemberRef = (StructMemberRef) programValue.get();
|
||||
if(structMemberRef.getStruct() instanceof VariableRef) {
|
||||
Variable structVariable = getScope().getVariable((VariableRef) structMemberRef.getStruct());
|
||||
Map<String, VariableRef> memberVariables = structMemberVariableMap.get(structVariable.getRef());
|
||||
if(memberVariables != null) {
|
||||
VariableRef structMemberVariable = memberVariables.get(structMemberRef.getMemberName());
|
||||
getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member variable reference " + structMemberVariable.toString(getProgram()));
|
||||
programValue.set(structMemberVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
getProgram(), (programValue, currentStmt, stmtIt, currentBlock) ->
|
||||
{
|
||||
if(programValue.get() instanceof StructMemberRef) {
|
||||
StructMemberRef structMemberRef = (StructMemberRef) programValue.get();
|
||||
if(structMemberRef.getStruct() instanceof VariableRef) {
|
||||
Variable structVariable = getScope().getVariable((VariableRef) structMemberRef.getStruct());
|
||||
StructUnwinding.VariableUnwinding memberVariables = structUnwinding.getVariableUnwinding(structVariable.getRef());
|
||||
if(memberVariables != null) {
|
||||
VariableRef structMemberVariable = memberVariables.getMemberUnwinding(structMemberRef.getMemberName());
|
||||
getLog().append("Replacing struct member reference " + structMemberRef.toString(getProgram()) + " with member variable reference " + structMemberVariable.toString(getProgram()));
|
||||
programValue.set(structMemberVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return modified;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps track of all structs that have been unwound into member variables.
|
||||
*/
|
||||
public static class StructUnwinding {
|
||||
|
||||
/** Maps struct variables to unwinding of each member. */
|
||||
Map<VariableRef, VariableUnwinding> structVariables = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Get information about how a struct variable was unwound into member variables
|
||||
*
|
||||
* @param ref The variable to look for
|
||||
* @return Information about the unwinding. Null if not unwound
|
||||
*/
|
||||
public VariableUnwinding getVariableUnwinding(VariableRef ref) {
|
||||
return structVariables.get(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add information about how a struct variable was unwound into member variables
|
||||
*
|
||||
* @param ref The variable to add information for
|
||||
* @return The new information about the unwinding.
|
||||
*/
|
||||
public VariableUnwinding createVariableUnwinding(VariableRef ref) {
|
||||
VariableUnwinding existing = structVariables.put(ref, new VariableUnwinding());
|
||||
if(existing != null) {
|
||||
throw new InternalError("ERROR! Struct unwinding was already created once! " + ref.toString());
|
||||
}
|
||||
return structVariables.get(ref);
|
||||
}
|
||||
|
||||
|
||||
/** Information about how a single struct variable was unwound. */
|
||||
public static class VariableUnwinding {
|
||||
|
||||
/** Maps member names to the unwound variables. */
|
||||
Map<String, VariableRef> memberUnwinding = new LinkedHashMap<>();
|
||||
|
||||
/** Set how a member variable was unwound to a specific (new) variable. */
|
||||
public void setMemberUnwinding(String memberName, VariableRef memberVariableUnwound) {
|
||||
this.memberUnwinding.put(memberName, memberVariableUnwound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the members of the struct
|
||||
*
|
||||
* @return the names
|
||||
*/
|
||||
public List<String> getMemberNames() {
|
||||
return new ArrayList<>(memberUnwinding.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (new) variable that a specific member was unwound to
|
||||
*
|
||||
* @param memberName The member name
|
||||
* @return The new variable
|
||||
*/
|
||||
public VariableRef getMemberUnwinding(String memberName) {
|
||||
return this.memberUnwinding.get(memberName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,22 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStructPtr2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-2", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStructPtr1() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-1", log());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStructPtr0() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-ptr-0", log());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testStruct5() throws IOException, URISyntaxException {
|
||||
@ -48,7 +64,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testStruct3() throws IOException, URISyntaxException {
|
||||
compileAndCompare("struct-3", log());
|
||||
compileAndCompare("struct-3", log().verboseCreateSsa());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,20 +1,23 @@
|
||||
// Minimal struct - array of struct
|
||||
// Minimal struct - passing struct value parameter
|
||||
|
||||
struct Point {
|
||||
byte x;
|
||||
byte y;
|
||||
};
|
||||
|
||||
struct Point[4] points;
|
||||
|
||||
void main() {
|
||||
for( byte i: 0..4) {
|
||||
points[i].x = i;
|
||||
points[i].y = i+1;
|
||||
}
|
||||
const byte* SCREEN = 0x0400;
|
||||
for( byte i: 0..4) {
|
||||
SCREEN[i] = points[i].x;
|
||||
(SCREEN+40)[i] = points[i].y;
|
||||
}
|
||||
struct Point p1;
|
||||
p1.x = 1;
|
||||
p1.y = 4;
|
||||
print(p1);
|
||||
p1.x = 2;
|
||||
print(p1);
|
||||
}
|
||||
|
||||
const byte* SCREEN = 0x0400;
|
||||
byte idx = 0;
|
||||
|
||||
void print(struct Point p) {
|
||||
SCREEN[idx++] = p.x;
|
||||
SCREEN[idx++] = p.y;
|
||||
}
|
20
src/test/kc/struct-ptr-0.kc
Normal file
20
src/test/kc/struct-ptr-0.kc
Normal file
@ -0,0 +1,20 @@
|
||||
// Minimal struct - array of struct
|
||||
|
||||
struct Point {
|
||||
byte x;
|
||||
byte y;
|
||||
};
|
||||
|
||||
struct Point[4] points;
|
||||
|
||||
void main() {
|
||||
for( byte i: 0..4) {
|
||||
points[i].x = i;
|
||||
points[i].y = i+1;
|
||||
}
|
||||
const byte* SCREEN = 0x0400;
|
||||
for( byte i: 0..4) {
|
||||
SCREEN[i] = points[i].x;
|
||||
(SCREEN+40)[i] = points[i].y;
|
||||
}
|
||||
}
|
24
src/test/kc/struct-ptr-1.kc
Normal file
24
src/test/kc/struct-ptr-1.kc
Normal file
@ -0,0 +1,24 @@
|
||||
// Minimal struct - array of struct - near pointer math indexing
|
||||
|
||||
struct Point {
|
||||
byte x;
|
||||
byte y;
|
||||
};
|
||||
|
||||
struct Point[4] points;
|
||||
|
||||
const byte SIZEOF_POINT = 2;
|
||||
const byte OFFS_X = 0;
|
||||
const byte OFFS_Y = 1;
|
||||
|
||||
void main() {
|
||||
for( byte i: 0..3) {
|
||||
*((byte*)points+OFFS_X+i*SIZEOF_POINT) = i; // points[i].x = i;
|
||||
*((byte*)points+OFFS_Y+i*SIZEOF_POINT) = i+4; // points[i].y = i+4;
|
||||
}
|
||||
const byte* SCREEN = 0x0400;
|
||||
for( byte i: 0..3) {
|
||||
SCREEN[i] = *((byte*)points+OFFS_X+i*SIZEOF_POINT); // SCREEN[i] = points[i].x;
|
||||
(SCREEN+40)[i] = *((byte*)points+OFFS_Y+i*SIZEOF_POINT); // (SCREEN+40)[i] = points[i].y;
|
||||
}
|
||||
}
|
26
src/test/kc/struct-ptr-2.kc
Normal file
26
src/test/kc/struct-ptr-2.kc
Normal file
@ -0,0 +1,26 @@
|
||||
// Minimal struct - array of struct - far pointer math indexing
|
||||
|
||||
struct Point {
|
||||
byte x;
|
||||
byte y;
|
||||
};
|
||||
|
||||
struct Point[4] points;
|
||||
|
||||
const byte SIZEOF_POINT = 2;
|
||||
const byte OFFS_X = 0;
|
||||
const byte OFFS_Y = 1;
|
||||
|
||||
void main() {
|
||||
for( byte i: 0..3) {
|
||||
struct Point* point_i = points+i;
|
||||
*((byte*)point_i+OFFS_X) = i; // points[i].x = i;
|
||||
*((byte*)point_i+OFFS_Y) = i+4; // points[i].y = i+4;
|
||||
}
|
||||
const byte* SCREEN = 0x0400;
|
||||
for( byte i: 0..3) {
|
||||
struct Point* point_i = points+i;
|
||||
SCREEN[i] = *((byte*)point_i+OFFS_X); // SCREEN[i] = points[i].x;
|
||||
(SCREEN+40)[i] = *((byte*)point_i+OFFS_Y); // (SCREEN+40)[i] = points[i].y;
|
||||
}
|
||||
}
|
@ -1,39 +1,23 @@
|
||||
// Minimal struct - array of struct
|
||||
// Minimal struct - passing struct value parameter
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label SCREEN = $400
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label _5 = 2
|
||||
.label p1_y = 4
|
||||
ldx #0
|
||||
b1:
|
||||
txa
|
||||
asl
|
||||
sta _5
|
||||
tay
|
||||
txa
|
||||
sta points,y
|
||||
txa
|
||||
tay
|
||||
iny
|
||||
tya
|
||||
ldy _5
|
||||
sta points+1,y
|
||||
inx
|
||||
cpx #5
|
||||
bne b1
|
||||
ldy #0
|
||||
b2:
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
lda points,x
|
||||
sta SCREEN,y
|
||||
lda points+1,x
|
||||
sta SCREEN+$28,y
|
||||
iny
|
||||
cpy #5
|
||||
bne b2
|
||||
lda #1
|
||||
jsr print
|
||||
lda #2
|
||||
jsr print
|
||||
rts
|
||||
}
|
||||
// print(byte register(A) p_x)
|
||||
print: {
|
||||
sta SCREEN,x
|
||||
inx
|
||||
lda #main.p1_y
|
||||
sta SCREEN,x
|
||||
inx
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
@ -9,24 +9,23 @@
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] phi()
|
||||
[5] call print
|
||||
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 )
|
||||
[6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1
|
||||
[7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2
|
||||
[8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1
|
||||
[9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0
|
||||
[10] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[11] if((byte) main::i#1!=(byte) 5) 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 )
|
||||
[13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1
|
||||
[14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x
|
||||
[15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y
|
||||
[16] (byte) main::i1#1 ← ++ (byte) main::i1#2
|
||||
[17] if((byte) main::i1#1!=(byte) 5) goto main::@2
|
||||
main::@1: scope:[main] from main
|
||||
[6] phi()
|
||||
[7] call print
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[18] return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[8] return
|
||||
to:@return
|
||||
print: scope:[print] from main main::@1
|
||||
[9] (byte) idx#11 ← phi( main/(byte) 0 main::@1/(byte) idx#12 )
|
||||
[9] (byte) print::p_x#2 ← phi( main/(byte) 1 main::@1/(byte) 2 )
|
||||
[10] *((const byte*) SCREEN#0 + (byte) idx#11) ← (byte) print::p_x#2
|
||||
[11] (byte) idx#4 ← ++ (byte) idx#11
|
||||
[12] *((const byte*) SCREEN#0 + (byte) idx#4) ← (const byte) main::p1_y#1
|
||||
[13] (byte) idx#12 ← ++ (byte) idx#4
|
||||
to:print::@return
|
||||
print::@return: scope:[print] from print
|
||||
[14] return
|
||||
to:@return
|
||||
|
File diff suppressed because it is too large
Load Diff
39
src/test/ref/struct-ptr-0.asm
Normal file
39
src/test/ref/struct-ptr-0.asm
Normal file
@ -0,0 +1,39 @@
|
||||
// Minimal struct - array of struct
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label _5 = 2
|
||||
ldx #0
|
||||
b1:
|
||||
txa
|
||||
asl
|
||||
sta _5
|
||||
tay
|
||||
txa
|
||||
sta points,y
|
||||
txa
|
||||
tay
|
||||
iny
|
||||
tya
|
||||
ldy _5
|
||||
sta points+1,y
|
||||
inx
|
||||
cpx #5
|
||||
bne b1
|
||||
ldy #0
|
||||
b2:
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
lda points,x
|
||||
sta SCREEN,y
|
||||
lda points+1,x
|
||||
sta SCREEN+$28,y
|
||||
iny
|
||||
cpy #5
|
||||
bne b2
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
32
src/test/ref/struct-ptr-0.cfg
Normal file
32
src/test/ref/struct-ptr-0.cfg
Normal file
@ -0,0 +1,32 @@
|
||||
@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 )
|
||||
[6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1
|
||||
[7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2
|
||||
[8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1
|
||||
[9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0
|
||||
[10] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[11] if((byte) main::i#1!=(byte) 5) 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 )
|
||||
[13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1
|
||||
[14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x
|
||||
[15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y
|
||||
[16] (byte) main::i1#1 ← ++ (byte) main::i1#2
|
||||
[17] if((byte) main::i1#1!=(byte) 5) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[18] return
|
||||
to:@return
|
609
src/test/ref/struct-ptr-0.log
Normal file
609
src/test/ref/struct-ptr-0.log
Normal file
@ -0,0 +1,609 @@
|
||||
Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i)
|
||||
Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i)
|
||||
Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1)
|
||||
Fixing pointer array-indexing *((struct Point[4]) points + (byte) main::i1)
|
||||
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
|
||||
Culled Empty Block (label) main::@4
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(struct Point[4]) points#0 ← { fill( 4, 0) }
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(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 )
|
||||
(byte~) main::$4 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
*((struct Point[4]) points#0 + (byte~) main::$4).x ← (byte) main::i#2
|
||||
(number~) main::$0 ← (byte) main::i#2 + (number) 1
|
||||
(byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
*((struct Point[4]) points#0 + (byte~) main::$5).y ← (number~) main::$0
|
||||
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,4)
|
||||
(bool~) main::$1 ← (byte) main::i#1 != rangelast(0,4)
|
||||
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::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::$6 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
*((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$6).x
|
||||
(byte*~) main::$2 ← (byte*) main::SCREEN#0 + (number) $28
|
||||
(byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
*((byte*~) main::$2 + (byte) main::i1#2) ← *((struct Point[4]) points#0 + (byte~) main::$7).y
|
||||
(byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,4)
|
||||
(bool~) main::$3 ← (byte) main::i1#1 != rangelast(0,4)
|
||||
if((bool~) main::$3) 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
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(const byte) SIZEOF_STRUCT_POINT = (byte) 2
|
||||
(void()) main()
|
||||
(number~) main::$0
|
||||
(bool~) main::$1
|
||||
(byte*~) main::$2
|
||||
(bool~) main::$3
|
||||
(byte~) main::$4
|
||||
(byte~) main::$5
|
||||
(byte~) main::$6
|
||||
(byte~) main::$7
|
||||
(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
|
||||
(struct Point[4]) points
|
||||
(struct Point[4]) points#0
|
||||
|
||||
Adding number conversion cast (unumber) 1 in (number~) main::$0 ← (byte) main::i#2 + (number) 1
|
||||
Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::i#2 + (unumber)(number) 1
|
||||
Adding number conversion cast (unumber) $28 in (byte*~) main::$2 ← (byte*) main::SCREEN#0 + (number) $28
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant integer cast 1
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast $28
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 1
|
||||
Finalized unsigned number type (byte) $28
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::i#2 + (byte) 1
|
||||
Identified duplicate assignment right side [6] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
Identified duplicate assignment right side [17] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
Successful SSA optimization Pass2DuplicateRValueIdentification
|
||||
Simple Condition (bool~) main::$1 [10] if((byte) main::i#1!=rangelast(0,4)) goto main::@1
|
||||
Simple Condition (bool~) main::$3 [21] if((byte) main::i1#1!=rangelast(0,4)) goto main::@3
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) }
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const struct Point[4]) points#0 = { fill( 4, 0) }
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
|
||||
Constant (const byte) main::i1#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value [8] main::i#1 ← ++ main::i#2 to ++
|
||||
Resolved ranged comparison value [10] if(main::i#1!=rangelast(0,4)) goto main::@1 to (number) 5
|
||||
Resolved ranged next value [19] main::i1#1 ← ++ main::i1#2 to ++
|
||||
Resolved ranged comparison value [21] if(main::i1#1!=rangelast(0,4)) goto main::@3 to (number) 5
|
||||
Adding number conversion cast (unumber) 5 in if((byte) main::i#1!=(number) 5) goto main::@1
|
||||
Adding number conversion cast (unumber) 5 in if((byte) main::i1#1!=(number) 5) goto main::@3
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant integer cast 5
|
||||
Simplifying constant integer cast 5
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 5
|
||||
Finalized unsigned number type (byte) 5
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias (byte~) main::$5 = (byte~) main::$4
|
||||
Alias (byte~) main::$7 = (byte~) main::$6
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Constant right-side identified [11] (byte*~) main::$2 ← (const byte*) main::SCREEN#0 + (byte) $28
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte*) main::$2 = main::SCREEN#0+$28
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Rewriting multiplication to use shift [1] (byte~) main::$5 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
Rewriting multiplication to use shift [8] (byte~) main::$7 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
Successful SSA optimization Pass2MultiplyToShiftRewriting
|
||||
Inlining constant with var siblings (const byte) main::i#0
|
||||
Inlining constant with var siblings (const byte) main::i1#0
|
||||
Constant inlined main::i#0 = (byte) 0
|
||||
Constant inlined main::i1#0 = (byte) 0
|
||||
Constant inlined main::$2 = (const byte*) main::SCREEN#0+(byte) $28
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
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 2 initial phi equivalence classes
|
||||
Coalesced [21] main::i1#3 ← main::i1#1
|
||||
Coalesced [22] main::i#3 ← main::i#1
|
||||
Coalesced down to 2 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 )
|
||||
[6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1
|
||||
[7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2
|
||||
[8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1
|
||||
[9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0
|
||||
[10] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[11] if((byte) main::i#1!=(byte) 5) 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 )
|
||||
[13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1
|
||||
[14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x
|
||||
[15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y
|
||||
[16] (byte) main::i1#1 ← ++ (byte) main::i1#2
|
||||
[17] if((byte) main::i1#1!=(byte) 5) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[18] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(byte~) main::$0 22.0
|
||||
(byte~) main::$5 3.6666666666666665
|
||||
(byte~) main::$7 5.5
|
||||
(byte*) main::SCREEN
|
||||
(byte) main::i
|
||||
(byte) main::i#1 16.5
|
||||
(byte) main::i#2 11.0
|
||||
(byte) main::i1
|
||||
(byte) main::i1#1 16.5
|
||||
(byte) main::i1#2 13.75
|
||||
(struct Point[4]) points
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ main::i1#2 main::i1#1 ]
|
||||
Added variable main::$5 to zero page equivalence class [ main::$5 ]
|
||||
Added variable main::$0 to zero page equivalence class [ main::$0 ]
|
||||
Added variable main::$7 to zero page equivalence class [ main::$7 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ main::i1#2 main::i1#1 ]
|
||||
[ main::$5 ]
|
||||
[ main::$0 ]
|
||||
[ main::$7 ]
|
||||
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ]
|
||||
Allocated zp ZP_BYTE:4 [ main::$5 ]
|
||||
Allocated zp ZP_BYTE:5 [ main::$0 ]
|
||||
Allocated zp ZP_BYTE:6 [ main::$7 ]
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
.label _0 = 5
|
||||
.label _5 = 4
|
||||
.label _7 = 6
|
||||
.label i = 2
|
||||
.label i1 = 3
|
||||
//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
|
||||
jmp b1
|
||||
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
b1_from_b1:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda i
|
||||
asl
|
||||
sta _5
|
||||
//SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuz2
|
||||
lda i
|
||||
ldy _5
|
||||
sta points,y
|
||||
//SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuz1=vbuz2_plus_1
|
||||
ldy i
|
||||
iny
|
||||
sty _0
|
||||
//SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuz2
|
||||
lda _0
|
||||
ldy _5
|
||||
sta points+1,y
|
||||
//SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc i
|
||||
//SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #5
|
||||
cmp i
|
||||
bne b1_from_b1
|
||||
//SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
b2_from_b1:
|
||||
//SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta i1
|
||||
jmp b2
|
||||
//SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
b2_from_b2:
|
||||
//SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
jmp b2
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda i1
|
||||
asl
|
||||
sta _7
|
||||
//SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_0
|
||||
ldx _7
|
||||
lda points,x
|
||||
ldx i1
|
||||
sta SCREEN,x
|
||||
//SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuz1=pssc2_derefidx_vbuz2_mbr_1
|
||||
ldx _7
|
||||
lda points+1,x
|
||||
ldx i1
|
||||
sta SCREEN+$28,x
|
||||
//SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1
|
||||
inc i1
|
||||
//SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #5
|
||||
cmp i1
|
||||
bne b2_from_b2
|
||||
jmp breturn
|
||||
//SEG32 main::@return
|
||||
breturn:
|
||||
//SEG33 [18] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 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 ]
|
||||
Statement [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$5 ]
|
||||
Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ]
|
||||
Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::$7 ]
|
||||
Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a
|
||||
Statement [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a
|
||||
Statement [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 [ main::i#2 main::$5 ] ( main:2 [ main::i#2 main::$5 ] ) always clobbers reg byte a
|
||||
Statement [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a
|
||||
Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x [ main::i1#2 main::$7 ] ( main:2 [ main::i1#2 main::$7 ] ) always clobbers reg byte a
|
||||
Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) 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 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:4 [ main::$5 ] : zp ZP_BYTE:4 , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:5 [ main::$0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:6 [ main::$7 ] : zp ZP_BYTE:6 , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 30.25: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:5 [ main::$0 ] 5.5: zp ZP_BYTE:6 [ main::$7 ] 3.67: zp ZP_BYTE:4 [ main::$5 ]
|
||||
Uplift Scope [Point]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 918 combination reg byte y [ main::i1#2 main::i1#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte y [ main::$0 ] reg byte x [ main::$7 ] zp ZP_BYTE:4 [ main::$5 ]
|
||||
Limited combination testing to 100 combinations of 324 possible.
|
||||
Uplifting [Point] best 918 combination
|
||||
Uplifting [] best 918 combination
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ main::$5 ]
|
||||
Uplifting [main] best 918 combination zp ZP_BYTE:4 [ main::$5 ]
|
||||
Allocated (was zp ZP_BYTE:4) zp ZP_BYTE:2 [ main::$5 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
.label _5 = 2
|
||||
//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
|
||||
jmp b1
|
||||
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
b1_from_b1:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
sta _5
|
||||
//SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx
|
||||
ldy _5
|
||||
txa
|
||||
sta points,y
|
||||
//SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuyy=vbuxx_plus_1
|
||||
txa
|
||||
tay
|
||||
iny
|
||||
//SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy
|
||||
tya
|
||||
ldy _5
|
||||
sta points+1,y
|
||||
//SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #5
|
||||
bne b1_from_b1
|
||||
//SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
b2_from_b1:
|
||||
//SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1
|
||||
ldy #0
|
||||
jmp b2
|
||||
//SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
b2_from_b2:
|
||||
//SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
jmp b2
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
//SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0
|
||||
lda points,x
|
||||
sta SCREEN,y
|
||||
//SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1
|
||||
lda points+1,x
|
||||
sta SCREEN+$28,y
|
||||
//SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy
|
||||
iny
|
||||
//SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuyy_neq_vbuc1_then_la1
|
||||
cpy #5
|
||||
bne b2_from_b2
|
||||
jmp breturn
|
||||
//SEG32 main::@return
|
||||
breturn:
|
||||
//SEG33 [18] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
||||
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 ldy _5 with TAY
|
||||
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
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(byte~) main::$0 reg byte y 22.0
|
||||
(byte~) main::$5 $5 zp ZP_BYTE:2 3.6666666666666665
|
||||
(byte~) main::$7 reg byte x 5.5
|
||||
(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 11.0
|
||||
(byte) main::i1
|
||||
(byte) main::i1#1 reg byte y 16.5
|
||||
(byte) main::i1#2 reg byte y 13.75
|
||||
(struct Point[4]) points
|
||||
(const struct Point[4]) points#0 points = { fill( 4, 0) }
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte y [ main::i1#2 main::i1#1 ]
|
||||
zp ZP_BYTE:2 [ main::$5 ]
|
||||
reg byte y [ main::$0 ]
|
||||
reg byte x [ main::$7 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 746
|
||||
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
.label _5 = 2
|
||||
//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 from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$5 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
sta _5
|
||||
//SEG17 [7] *((const struct Point[4]) points#0 + (byte~) main::$5).x ← (byte) main::i#2 -- pssc1_derefidx_vbuz1_mbr_0=vbuxx
|
||||
tay
|
||||
txa
|
||||
sta points,y
|
||||
//SEG18 [8] (byte~) main::$0 ← (byte) main::i#2 + (byte) 1 -- vbuyy=vbuxx_plus_1
|
||||
txa
|
||||
tay
|
||||
iny
|
||||
//SEG19 [9] *((const struct Point[4]) points#0 + (byte~) main::$5).y ← (byte~) main::$0 -- pssc1_derefidx_vbuz1_mbr_1=vbuyy
|
||||
tya
|
||||
ldy _5
|
||||
sta points+1,y
|
||||
//SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG21 [11] if((byte) main::i#1!=(byte) 5) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #5
|
||||
bne b1
|
||||
//SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
//SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1
|
||||
ldy #0
|
||||
//SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
//SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [13] (byte~) main::$7 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
//SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).x -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_0
|
||||
lda points,x
|
||||
sta SCREEN,y
|
||||
//SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((const struct Point[4]) points#0 + (byte~) main::$7).y -- pbuc1_derefidx_vbuyy=pssc2_derefidx_vbuxx_mbr_1
|
||||
lda points+1,x
|
||||
sta SCREEN+$28,y
|
||||
//SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy
|
||||
iny
|
||||
//SEG31 [17] if((byte) main::i1#1!=(byte) 5) goto main::@2 -- vbuyy_neq_vbuc1_then_la1
|
||||
cpy #5
|
||||
bne b2
|
||||
//SEG32 main::@return
|
||||
//SEG33 [18] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
1
src/test/ref/struct-ptr-0.sym
Normal file
1
src/test/ref/struct-ptr-0.sym
Normal file
@ -0,0 +1 @@
|
||||
program
|
38
src/test/ref/struct-ptr-1.asm
Normal file
38
src/test/ref/struct-ptr-1.asm
Normal file
@ -0,0 +1,38 @@
|
||||
// Minimal struct - array of struct - near pointer math indexing
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const OFFS_Y = 1
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
ldx #0
|
||||
b1:
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
txa
|
||||
sta points,y
|
||||
txa
|
||||
clc
|
||||
adc #4
|
||||
// points[i].x = i;
|
||||
sta points+OFFS_Y,y
|
||||
inx
|
||||
cpx #4
|
||||
bne b1
|
||||
ldy #0
|
||||
b2:
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
lda points,x
|
||||
sta SCREEN,y
|
||||
// SCREEN[i] = points[i].x;
|
||||
lda points+OFFS_Y,x
|
||||
sta SCREEN+$28,y
|
||||
iny
|
||||
cpy #4
|
||||
bne b2
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
32
src/test/ref/struct-ptr-1.cfg
Normal file
32
src/test/ref/struct-ptr-1.cfg
Normal file
@ -0,0 +1,32 @@
|
||||
@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 )
|
||||
[6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1
|
||||
[7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2
|
||||
[8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4
|
||||
[9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8
|
||||
[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 )
|
||||
[13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1
|
||||
[14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17)
|
||||
[15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17)
|
||||
[16] (byte) main::i1#1 ← ++ (byte) main::i1#2
|
||||
[17] if((byte) main::i1#1!=(byte) 4) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[18] return
|
||||
to:@return
|
701
src/test/ref/struct-ptr-1.log
Normal file
701
src/test/ref/struct-ptr-1.log
Normal file
@ -0,0 +1,701 @@
|
||||
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
|
||||
Culled Empty Block (label) main::@4
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(struct Point[4]) points#0 ← { fill( 4, 0) }
|
||||
(byte) SIZEOF_POINT#0 ← (number) 2
|
||||
(byte) OFFS_X#0 ← (number) 0
|
||||
(byte) OFFS_Y#0 ← (number) 1
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(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 )
|
||||
(byte*~) main::$0 ← ((byte*)) (struct Point[4]) points#0
|
||||
(byte*~) main::$1 ← (byte*~) main::$0 + (byte) OFFS_X#0
|
||||
(byte~) main::$2 ← (byte) main::i#2 * (byte) SIZEOF_POINT#0
|
||||
(byte*~) main::$3 ← (byte*~) main::$1 + (byte~) main::$2
|
||||
*((byte*~) main::$3) ← (byte) main::i#2
|
||||
(byte*~) main::$4 ← ((byte*)) (struct Point[4]) points#0
|
||||
(byte*~) main::$5 ← (byte*~) main::$4 + (byte) OFFS_Y#0
|
||||
(byte~) main::$6 ← (byte) main::i#2 * (byte) SIZEOF_POINT#0
|
||||
(byte*~) main::$7 ← (byte*~) main::$5 + (byte~) main::$6
|
||||
(number~) main::$8 ← (byte) main::i#2 + (number) 4
|
||||
*((byte*~) main::$7) ← (number~) main::$8
|
||||
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,3)
|
||||
(bool~) main::$9 ← (byte) main::i#1 != rangelast(0,3)
|
||||
if((bool~) main::$9) goto main::@1
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
|
||||
(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::$10 ← ((byte*)) (struct Point[4]) points#0
|
||||
(byte*~) main::$11 ← (byte*~) main::$10 + (byte) OFFS_X#0
|
||||
(byte~) main::$12 ← (byte) main::i1#2 * (byte) SIZEOF_POINT#0
|
||||
(byte*~) main::$13 ← (byte*~) main::$11 + (byte~) main::$12
|
||||
*((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$13)
|
||||
(byte*~) main::$14 ← (byte*) main::SCREEN#0 + (number) $28
|
||||
(byte*~) main::$15 ← ((byte*)) (struct Point[4]) points#0
|
||||
(byte*~) main::$16 ← (byte*~) main::$15 + (byte) OFFS_Y#0
|
||||
(byte~) main::$17 ← (byte) main::i1#2 * (byte) SIZEOF_POINT#0
|
||||
(byte*~) main::$18 ← (byte*~) main::$16 + (byte~) main::$17
|
||||
*((byte*~) main::$14 + (byte) main::i1#2) ← *((byte*~) main::$18)
|
||||
(byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,3)
|
||||
(bool~) main::$19 ← (byte) main::i1#1 != rangelast(0,3)
|
||||
if((bool~) main::$19) 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
|
||||
(byte) OFFS_X
|
||||
(byte) OFFS_X#0
|
||||
(byte) OFFS_Y
|
||||
(byte) OFFS_Y#0
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(byte) SIZEOF_POINT
|
||||
(byte) SIZEOF_POINT#0
|
||||
(void()) main()
|
||||
(byte*~) main::$0
|
||||
(byte*~) main::$1
|
||||
(byte*~) main::$10
|
||||
(byte*~) main::$11
|
||||
(byte~) main::$12
|
||||
(byte*~) main::$13
|
||||
(byte*~) main::$14
|
||||
(byte*~) main::$15
|
||||
(byte*~) main::$16
|
||||
(byte~) main::$17
|
||||
(byte*~) main::$18
|
||||
(bool~) main::$19
|
||||
(byte~) main::$2
|
||||
(byte*~) main::$3
|
||||
(byte*~) main::$4
|
||||
(byte*~) main::$5
|
||||
(byte~) main::$6
|
||||
(byte*~) main::$7
|
||||
(number~) main::$8
|
||||
(bool~) main::$9
|
||||
(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
|
||||
(struct Point[4]) points
|
||||
(struct Point[4]) points#0
|
||||
|
||||
Adding number conversion cast (unumber) 2 in (byte) SIZEOF_POINT#0 ← (number) 2
|
||||
Adding number conversion cast (unumber) 0 in (byte) OFFS_X#0 ← (number) 0
|
||||
Adding number conversion cast (unumber) 1 in (byte) OFFS_Y#0 ← (number) 1
|
||||
Adding number conversion cast (unumber) 4 in (number~) main::$8 ← (byte) main::i#2 + (number) 4
|
||||
Adding number conversion cast (unumber) main::$8 in (number~) main::$8 ← (byte) main::i#2 + (unumber)(number) 4
|
||||
Adding number conversion cast (unumber) $28 in (byte*~) main::$14 ← (byte*) main::SCREEN#0 + (number) $28
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast (byte) SIZEOF_POINT#0 ← (unumber)(number) 2
|
||||
Inlining cast (byte) OFFS_X#0 ← (unumber)(number) 0
|
||||
Inlining cast (byte) OFFS_Y#0 ← (unumber)(number) 1
|
||||
Inlining cast (byte*~) main::$0 ← (byte*)(struct Point[4]) points#0
|
||||
Inlining cast (byte*~) main::$4 ← (byte*)(struct Point[4]) points#0
|
||||
Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400
|
||||
Inlining cast (byte*~) main::$10 ← (byte*)(struct Point[4]) points#0
|
||||
Inlining cast (byte*~) main::$15 ← (byte*)(struct Point[4]) points#0
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant integer cast 2
|
||||
Simplifying constant integer cast 0
|
||||
Simplifying constant integer cast 1
|
||||
Simplifying constant integer cast 4
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast $28
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 2
|
||||
Finalized unsigned number type (byte) 0
|
||||
Finalized unsigned number type (byte) 1
|
||||
Finalized unsigned number type (byte) 4
|
||||
Finalized unsigned number type (byte) $28
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inferred type updated to byte in (unumber~) main::$8 ← (byte) main::i#2 + (byte) 4
|
||||
Identified duplicate assignment right side [13] (byte~) main::$6 ← (byte) main::i#2 * (byte) SIZEOF_POINT#0
|
||||
Identified duplicate assignment right side [31] (byte~) main::$17 ← (byte) main::i1#2 * (byte) SIZEOF_POINT#0
|
||||
Successful SSA optimization Pass2DuplicateRValueIdentification
|
||||
Simple Condition (bool~) main::$9 [19] if((byte) main::i#1!=rangelast(0,3)) goto main::@1
|
||||
Simple Condition (bool~) main::$19 [36] if((byte) main::i1#1!=rangelast(0,3)) goto main::@3
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) }
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const struct Point[4]) points#0 = { fill( 4, 0) }
|
||||
Constant (const byte) SIZEOF_POINT#0 = 2
|
||||
Constant (const byte) OFFS_X#0 = 0
|
||||
Constant (const byte) OFFS_Y#0 = 1
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
|
||||
Constant (const byte) main::i1#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant value identified (byte*)points#0 in [6] (byte*~) main::$0 ← (byte*)(const struct Point[4]) points#0
|
||||
Constant value identified (byte*)points#0 in [11] (byte*~) main::$4 ← (byte*)(const struct Point[4]) points#0
|
||||
Constant value identified (byte*)points#0 in [23] (byte*~) main::$10 ← (byte*)(const struct Point[4]) points#0
|
||||
Constant value identified (byte*)points#0 in [29] (byte*~) main::$15 ← (byte*)(const struct Point[4]) points#0
|
||||
Successful SSA optimization Pass2ConstantValues
|
||||
Resolved ranged next value [17] main::i#1 ← ++ main::i#2 to ++
|
||||
Resolved ranged comparison value [19] if(main::i#1!=rangelast(0,3)) goto main::@1 to (number) 4
|
||||
Resolved ranged next value [34] main::i1#1 ← ++ main::i1#2 to ++
|
||||
Resolved ranged comparison value [36] if(main::i1#1!=rangelast(0,3)) goto main::@3 to (number) 4
|
||||
Converting *(pointer+n) to pointer[n] [10] *((byte*~) main::$3) ← (byte) main::i#2 -- *(main::$1 + main::$2)
|
||||
Converting *(pointer+n) to pointer[n] [16] *((byte*~) main::$7) ← (byte~) main::$8 -- *(main::$5 + main::$6)
|
||||
Converting *(pointer+n) to pointer[n] [27] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$13) -- *(main::$11 + main::$12)
|
||||
Converting *(pointer+n) to pointer[n] [33] *((byte*~) main::$14 + (byte) main::i1#2) ← *((byte*~) main::$18) -- *(main::$16 + main::$17)
|
||||
Successful SSA optimization Pass2InlineDerefIdx
|
||||
Simplifying expression containing zero main::$0 in [7] (byte*~) main::$1 ← (byte*~) main::$0 + (const byte) OFFS_X#0
|
||||
Simplifying expression containing zero main::$10 in [24] (byte*~) main::$11 ← (byte*~) main::$10 + (const byte) OFFS_X#0
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused variable (byte*~) main::$3 and assignment [4] (byte*~) main::$3 ← (byte*~) main::$1 + (byte~) main::$2
|
||||
Eliminating unused variable (byte*~) main::$7 and assignment [9] (byte*~) main::$7 ← (byte*~) main::$5 + (byte~) main::$6
|
||||
Eliminating unused variable (byte*~) main::$13 and assignment [18] (byte*~) main::$13 ← (byte*~) main::$11 + (byte~) main::$12
|
||||
Eliminating unused variable (byte*~) main::$18 and assignment [24] (byte*~) main::$18 ← (byte*~) main::$16 + (byte~) main::$17
|
||||
Eliminating unused constant (const byte) OFFS_X#0
|
||||
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
|
||||
Alias (byte*~) main::$1 = (byte*~) main::$0
|
||||
Alias (byte~) main::$6 = (byte~) main::$2
|
||||
Alias (byte*~) main::$11 = (byte*~) main::$10
|
||||
Alias (byte~) main::$17 = (byte~) main::$12
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Constant right-side identified [17] (byte*~) main::$14 ← (const byte*) main::SCREEN#0 + (byte) $28
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte*) main::$1 = (byte*)points#0
|
||||
Constant (const byte*) main::$4 = (byte*)points#0
|
||||
Constant (const byte*) main::$11 = (byte*)points#0
|
||||
Constant (const byte*) main::$14 = main::SCREEN#0+$28
|
||||
Constant (const byte*) main::$15 = (byte*)points#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Constant right-side identified [3] (byte*~) main::$5 ← (const byte*) main::$4 + (const byte) OFFS_Y#0
|
||||
Constant right-side identified [11] (byte*~) main::$16 ← (const byte*) main::$15 + (const byte) OFFS_Y#0
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte*) main::$5 = main::$4+OFFS_Y#0
|
||||
Constant (const byte*) main::$16 = main::$15+OFFS_Y#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Rewriting multiplication to use shift [1] (byte~) main::$6 ← (byte) main::i#2 * (const byte) SIZEOF_POINT#0
|
||||
Rewriting multiplication to use shift [8] (byte~) main::$17 ← (byte) main::i1#2 * (const byte) SIZEOF_POINT#0
|
||||
Successful SSA optimization Pass2MultiplyToShiftRewriting
|
||||
Inlining constant with var siblings (const byte) main::i#0
|
||||
Inlining constant with var siblings (const byte) main::i1#0
|
||||
Constant inlined main::$1 = (byte*)(const struct Point[4]) points#0
|
||||
Constant inlined main::$16 = (byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0
|
||||
Constant inlined main::$5 = (byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0
|
||||
Constant inlined main::i#0 = (byte) 0
|
||||
Constant inlined main::i1#0 = (byte) 0
|
||||
Constant inlined main::$14 = (const byte*) main::SCREEN#0+(byte) $28
|
||||
Constant inlined main::$4 = (byte*)(const struct Point[4]) points#0
|
||||
Constant inlined main::$15 = (byte*)(const struct Point[4]) points#0
|
||||
Constant inlined main::$11 = (byte*)(const struct Point[4]) points#0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Eliminating unused constant (const byte) SIZEOF_POINT#0
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
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 2 initial phi equivalence classes
|
||||
Coalesced [21] main::i1#3 ← main::i1#1
|
||||
Coalesced [22] main::i#3 ← main::i#1
|
||||
Coalesced down to 2 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 )
|
||||
[6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1
|
||||
[7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2
|
||||
[8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4
|
||||
[9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8
|
||||
[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 )
|
||||
[13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1
|
||||
[14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17)
|
||||
[15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17)
|
||||
[16] (byte) main::i1#1 ← ++ (byte) main::i1#2
|
||||
[17] if((byte) main::i1#1!=(byte) 4) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[18] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte) OFFS_X
|
||||
(byte) OFFS_Y
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(byte) SIZEOF_POINT
|
||||
(void()) main()
|
||||
(byte~) main::$17 16.5
|
||||
(byte~) main::$6 11.0
|
||||
(byte~) main::$8 22.0
|
||||
(byte*) main::SCREEN
|
||||
(byte) main::i
|
||||
(byte) main::i#1 16.5
|
||||
(byte) main::i#2 11.0
|
||||
(byte) main::i1
|
||||
(byte) main::i1#1 16.5
|
||||
(byte) main::i1#2 13.75
|
||||
(struct Point[4]) points
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ main::i1#2 main::i1#1 ]
|
||||
Added variable main::$6 to zero page equivalence class [ main::$6 ]
|
||||
Added variable main::$8 to zero page equivalence class [ main::$8 ]
|
||||
Added variable main::$17 to zero page equivalence class [ main::$17 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ main::i1#2 main::i1#1 ]
|
||||
[ main::$6 ]
|
||||
[ main::$8 ]
|
||||
[ main::$17 ]
|
||||
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ]
|
||||
Allocated zp ZP_BYTE:4 [ main::$6 ]
|
||||
Allocated zp ZP_BYTE:5 [ main::$8 ]
|
||||
Allocated zp ZP_BYTE:6 [ main::$17 ]
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct - near pointer math indexing
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFS_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
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
.label _6 = 4
|
||||
.label _8 = 5
|
||||
.label _17 = 6
|
||||
.label i = 2
|
||||
.label i1 = 3
|
||||
//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
|
||||
jmp b1
|
||||
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
b1_from_b1:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda i
|
||||
asl
|
||||
sta _6
|
||||
//SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 -- pbuc1_derefidx_vbuz1=vbuz2
|
||||
lda i
|
||||
ldy _6
|
||||
sta points,y
|
||||
//SEG18 [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 -- vbuz1=vbuz2_plus_vbuc1
|
||||
lax i
|
||||
axs #-[4]
|
||||
stx _8
|
||||
//SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 -- pbuc1_derefidx_vbuz1=vbuz2
|
||||
// points[i].x = i;
|
||||
lda _8
|
||||
ldy _6
|
||||
sta points+OFFS_Y,y
|
||||
//SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc i
|
||||
//SEG21 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #4
|
||||
cmp i
|
||||
bne b1_from_b1
|
||||
//SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
b2_from_b1:
|
||||
//SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta i1
|
||||
jmp b2
|
||||
//SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
b2_from_b2:
|
||||
//SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
jmp b2
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda i1
|
||||
asl
|
||||
sta _17
|
||||
//SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2
|
||||
ldy _17
|
||||
lda points,y
|
||||
ldy i1
|
||||
sta SCREEN,y
|
||||
//SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2
|
||||
// SCREEN[i] = points[i].x;
|
||||
ldy _17
|
||||
lda points+OFFS_Y,y
|
||||
ldy i1
|
||||
sta SCREEN+$28,y
|
||||
//SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1
|
||||
inc i1
|
||||
//SEG31 [17] 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
|
||||
//SEG32 main::@return
|
||||
breturn:
|
||||
//SEG33 [18] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) 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 ]
|
||||
Statement [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$6 ]
|
||||
Statement [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::$6 main::$8 ] ( main:2 [ main::i#2 main::$6 main::$8 ] ) always clobbers reg byte a
|
||||
Statement [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ]
|
||||
Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:6 [ main::$17 ]
|
||||
Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a
|
||||
Statement [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) always clobbers reg byte a
|
||||
Statement [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 [ main::i#2 main::$6 ] ( main:2 [ main::i#2 main::$6 ] ) always clobbers reg byte a
|
||||
Statement [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::$6 main::$8 ] ( main:2 [ main::i#2 main::$6 main::$8 ] ) always clobbers reg byte a
|
||||
Statement [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a
|
||||
Statement [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) [ main::i1#2 main::$17 ] ( main:2 [ main::i1#2 main::$17 ] ) always clobbers reg byte a
|
||||
Statement [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) 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 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:4 [ main::$6 ] : zp ZP_BYTE:4 , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:5 [ main::$8 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:6 [ main::$17 ] : zp ZP_BYTE:6 , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 30.25: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 27.5: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:5 [ main::$8 ] 16.5: zp ZP_BYTE:6 [ main::$17 ] 11: zp ZP_BYTE:4 [ main::$6 ]
|
||||
Uplift Scope [Point]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 898 combination reg byte y [ main::i1#2 main::i1#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$8 ] reg byte x [ main::$17 ] zp ZP_BYTE:4 [ main::$6 ]
|
||||
Limited combination testing to 100 combinations of 324 possible.
|
||||
Uplifting [Point] best 898 combination
|
||||
Uplifting [] best 898 combination
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ main::$6 ]
|
||||
Uplifting [main] best 828 combination reg byte y [ main::$6 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct - near pointer math indexing
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFS_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
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
//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
|
||||
jmp b1
|
||||
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
b1_from_b1:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
//SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx
|
||||
txa
|
||||
sta points,y
|
||||
//SEG18 [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1
|
||||
txa
|
||||
clc
|
||||
adc #4
|
||||
//SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 -- pbuc1_derefidx_vbuyy=vbuaa
|
||||
// points[i].x = i;
|
||||
sta points+OFFS_Y,y
|
||||
//SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG21 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #4
|
||||
bne b1_from_b1
|
||||
//SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
b2_from_b1:
|
||||
//SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1
|
||||
ldy #0
|
||||
jmp b2
|
||||
//SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
b2_from_b2:
|
||||
//SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
jmp b2
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
//SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx
|
||||
lda points,x
|
||||
sta SCREEN,y
|
||||
//SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx
|
||||
// SCREEN[i] = points[i].x;
|
||||
lda points+OFFS_Y,x
|
||||
sta SCREEN+$28,y
|
||||
//SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy
|
||||
iny
|
||||
//SEG31 [17] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuyy_neq_vbuc1_then_la1
|
||||
cpy #4
|
||||
bne b2_from_b2
|
||||
jmp breturn
|
||||
//SEG32 main::@return
|
||||
breturn:
|
||||
//SEG33 [18] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
||||
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 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
|
||||
(byte) OFFS_X
|
||||
(byte) OFFS_Y
|
||||
(const byte) OFFS_Y#0 OFFS_Y = (byte) 1
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(byte) SIZEOF_POINT
|
||||
(void()) main()
|
||||
(byte~) main::$17 reg byte x 16.5
|
||||
(byte~) main::$6 reg byte y 11.0
|
||||
(byte~) main::$8 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 11.0
|
||||
(byte) main::i1
|
||||
(byte) main::i1#1 reg byte y 16.5
|
||||
(byte) main::i1#2 reg byte y 13.75
|
||||
(struct Point[4]) points
|
||||
(const struct Point[4]) points#0 points = { fill( 4, 0) }
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte y [ main::i1#2 main::i1#1 ]
|
||||
reg byte y [ main::$6 ]
|
||||
reg byte a [ main::$8 ]
|
||||
reg byte x [ main::$17 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 666
|
||||
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct - near pointer math indexing
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFS_Y = 1
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
//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 from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$6 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
//SEG17 [7] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$6) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx
|
||||
txa
|
||||
sta points,y
|
||||
//SEG18 [8] (byte~) main::$8 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1
|
||||
txa
|
||||
clc
|
||||
adc #4
|
||||
//SEG19 [9] *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$6) ← (byte~) main::$8 -- pbuc1_derefidx_vbuyy=vbuaa
|
||||
// points[i].x = i;
|
||||
sta points+OFFS_Y,y
|
||||
//SEG20 [10] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG21 [11] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #4
|
||||
bne b1
|
||||
//SEG22 [12] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
//SEG23 [12] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1
|
||||
ldy #0
|
||||
//SEG24 [12] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
//SEG25 [12] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [13] (byte~) main::$17 ← (byte) main::i1#2 << (byte) 1 -- vbuxx=vbuyy_rol_1
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
//SEG28 [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx
|
||||
lda points,x
|
||||
sta SCREEN,y
|
||||
//SEG29 [15] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0+(const byte) OFFS_Y#0 + (byte~) main::$17) -- pbuc1_derefidx_vbuyy=pbuc2_derefidx_vbuxx
|
||||
// SCREEN[i] = points[i].x;
|
||||
lda points+OFFS_Y,x
|
||||
sta SCREEN+$28,y
|
||||
//SEG30 [16] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuyy=_inc_vbuyy
|
||||
iny
|
||||
//SEG31 [17] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuyy_neq_vbuc1_then_la1
|
||||
cpy #4
|
||||
bne b2
|
||||
//SEG32 main::@return
|
||||
//SEG33 [18] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
1
src/test/ref/struct-ptr-1.sym
Normal file
1
src/test/ref/struct-ptr-1.sym
Normal file
@ -0,0 +1 @@
|
||||
program
|
56
src/test/ref/struct-ptr-2.asm
Normal file
56
src/test/ref/struct-ptr-2.asm
Normal file
@ -0,0 +1,56 @@
|
||||
// Minimal struct - array of struct - far pointer math indexing
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.const OFFS_Y = 1
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label point_i = 2
|
||||
.label point_i1 = 4
|
||||
ldx #0
|
||||
b1:
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
tya
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i+1
|
||||
txa
|
||||
sta points,y
|
||||
txa
|
||||
clc
|
||||
adc #4
|
||||
// points[i].x = i;
|
||||
ldy #OFFS_Y
|
||||
sta (point_i),y
|
||||
inx
|
||||
cpx #4
|
||||
bne b1
|
||||
ldx #0
|
||||
b2:
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
tya
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i1
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i1+1
|
||||
lda points,y
|
||||
sta SCREEN,x
|
||||
// SCREEN[i] = points[i].x;
|
||||
ldy #OFFS_Y
|
||||
lda (point_i1),y
|
||||
sta SCREEN+$28,x
|
||||
inx
|
||||
cpx #4
|
||||
bne b2
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
34
src/test/ref/struct-ptr-2.cfg
Normal file
34
src/test/ref/struct-ptr-2.cfg
Normal file
@ -0,0 +1,34 @@
|
||||
@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 )
|
||||
[6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1
|
||||
[7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14
|
||||
[8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2
|
||||
[9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4
|
||||
[10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5
|
||||
[11] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[12] if((byte) main::i#1!=(byte) 4) goto main::@1
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1 main::@2
|
||||
[13] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 )
|
||||
[14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1
|
||||
[15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15
|
||||
[16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15)
|
||||
[17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0)
|
||||
[18] (byte) main::i1#1 ← ++ (byte) main::i1#2
|
||||
[19] if((byte) main::i1#1!=(byte) 4) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[20] return
|
||||
to:@return
|
768
src/test/ref/struct-ptr-2.log
Normal file
768
src/test/ref/struct-ptr-2.log
Normal file
@ -0,0 +1,768 @@
|
||||
Fixing pointer addition (struct Point*~) main::$0 ← (struct Point[4]) points + (byte) main::i
|
||||
Fixing pointer addition (struct Point*~) main::$7 ← (struct Point[4]) points + (byte) main::i1
|
||||
Adding pointer type conversion cast (byte*) main::SCREEN in (byte*) main::SCREEN ← (number) $400
|
||||
Culled Empty Block (label) main::@4
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
(struct Point[4]) points#0 ← { fill( 4, 0) }
|
||||
(byte) OFFS_X#0 ← (number) 0
|
||||
(byte) OFFS_Y#0 ← (number) 1
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(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 )
|
||||
(byte~) main::$14 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
(struct Point*~) main::$0 ← (struct Point[4]) points#0 + (byte~) main::$14
|
||||
(struct Point*) main::point_i#0 ← (struct Point*~) main::$0
|
||||
(byte*~) main::$1 ← ((byte*)) (struct Point*) main::point_i#0
|
||||
(byte*~) main::$2 ← (byte*~) main::$1 + (byte) OFFS_X#0
|
||||
*((byte*~) main::$2) ← (byte) main::i#2
|
||||
(byte*~) main::$3 ← ((byte*)) (struct Point*) main::point_i#0
|
||||
(byte*~) main::$4 ← (byte*~) main::$3 + (byte) OFFS_Y#0
|
||||
(number~) main::$5 ← (byte) main::i#2 + (number) 4
|
||||
*((byte*~) main::$4) ← (number~) main::$5
|
||||
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,3)
|
||||
(bool~) main::$6 ← (byte) main::i#1 != rangelast(0,3)
|
||||
if((bool~) main::$6) goto main::@1
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte*) main::SCREEN#0 ← ((byte*)) (number) $400
|
||||
(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::$15 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
(struct Point*~) main::$7 ← (struct Point[4]) points#0 + (byte~) main::$15
|
||||
(struct Point*) main::point_i1#0 ← (struct Point*~) main::$7
|
||||
(byte*~) main::$8 ← ((byte*)) (struct Point*) main::point_i1#0
|
||||
(byte*~) main::$9 ← (byte*~) main::$8 + (byte) OFFS_X#0
|
||||
*((byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$9)
|
||||
(byte*~) main::$10 ← (byte*) main::SCREEN#0 + (number) $28
|
||||
(byte*~) main::$11 ← ((byte*)) (struct Point*) main::point_i1#0
|
||||
(byte*~) main::$12 ← (byte*~) main::$11 + (byte) OFFS_Y#0
|
||||
*((byte*~) main::$10 + (byte) main::i1#2) ← *((byte*~) main::$12)
|
||||
(byte) main::i1#1 ← (byte) main::i1#2 + rangenext(0,3)
|
||||
(bool~) main::$13 ← (byte) main::i1#1 != rangelast(0,3)
|
||||
if((bool~) main::$13) 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
|
||||
(byte) OFFS_X
|
||||
(byte) OFFS_X#0
|
||||
(byte) OFFS_Y
|
||||
(byte) OFFS_Y#0
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(const byte) SIZEOF_STRUCT_POINT = (byte) 2
|
||||
(void()) main()
|
||||
(struct Point*~) main::$0
|
||||
(byte*~) main::$1
|
||||
(byte*~) main::$10
|
||||
(byte*~) main::$11
|
||||
(byte*~) main::$12
|
||||
(bool~) main::$13
|
||||
(byte~) main::$14
|
||||
(byte~) main::$15
|
||||
(byte*~) main::$2
|
||||
(byte*~) main::$3
|
||||
(byte*~) main::$4
|
||||
(number~) main::$5
|
||||
(bool~) main::$6
|
||||
(struct Point*~) main::$7
|
||||
(byte*~) main::$8
|
||||
(byte*~) main::$9
|
||||
(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
|
||||
(struct Point*) main::point_i
|
||||
(struct Point*) main::point_i#0
|
||||
(struct Point*) main::point_i1
|
||||
(struct Point*) main::point_i1#0
|
||||
(struct Point[4]) points
|
||||
(struct Point[4]) points#0
|
||||
|
||||
Adding number conversion cast (unumber) 0 in (byte) OFFS_X#0 ← (number) 0
|
||||
Adding number conversion cast (unumber) 1 in (byte) OFFS_Y#0 ← (number) 1
|
||||
Adding number conversion cast (unumber) 4 in (number~) main::$5 ← (byte) main::i#2 + (number) 4
|
||||
Adding number conversion cast (unumber) main::$5 in (number~) main::$5 ← (byte) main::i#2 + (unumber)(number) 4
|
||||
Adding number conversion cast (unumber) $28 in (byte*~) main::$10 ← (byte*) main::SCREEN#0 + (number) $28
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Inlining cast (byte) OFFS_X#0 ← (unumber)(number) 0
|
||||
Inlining cast (byte) OFFS_Y#0 ← (unumber)(number) 1
|
||||
Inlining cast (byte*~) main::$1 ← (byte*)(struct Point*) main::point_i#0
|
||||
Inlining cast (byte*~) main::$3 ← (byte*)(struct Point*) main::point_i#0
|
||||
Inlining cast (byte*) main::SCREEN#0 ← (byte*)(number) $400
|
||||
Inlining cast (byte*~) main::$8 ← (byte*)(struct Point*) main::point_i1#0
|
||||
Inlining cast (byte*~) main::$11 ← (byte*)(struct Point*) main::point_i1#0
|
||||
Successful SSA optimization Pass2InlineCast
|
||||
Simplifying constant integer cast 0
|
||||
Simplifying constant integer cast 1
|
||||
Simplifying constant integer cast 4
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast $28
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) 0
|
||||
Finalized unsigned number type (byte) 1
|
||||
Finalized unsigned number type (byte) 4
|
||||
Finalized unsigned number type (byte) $28
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Inferred type updated to byte in (unumber~) main::$5 ← (byte) main::i#2 + (byte) 4
|
||||
Alias (struct Point*) main::point_i#0 = (struct Point*~) main::$0
|
||||
Alias (struct Point*) main::point_i1#0 = (struct Point*~) main::$7
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition (bool~) main::$6 [17] if((byte) main::i#1!=rangelast(0,3)) goto main::@1
|
||||
Simple Condition (bool~) main::$13 [33] if((byte) main::i1#1!=rangelast(0,3)) goto main::@3
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant right-side identified [0] (struct Point[4]) points#0 ← { fill( 4, 0) }
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const struct Point[4]) points#0 = { fill( 4, 0) }
|
||||
Constant (const byte) OFFS_X#0 = 0
|
||||
Constant (const byte) OFFS_Y#0 = 1
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte*) main::SCREEN#0 = (byte*) 1024
|
||||
Constant (const byte) main::i1#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value [15] main::i#1 ← ++ main::i#2 to ++
|
||||
Resolved ranged comparison value [17] if(main::i#1!=rangelast(0,3)) goto main::@1 to (number) 4
|
||||
Resolved ranged next value [31] main::i1#1 ← ++ main::i1#2 to ++
|
||||
Resolved ranged comparison value [33] if(main::i1#1!=rangelast(0,3)) goto main::@3 to (number) 4
|
||||
Converting *(pointer+n) to pointer[n] [10] *((byte*~) main::$2) ← (byte) main::i#2 -- *(main::$1 + OFFS_X#0)
|
||||
Converting *(pointer+n) to pointer[n] [14] *((byte*~) main::$4) ← (byte~) main::$5 -- *(main::$3 + OFFS_Y#0)
|
||||
Converting *(pointer+n) to pointer[n] [26] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$9) -- *(main::$8 + OFFS_X#0)
|
||||
Converting *(pointer+n) to pointer[n] [30] *((byte*~) main::$10 + (byte) main::i1#2) ← *((byte*~) main::$12) -- *(main::$11 + OFFS_Y#0)
|
||||
Successful SSA optimization Pass2InlineDerefIdx
|
||||
Simplifying expression containing zero main::$1 in [9] (byte*~) main::$2 ← (byte*~) main::$1 + (const byte) OFFS_X#0
|
||||
Simplifying expression containing zero main::$1 in [10] *((byte*~) main::$1 + (const byte) OFFS_X#0) ← (byte) main::i#2
|
||||
Simplifying expression containing zero main::$8 in [25] (byte*~) main::$9 ← (byte*~) main::$8 + (const byte) OFFS_X#0
|
||||
Simplifying expression containing zero main::$8 in [26] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$8 + (const byte) OFFS_X#0)
|
||||
Successful SSA optimization PassNSimplifyExpressionWithZero
|
||||
Eliminating unused variable (byte*~) main::$2 and assignment [4] (byte*~) main::$2 ← (byte*~) main::$1
|
||||
Eliminating unused variable (byte*~) main::$4 and assignment [7] (byte*~) main::$4 ← (byte*~) main::$3 + (const byte) OFFS_Y#0
|
||||
Eliminating unused variable (byte*~) main::$9 and assignment [16] (byte*~) main::$9 ← (byte*~) main::$8
|
||||
Eliminating unused variable (byte*~) main::$12 and assignment [20] (byte*~) main::$12 ← (byte*~) main::$11 + (const byte) OFFS_Y#0
|
||||
Eliminating unused constant (const byte) OFFS_X#0
|
||||
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
|
||||
Constant right-side identified [15] (byte*~) main::$10 ← (const byte*) main::SCREEN#0 + (byte) $28
|
||||
Successful SSA optimization Pass2ConstantRValueConsolidation
|
||||
Constant (const byte*) main::$10 = main::SCREEN#0+$28
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Converting *(pointer+n) to pointer[n] [4] *((byte*~) main::$1) ← (byte) main::i#2 -- *((byte*)points#0 + main::$14)
|
||||
Converting *(pointer+n) to pointer[n] [14] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*~) main::$8) -- *((byte*)points#0 + main::$15)
|
||||
Successful SSA optimization Pass2InlineDerefIdx
|
||||
Eliminating unused variable (byte*~) main::$1 and assignment [3] (byte*~) main::$1 ← (byte*)(struct Point*) main::point_i#0
|
||||
Eliminating unused variable (byte*~) main::$8 and assignment [13] (byte*~) main::$8 ← (byte*)(struct Point*) main::point_i1#0
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
Constant value identified (byte*)points#0 in [3] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2
|
||||
Constant value identified (byte*)points#0 in [12] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15)
|
||||
Successful SSA optimization Pass2ConstantValues
|
||||
Inlining Noop Cast [4] (byte*~) main::$3 ← (byte*)(struct Point*) main::point_i#0 keeping main::point_i#0
|
||||
Inlining Noop Cast [13] (byte*~) main::$11 ← (byte*)(struct Point*) main::point_i1#0 keeping main::point_i1#0
|
||||
Successful SSA optimization Pass2NopCastInlining
|
||||
Rewriting multiplication to use shift [1] (byte~) main::$14 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
Rewriting multiplication to use shift [10] (byte~) main::$15 ← (byte) main::i1#2 * (const byte) SIZEOF_STRUCT_POINT
|
||||
Successful SSA optimization Pass2MultiplyToShiftRewriting
|
||||
Inlining constant with var siblings (const byte) main::i#0
|
||||
Inlining constant with var siblings (const byte) main::i1#0
|
||||
Constant inlined main::i#0 = (byte) 0
|
||||
Constant inlined main::i1#0 = (byte) 0
|
||||
Constant inlined main::$10 = (const byte*) main::SCREEN#0+(byte) $28
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Eliminating unused constant (const byte) SIZEOF_STRUCT_POINT
|
||||
Successful SSA optimization PassNEliminateUnusedVars
|
||||
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 2 initial phi equivalence classes
|
||||
Coalesced [23] main::i1#3 ← main::i1#1
|
||||
Coalesced [24] main::i#3 ← main::i#1
|
||||
Coalesced down to 2 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 )
|
||||
[6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1
|
||||
[7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14
|
||||
[8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2
|
||||
[9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4
|
||||
[10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5
|
||||
[11] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
[12] if((byte) main::i#1!=(byte) 4) goto main::@1
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1 main::@2
|
||||
[13] (byte) main::i1#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::i1#1 )
|
||||
[14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1
|
||||
[15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15
|
||||
[16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15)
|
||||
[17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0)
|
||||
[18] (byte) main::i1#1 ← ++ (byte) main::i1#2
|
||||
[19] if((byte) main::i1#1!=(byte) 4) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@2
|
||||
[20] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(byte) OFFS_X
|
||||
(byte) OFFS_Y
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(byte~) main::$14 16.5
|
||||
(byte~) main::$15 16.5
|
||||
(byte~) main::$5 22.0
|
||||
(byte*) main::SCREEN
|
||||
(byte) main::i
|
||||
(byte) main::i#1 16.5
|
||||
(byte) main::i#2 9.166666666666666
|
||||
(byte) main::i1
|
||||
(byte) main::i1#1 16.5
|
||||
(byte) main::i1#2 11.0
|
||||
(struct Point*) main::point_i
|
||||
(struct Point*) main::point_i#0 3.6666666666666665
|
||||
(struct Point*) main::point_i1
|
||||
(struct Point*) main::point_i1#0 5.5
|
||||
(struct Point[4]) points
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ main::i1#2 main::i1#1 ]
|
||||
Added variable main::$14 to zero page equivalence class [ main::$14 ]
|
||||
Added variable main::point_i#0 to zero page equivalence class [ main::point_i#0 ]
|
||||
Added variable main::$5 to zero page equivalence class [ main::$5 ]
|
||||
Added variable main::$15 to zero page equivalence class [ main::$15 ]
|
||||
Added variable main::point_i1#0 to zero page equivalence class [ main::point_i1#0 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
[ main::i1#2 main::i1#1 ]
|
||||
[ main::$14 ]
|
||||
[ main::point_i#0 ]
|
||||
[ main::$5 ]
|
||||
[ main::$15 ]
|
||||
[ main::point_i1#0 ]
|
||||
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Allocated zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ]
|
||||
Allocated zp ZP_BYTE:4 [ main::$14 ]
|
||||
Allocated zp ZP_WORD:5 [ main::point_i#0 ]
|
||||
Allocated zp ZP_BYTE:7 [ main::$5 ]
|
||||
Allocated zp ZP_BYTE:8 [ main::$15 ]
|
||||
Allocated zp ZP_WORD:9 [ main::point_i1#0 ]
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct - far pointer math indexing
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFS_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
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
.label _5 = 7
|
||||
.label _14 = 4
|
||||
.label _15 = 8
|
||||
.label point_i = 5
|
||||
.label i = 2
|
||||
.label point_i1 = 9
|
||||
.label i1 = 3
|
||||
//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
|
||||
jmp b1
|
||||
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
b1_from_b1:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda i
|
||||
asl
|
||||
sta _14
|
||||
//SEG17 [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 -- pssz1=pssc1_plus_vbuz2
|
||||
lda _14
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i+1
|
||||
//SEG18 [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 -- pbuc1_derefidx_vbuz1=vbuz2
|
||||
lda i
|
||||
ldy _14
|
||||
sta points,y
|
||||
//SEG19 [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 -- vbuz1=vbuz2_plus_vbuc1
|
||||
lax i
|
||||
axs #-[4]
|
||||
stx _5
|
||||
//SEG20 [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 -- pbuz1_derefidx_vbuc1=vbuz2
|
||||
// points[i].x = i;
|
||||
lda _5
|
||||
ldy #OFFS_Y
|
||||
sta (point_i),y
|
||||
//SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
|
||||
inc i
|
||||
//SEG22 [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #4
|
||||
cmp i
|
||||
bne b1_from_b1
|
||||
//SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
b2_from_b1:
|
||||
//SEG24 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta i1
|
||||
jmp b2
|
||||
//SEG25 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
b2_from_b2:
|
||||
//SEG26 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
jmp b2
|
||||
//SEG27 main::@2
|
||||
b2:
|
||||
//SEG28 [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda i1
|
||||
asl
|
||||
sta _15
|
||||
//SEG29 [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 -- pssz1=pssc1_plus_vbuz2
|
||||
lda _15
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i1
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i1+1
|
||||
//SEG30 [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2
|
||||
ldy _15
|
||||
lda points,y
|
||||
ldy i1
|
||||
sta SCREEN,y
|
||||
//SEG31 [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuc2
|
||||
// SCREEN[i] = points[i].x;
|
||||
ldx i1
|
||||
ldy #OFFS_Y
|
||||
lda (point_i1),y
|
||||
sta SCREEN+$28,x
|
||||
//SEG32 [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuz1=_inc_vbuz1
|
||||
inc i1
|
||||
//SEG33 [19] 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
|
||||
//SEG34 main::@return
|
||||
breturn:
|
||||
//SEG35 [20] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$14 ] ( main:2 [ main::i#2 main::$14 ] ) 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 ]
|
||||
Statement [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 [ main::i#2 main::$14 main::point_i#0 ] ( main:2 [ main::i#2 main::$14 main::point_i#0 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::$14 ]
|
||||
Statement [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 [ main::i#2 main::point_i#0 ] ( main:2 [ main::i#2 main::point_i#0 ] ) always clobbers reg byte a
|
||||
Statement [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::point_i#0 main::$5 ] ( main:2 [ main::i#2 main::point_i#0 main::$5 ] ) always clobbers reg byte a
|
||||
Statement [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte y
|
||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
|
||||
Statement [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$15 ] ( main:2 [ main::i1#2 main::$15 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ]
|
||||
Statement [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 [ main::i1#2 main::$15 main::point_i1#0 ] ( main:2 [ main::i1#2 main::$15 main::point_i1#0 ] ) always clobbers reg byte a
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:8 [ main::$15 ]
|
||||
Statement [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) [ main::i1#2 main::point_i1#0 ] ( main:2 [ main::i1#2 main::point_i1#0 ] ) always clobbers reg byte a
|
||||
Statement [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a reg byte y
|
||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ]
|
||||
Statement [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 [ main::i#2 main::$14 ] ( main:2 [ main::i#2 main::$14 ] ) always clobbers reg byte a
|
||||
Statement [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 [ main::i#2 main::$14 main::point_i#0 ] ( main:2 [ main::i#2 main::$14 main::point_i#0 ] ) always clobbers reg byte a
|
||||
Statement [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 [ main::i#2 main::point_i#0 ] ( main:2 [ main::i#2 main::point_i#0 ] ) always clobbers reg byte a
|
||||
Statement [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 [ main::i#2 main::point_i#0 main::$5 ] ( main:2 [ main::i#2 main::point_i#0 main::$5 ] ) always clobbers reg byte a
|
||||
Statement [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte y
|
||||
Statement [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 [ main::i1#2 main::$15 ] ( main:2 [ main::i1#2 main::$15 ] ) always clobbers reg byte a
|
||||
Statement [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 [ main::i1#2 main::$15 main::point_i1#0 ] ( main:2 [ main::i1#2 main::$15 main::point_i1#0 ] ) always clobbers reg byte a
|
||||
Statement [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) [ main::i1#2 main::point_i1#0 ] ( main:2 [ main::i1#2 main::point_i1#0 ] ) always clobbers reg byte a
|
||||
Statement [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) [ main::i1#2 ] ( main:2 [ main::i1#2 ] ) always clobbers reg byte a reg byte y
|
||||
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x ,
|
||||
Potential registers zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] : zp ZP_BYTE:3 , reg byte x ,
|
||||
Potential registers zp ZP_BYTE:4 [ main::$14 ] : zp ZP_BYTE:4 , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_WORD:5 [ main::point_i#0 ] : zp ZP_WORD:5 ,
|
||||
Potential registers zp ZP_BYTE:7 [ main::$5 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_BYTE:8 [ main::$15 ] : zp ZP_BYTE:8 , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_WORD:9 [ main::point_i1#0 ] : zp ZP_WORD:9 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 27.5: zp ZP_BYTE:3 [ main::i1#2 main::i1#1 ] 25.67: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 22: zp ZP_BYTE:7 [ main::$5 ] 16.5: zp ZP_BYTE:4 [ main::$14 ] 16.5: zp ZP_BYTE:8 [ main::$15 ] 5.5: zp ZP_WORD:9 [ main::point_i1#0 ] 3.67: zp ZP_WORD:5 [ main::point_i#0 ]
|
||||
Uplift Scope [Point]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 1258 combination reg byte x [ main::i1#2 main::i1#1 ] reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$5 ] reg byte y [ main::$14 ] zp ZP_BYTE:8 [ main::$15 ] zp ZP_WORD:9 [ main::point_i1#0 ] zp ZP_WORD:5 [ main::point_i#0 ]
|
||||
Limited combination testing to 100 combinations of 144 possible.
|
||||
Uplifting [Point] best 1258 combination
|
||||
Uplifting [] best 1258 combination
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:8 [ main::$15 ]
|
||||
Uplifting [main] best 1208 combination reg byte y [ main::$15 ]
|
||||
Allocated (was zp ZP_WORD:5) zp ZP_WORD:2 [ main::point_i#0 ]
|
||||
Allocated (was zp ZP_WORD:9) zp ZP_WORD:4 [ main::point_i1#0 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct - far pointer math indexing
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFS_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
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
.label point_i = 2
|
||||
.label point_i1 = 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
|
||||
jmp b1
|
||||
//SEG13 [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
b1_from_b1:
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
jmp b1
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
//SEG17 [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 -- pssz1=pssc1_plus_vbuyy
|
||||
tya
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i+1
|
||||
//SEG18 [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx
|
||||
txa
|
||||
sta points,y
|
||||
//SEG19 [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1
|
||||
txa
|
||||
clc
|
||||
adc #4
|
||||
//SEG20 [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 -- pbuz1_derefidx_vbuc1=vbuaa
|
||||
// points[i].x = i;
|
||||
ldy #OFFS_Y
|
||||
sta (point_i),y
|
||||
//SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG22 [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #4
|
||||
bne b1_from_b1
|
||||
//SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
b2_from_b1:
|
||||
//SEG24 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
jmp b2
|
||||
//SEG25 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
b2_from_b2:
|
||||
//SEG26 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
jmp b2
|
||||
//SEG27 main::@2
|
||||
b2:
|
||||
//SEG28 [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 -- vbuyy=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
//SEG29 [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 -- pssz1=pssc1_plus_vbuyy
|
||||
tya
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i1
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i1+1
|
||||
//SEG30 [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy
|
||||
lda points,y
|
||||
sta SCREEN,x
|
||||
//SEG31 [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
|
||||
// SCREEN[i] = points[i].x;
|
||||
ldy #OFFS_Y
|
||||
lda (point_i1),y
|
||||
sta SCREEN+$28,x
|
||||
//SEG32 [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG33 [19] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #4
|
||||
bne b2_from_b2
|
||||
jmp breturn
|
||||
//SEG34 main::@return
|
||||
breturn:
|
||||
//SEG35 [20] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
||||
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 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
|
||||
(byte) OFFS_X
|
||||
(byte) OFFS_Y
|
||||
(const byte) OFFS_Y#0 OFFS_Y = (byte) 1
|
||||
(byte) Point::x
|
||||
(byte) Point::y
|
||||
(void()) main()
|
||||
(byte~) main::$14 reg byte y 16.5
|
||||
(byte~) main::$15 reg byte y 16.5
|
||||
(byte~) main::$5 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 9.166666666666666
|
||||
(byte) main::i1
|
||||
(byte) main::i1#1 reg byte x 16.5
|
||||
(byte) main::i1#2 reg byte x 11.0
|
||||
(struct Point*) main::point_i
|
||||
(struct Point*) main::point_i#0 point_i zp ZP_WORD:2 3.6666666666666665
|
||||
(struct Point*) main::point_i1
|
||||
(struct Point*) main::point_i1#0 point_i1 zp ZP_WORD:4 5.5
|
||||
(struct Point[4]) points
|
||||
(const struct Point[4]) points#0 points = { fill( 4, 0) }
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
reg byte x [ main::i1#2 main::i1#1 ]
|
||||
reg byte y [ main::$14 ]
|
||||
zp ZP_WORD:2 [ main::point_i#0 ]
|
||||
reg byte a [ main::$5 ]
|
||||
reg byte y [ main::$15 ]
|
||||
zp ZP_WORD:4 [ main::point_i1#0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 1046
|
||||
|
||||
//SEG0 File Comments
|
||||
// Minimal struct - array of struct - far pointer math indexing
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.const OFFS_Y = 1
|
||||
//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: {
|
||||
.label SCREEN = $400
|
||||
.label point_i = 2
|
||||
.label point_i1 = 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 from main::@1 to main::@1 [phi:main::@1->main::@1]
|
||||
//SEG14 [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
|
||||
//SEG15 main::@1
|
||||
b1:
|
||||
//SEG16 [6] (byte~) main::$14 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
//SEG17 [7] (struct Point*) main::point_i#0 ← (const struct Point[4]) points#0 + (byte~) main::$14 -- pssz1=pssc1_plus_vbuyy
|
||||
tya
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i+1
|
||||
//SEG18 [8] *((byte*)(const struct Point[4]) points#0 + (byte~) main::$14) ← (byte) main::i#2 -- pbuc1_derefidx_vbuyy=vbuxx
|
||||
txa
|
||||
sta points,y
|
||||
//SEG19 [9] (byte~) main::$5 ← (byte) main::i#2 + (byte) 4 -- vbuaa=vbuxx_plus_vbuc1
|
||||
txa
|
||||
clc
|
||||
adc #4
|
||||
//SEG20 [10] *((byte*)(struct Point*) main::point_i#0 + (const byte) OFFS_Y#0) ← (byte~) main::$5 -- pbuz1_derefidx_vbuc1=vbuaa
|
||||
// points[i].x = i;
|
||||
ldy #OFFS_Y
|
||||
sta (point_i),y
|
||||
//SEG21 [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG22 [12] if((byte) main::i#1!=(byte) 4) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #4
|
||||
bne b1
|
||||
//SEG23 [13] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
|
||||
//SEG24 [13] phi (byte) main::i1#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
//SEG25 [13] phi from main::@2 to main::@2 [phi:main::@2->main::@2]
|
||||
//SEG26 [13] phi (byte) main::i1#2 = (byte) main::i1#1 [phi:main::@2->main::@2#0] -- register_copy
|
||||
//SEG27 main::@2
|
||||
b2:
|
||||
//SEG28 [14] (byte~) main::$15 ← (byte) main::i1#2 << (byte) 1 -- vbuyy=vbuxx_rol_1
|
||||
txa
|
||||
asl
|
||||
tay
|
||||
//SEG29 [15] (struct Point*) main::point_i1#0 ← (const struct Point[4]) points#0 + (byte~) main::$15 -- pssz1=pssc1_plus_vbuyy
|
||||
tya
|
||||
clc
|
||||
adc #<points
|
||||
sta point_i1
|
||||
lda #>points
|
||||
adc #0
|
||||
sta point_i1+1
|
||||
//SEG30 [16] *((const byte*) main::SCREEN#0 + (byte) main::i1#2) ← *((byte*)(const struct Point[4]) points#0 + (byte~) main::$15) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy
|
||||
lda points,y
|
||||
sta SCREEN,x
|
||||
//SEG31 [17] *((const byte*) main::SCREEN#0+(byte) $28 + (byte) main::i1#2) ← *((byte*)(struct Point*) main::point_i1#0 + (const byte) OFFS_Y#0) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuc2
|
||||
// SCREEN[i] = points[i].x;
|
||||
ldy #OFFS_Y
|
||||
lda (point_i1),y
|
||||
sta SCREEN+$28,x
|
||||
//SEG32 [18] (byte) main::i1#1 ← ++ (byte) main::i1#2 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG33 [19] if((byte) main::i1#1!=(byte) 4) goto main::@2 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #4
|
||||
bne b2
|
||||
//SEG34 main::@return
|
||||
//SEG35 [20] return
|
||||
rts
|
||||
}
|
||||
points: .fill 2*4, 0
|
||||
|
1
src/test/ref/struct-ptr-2.sym
Normal file
1
src/test/ref/struct-ptr-2.sym
Normal file
@ -0,0 +1 @@
|
||||
program
|
Loading…
Reference in New Issue
Block a user