1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-03-24 00:30:25 +00:00

Progress on memory variables. Avoided const/alias/... passes. Added new register type and the first few fragments. The first few tests working. #328

This commit is contained in:
jespergravgaard 2019-09-30 23:57:27 +02:00
parent cfff09e038
commit 7b7d7de49d
43 changed files with 1189 additions and 953 deletions

View File

@ -0,0 +1,6 @@
ldy {m1}
sty $fe
ldy {m1}+1
sty $ff
ldy #0
sta ($fe),y

View File

@ -0,0 +1,6 @@
clc
adc {m2}
sta {m1}
lda #0
adc {m2}+1
sta {m1}+1

View File

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

View File

@ -227,7 +227,7 @@ public class Compiler {
new Pass1ProcedureCallParameters(program).generate();
new PassNUnwindLValueLists(program).execute();
new Pass1PointifyMemoryVariables(program).execute();
//new Pass1PointifyMemoryVariables(program).execute();
//getLog().append("CONTROL FLOW GRAPH (CALL PARAMETERS)");
//getLog().append(program.getGraph().toString(program));

View File

@ -81,6 +81,8 @@ public class AsmFragmentInstance {
Registers.Register register = boundVar.getAllocation();
if(register != null && register instanceof Registers.RegisterZp) {
return new AsmParameter(AsmFormat.getAsmParamName(boundVar, codeScopeRef), true);
} else if(register!=null && register instanceof Registers.RegisterMemory) {
return new AsmParameter(AsmFormat.getAsmParamName(boundVar, codeScopeRef), false);
} else {
throw new RuntimeException("Register Type not implemented " + register);
}

View File

@ -41,6 +41,7 @@ public class AsmFragmentInstanceSpecFactory {
/** Indexing for zeropages/constants/labels */
private int nextZpIdx = 1;
private int nextMemIdx = 1;
private int nextConstIdx = 1;
private int nextLabelIdx = 1;
@ -477,6 +478,10 @@ public class AsmFragmentInstanceSpecFactory {
zpNameIdx = Integer.toString(nextZpIdx++);
}
return "z" + zpNameIdx;
} else if(Registers.RegisterType.MEMORY.equals(register.getType())) {
// TODO: Examine of Memory is already bound!
return "m"+(nextMemIdx++);
} else if(Registers.RegisterType.REG_A_BYTE.equals(register.getType())) {
return "aa";
} else if(Registers.RegisterType.REG_X_BYTE.equals(register.getType())) {

View File

@ -81,24 +81,46 @@ public class AsmFragmentTemplate {
// Generate a dummy instance to find clobber & cycles
ProgramScope scope = new ProgramScope();
LinkedHashMap<String, Value> bindings = new LinkedHashMap<>();
Variable v1 = new Variable("$tmp1", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v2 = new Variable("$tmp2", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v3 = new Variable("$tmp3", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v4 = new Variable("$tmp4", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v5 = new Variable("$tmp5", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v6 = new Variable("$tmp6", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
v1.setAllocation(new Registers.RegisterZpByte(2));
v2.setAllocation(new Registers.RegisterZpByte(4));
v3.setAllocation(new Registers.RegisterZpByte(6));
v4.setAllocation(new Registers.RegisterZpByte(8));
v5.setAllocation(new Registers.RegisterZpByte(9));
v6.setAllocation(new Registers.RegisterZpByte(10));
if(signature.contains("z1")) bindings.put("z1", v1);
if(signature.contains("z2")) bindings.put("z2", v2);
if(signature.contains("z3")) bindings.put("z3", v3);
if(signature.contains("z4")) bindings.put("z4", v4);
if(signature.contains("z5")) bindings.put("z5", v5);
if(signature.contains("z6")) bindings.put("z6", v6);
{
Variable v1 = new Variable("z1", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v2 = new Variable("z2", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v3 = new Variable("z3", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v4 = new Variable("z4", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v5 = new Variable("z5", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
Variable v6 = new Variable("z6", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.PHI_VERSION);
v1.setAllocation(new Registers.RegisterZpByte(2));
v2.setAllocation(new Registers.RegisterZpByte(4));
v3.setAllocation(new Registers.RegisterZpByte(6));
v4.setAllocation(new Registers.RegisterZpByte(8));
v5.setAllocation(new Registers.RegisterZpByte(9));
v6.setAllocation(new Registers.RegisterZpByte(10));
if(signature.contains("z1")) bindings.put("z1", v1);
if(signature.contains("z2")) bindings.put("z2", v2);
if(signature.contains("z3")) bindings.put("z3", v3);
if(signature.contains("z4")) bindings.put("z4", v4);
if(signature.contains("z5")) bindings.put("z5", v5);
if(signature.contains("z6")) bindings.put("z6", v6);
}
{
Variable v1 = new Variable("m1", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.MEMORY);
Variable v2 = new Variable("m2", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.MEMORY);
Variable v3 = new Variable("m3", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.MEMORY);
Variable v4 = new Variable("m4", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.MEMORY);
Variable v5 = new Variable("m5", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.MEMORY);
Variable v6 = new Variable("m6", scope, SymbolType.BYTE, null, SymbolVariable.StorageStrategy.MEMORY);
v1.setAllocation(new Registers.RegisterMemory());
v2.setAllocation(new Registers.RegisterMemory());
v3.setAllocation(new Registers.RegisterMemory());
v4.setAllocation(new Registers.RegisterMemory());
v5.setAllocation(new Registers.RegisterMemory());
v6.setAllocation(new Registers.RegisterMemory());
if(signature.contains("m1")) bindings.put("m1", v1);
if(signature.contains("m2")) bindings.put("m2", v2);
if(signature.contains("m3")) bindings.put("m3", v3);
if(signature.contains("m4")) bindings.put("m4", v4);
if(signature.contains("m5")) bindings.put("m5", v5);
if(signature.contains("m6")) bindings.put("m6", v6);
}
if(signature.contains("c1")) bindings.put("c1", new ConstantInteger(310L));
if(signature.contains("c2")) bindings.put("c2", new ConstantInteger(320L));
if(signature.contains("c3")) bindings.put("c3", new ConstantInteger(330L));

View File

@ -222,6 +222,14 @@ class AsmFragmentTemplateSynthesisRule {
Map<String, String> mapZ4 = new LinkedHashMap<>();
mapZ4.put("z5", "z4");
mapZ4.put("z6", "z5");
// M1 is replaced by something non-mem - all above are moved down
Map<String, String> mapM1 = new LinkedHashMap<>();
mapM1.put("m2", "m1");
mapM1.put("m3", "m2");
mapM1.put("m4", "m3");
mapM1.put("m5", "m4");
mapM1.put("m6", "m5");
// C1 is replaced by something non-C - all above are moved down
Map<String, String> mapC1 = new LinkedHashMap<>();
mapC1.put("c2", "c1");
@ -320,10 +328,16 @@ class AsmFragmentTemplateSynthesisRule {
String lvalZ1 = "...z1=.*";
String lvalZ2 = "...z2=.*";
String lvalZ3 = "...z3=.*";
String lvalM1 = "...m1=.*";
String lvalM2 = "...m2=.*";
String lvalM3 = "...m3=.*";
// Multiple occurences of Z1/...
String twoZ1 = ".*z1.*z1.*";
String twoZ2 = ".*z2.*z2.*";
String twoZ3 = ".*z3.*z3.*";
String twoM1 = ".*m1.*m1.*";
String twoM2 = ".*m2.*m2.*";
String twoM3 = ".*m3.*m3.*";
String twoC1 = ".*c1.*c1.*";
String twoC2 = ".*c2.*c2.*";
String threeC1 = ".*c1.*c1.*c1.*";
@ -331,6 +345,9 @@ class AsmFragmentTemplateSynthesisRule {
String threeZ2 = ".*z2.*z2.*z2.*";
String threeZ3 = ".*z3.*z3.*z3.*";
String threeZ4 = ".*z4.*z4.*z4.*";
String threeM1 = ".*m1.*m1.*m1.*";
String threeM2 = ".*m2.*m2.*m2.*";
String threeM3 = ".*m3.*m3.*m3.*";
String threeAa = ".*aa.*aa.*aa.*";
// Presence of unwanted single symbols
@ -452,6 +469,20 @@ class AsmFragmentTemplateSynthesisRule {
// Replace Z3 with XX (only one)
synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)z3(.*)", lvalZ3+"|"+twoZ3+"|"+rvalXx, "ldx {z3}", "$1xx$2", null, mapZ3));
// Replace M1 with AA (only one)
synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)m1(.*)", lvalM1+"|"+rvalAa+"|"+ twoM1, "lda {m1}", "$1aa$2", null, mapM1));
// Replace two M1s with AA
synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)m1(.*vb.)m1(.*)", lvalM1+"|"+rvalAa+"|"+ threeM1, "lda {m1}", "$1aa$2aa$3", null, mapM1));
// Replace first (not second) M1 with AA
synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)m1(.*)m1(.*)", lvalM1+"|"+rvalAa, "lda {m1}", "$1aa$2m1$3", null, null));
// Replace second (not first) M1 with AA
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)m1(.*vb.)m1(.*)", lvalM1+"|"+rvalAa, "lda {m1}", "$1m1$2aa$3", null, null));
// Replace non-assigned M1 with AA
synths.add(new AsmFragmentTemplateSynthesisRule("(...aa)=(.*vb.)m1(.*)", rvalAa+"|"+ twoM1, "lda {m1}", "$1=$2aa$3", null, mapM1));
// Replace assigned M1 with AA
synths.add(new AsmFragmentTemplateSynthesisRule("(vb.)m1=(.*)", twoM1, null, "$1aa=$2", "sta {m1}", mapM1));
// Correct wrong ordered Z2/Z1
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z2(.*)z1(.*)", twoZ1+"|"+twoZ2, null, "$1z1$2z2$3", null, mapZ2Swap, false));
// Correct wrong ordered Z3/Z2

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.model;
import dk.camelot64.kickc.model.values.ConstantValue;
import dk.camelot64.kickc.model.values.Value;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.Locale;
import java.util.Objects;
@ -51,7 +52,8 @@ public class Registers {
ZP_STRUCT,
ZP_BOOL,
ZP_VAR,
CONSTANT
CONSTANT,
MEMORY
}
/** A register used for storing a single variable. */
@ -63,6 +65,29 @@ public class Registers {
}
public static class RegisterMemory implements Register {
@Override
public RegisterType getType() {
return RegisterType.MEMORY;
}
@Override
public boolean isZp() {
return false;
}
@Override
public String toString() {
return "mem";
}
@Override
public String toString(Program program) {
return toString();
}
}
public static abstract class RegisterZp implements Register {
/** The ZP address used for the byte. */

View File

@ -202,7 +202,7 @@ public abstract class SymbolVariable implements Symbol {
}
public boolean isVolatile() {
return declaredVolatile || inferedVolatile;
return declaredVolatile || inferedVolatile || StorageStrategy.MEMORY.equals(getStorageStrategy());
}
public boolean isDeclaredExport() {

View File

@ -51,6 +51,10 @@ public class Variable extends SymbolVariable {
this.setComments(phiMaster.getComments());
}
public VariableRef getRef() {
return new VariableRef(this);
}
public Registers.Register getAllocation() {
return allocation;
}
@ -86,9 +90,6 @@ public class Variable extends SymbolVariable {
return getScope().getVariable(versionOfName);
}
public VariableRef getRef() {
return new VariableRef(this);
}
@Override
public boolean equals(Object o) {

View File

@ -115,6 +115,8 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
// Add self-assignments for all variables modified in the procedure
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) {
if(getScope().getVariable(modifiedVar).isStorageMemory())
continue;
addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar, origCall.getSource(), Comment.NO_COMMENTS));
}
return null;
@ -132,6 +134,8 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
// Add self-assignments for all variables modified in the procedure
Set<VariableRef> modifiedVars = program.getProcedureModifiedVars().getModifiedVars(procedure.getRef());
for(VariableRef modifiedVar : modifiedVars) {
if(getScope().getVariable(modifiedVar).isStorageMemory())
continue;
addStatementToCurrentBlock(new StatementAssignment(modifiedVar, modifiedVar, orig.getSource(), Comment.NO_COMMENTS));
}
return super.visitReturn(orig);

View File

@ -220,6 +220,10 @@ public class Pass1UnwindStructValues extends Pass1Base {
memberVariable.setInferedVolatile(variable.isInferedVolatile());
memberVariable.setDeclaredConstant(variable.isDeclaredConstant());
memberVariable.setDeclaredExport(variable.isDeclaredExport());
if(variable.getStorageStrategy().equals(SymbolVariable.StorageStrategy.MEMORY)) {
if(member.getStorageStrategy().equals(SymbolVariable.StorageStrategy.PHI_MASTER))
memberVariable.setStorageStrategy(SymbolVariable.StorageStrategy.MEMORY);
}
variableUnwinding.setMemberUnwinding(member.getLocalName(), memberVariable.getRef());
getLog().append("Created struct value member variable " + memberVariable.toString(getProgram()));
}

View File

@ -1,11 +1,12 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementLValue;
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.LinkedHashMap;
import java.util.Map;
@ -27,7 +28,7 @@ public class Pass2AssertSingleAssignment extends Pass2SsaAssertion {
if(statement instanceof StatementLValue) {
LValue lValue = ((StatementLValue) statement).getlValue();
if(lValue instanceof VariableRef) {
checkAssignment(assignments, lValue, statement);
checkAssignment(assignments, (VariableRef) lValue, statement);
}
} else if(statement instanceof StatementPhiBlock) {
for(StatementPhiBlock.PhiVariable phiVariable : ((StatementPhiBlock) statement).getPhiVariables()) {
@ -39,11 +40,13 @@ public class Pass2AssertSingleAssignment extends Pass2SsaAssertion {
}
private void checkAssignment(Map<VariableRef, Statement> assignments, LValue lValue, Statement statement) {
private void checkAssignment(Map<VariableRef, Statement> assignments, VariableRef lValue, Statement statement) {
if(getScope().getVariable(lValue).isStorageMemory())
return;
if(assignments.get(lValue) != null) {
throw new AssertionFailed("Multiple assignments to variable " + lValue + " 1: " + assignments.get(lValue) + " 2:" + statement);
} else {
assignments.put((VariableRef) lValue, statement);
assignments.put(lValue, statement);
}
}

View File

@ -168,7 +168,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
if(getConstant(phiRValue.getrValue()) != null) {
VariableRef variable = phiVariable.getVariable();
Variable var = getScope().getVariable(variable);
if(var.isVolatile()) {
if(var.isVolatile() || var.isStorageMemory()) {
// Volatile variables cannot be constant
continue;
}
@ -184,8 +184,8 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
if(lValue instanceof VariableRef) {
VariableRef variable = (VariableRef) lValue;
Variable var = getScope().getVariable(variable);
if(var.isVolatile()) {
// Volatile variables cannot be constant
if(var.isVolatile() || var.isStorageMemory()) {
// Volatile or memory variables cannot be constant
return;
}
if(assignment.getrValue1() == null && assignment.getOperator() == null && assignment.getrValue2() instanceof ConstantValue) {

View File

@ -1,12 +1,11 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/*** Initialize potential registers for each equivalence class.
@ -46,12 +45,12 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
Registers.RegisterType registerType = defaultRegister.getType();
List<Registers.Register> potentials = new ArrayList<>();
potentials.add(defaultRegister);
if(registerType.equals(Registers.RegisterType.ZP_BYTE) &&!varVolatile(equivalenceClass)) {
if(registerType.equals(Registers.RegisterType.ZP_BYTE) && !varVolatile(equivalenceClass)) {
potentials.add(Registers.getRegisterA());
potentials.add(Registers.getRegisterX());
potentials.add(Registers.getRegisterY());
}
if(registerType.equals(Registers.RegisterType.ZP_BOOL) &&!varVolatile(equivalenceClass)) {
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !varVolatile(equivalenceClass)) {
potentials.add(Registers.getRegisterA());
}
registerPotentials.setPotentialRegisters(equivalenceClass, potentials);
@ -62,13 +61,14 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
/**
* Determine if any variable is declared as volatile
*
* @param equivalenceClass The variable equivalence class
* @return true if any variable is volatile
*/
private boolean varVolatile(LiveRangeEquivalenceClass equivalenceClass) {
for(VariableRef variableRef : equivalenceClass.getVariables()) {
Variable variable = getSymbols().getVariable(variableRef);
if(variable.isVolatile()) {
if(variable.isVolatile() || variable.isStorageMemory()) {
return true;
}
}

View File

@ -184,7 +184,11 @@ public class Pass4RegistersFinalize extends Pass2Base {
String before = register == null ? null : register.toString();
VariableRef variableRef = equivalenceClass.getVariables().get(0);
Variable variable = getProgram().getSymbolInfos().getVariable(variableRef);
register = allocateNewRegisterZp(variable);
if(variable.isStorageMemory()) {
register = new Registers.RegisterMemory();
} else {
register = allocateNewRegisterZp(variable);
}
equivalenceClass.setRegister(register);
if(before == null || !before.equals(register.toString())) {
getLog().append("Allocated " + (before == null ? "" : ("(was " + before + ") ")) + equivalenceClass.toString());

View File

@ -35,6 +35,11 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testDeclaredMemoryVar5() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-5");
}
@Test
public void testDeclaredMemoryVar4() throws IOException, URISyntaxException {
compileAndCompare("declared-memory-var-4");

View File

@ -0,0 +1,17 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
struct foo {
char thing1;
char thing2;
};
memory struct foo bar = { 'a', 'b' };
void main(void) {
const char* SCREEN = 0x0400;
char i=0;
SCREEN[i++] = bar.thing1;
SCREEN[i++] = bar.thing2;
}

View File

@ -2,26 +2,24 @@
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.label idx_ptr = idx
.label SCREEN = $400
__bbegin:
lda #0
sta idx_ptr
sta idx
jsr main
rts
main: {
ldx #0
__b1:
lda idx_ptr
lda idx
sta SCREEN,x
txa
stx.z $ff
clc
adc idx_ptr
sta idx_ptr
adc.z $ff
sta idx
inx
cpx #6
bne __b1
sta idx_ptr
rts
}
idx: .byte 0

View File

@ -1,28 +1,24 @@
@begin: scope:[] from
[0] *((const byte*) idx_ptr) ← (byte) 0
[0] (byte) idx ← (byte) 0
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@2
@2: scope:[] from @1
[3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
to:@end
@end: scope:[] from @2
[4] phi()
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[5] phi()
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[7] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr)
[8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2
[9] (byte) main::i#1 ← ++ (byte) main::i#2
[10] if((byte) main::i#1!=(byte) 6) goto main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] *((const byte*) SCREEN + (byte) main::i#2) ← (byte) idx
[7] (byte) idx ← (byte) idx + (byte) main::i#2
[8] (byte) main::i#1 ← ++ (byte) main::i#2
[9] if((byte) main::i#1!=(byte) 6) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
[12] return
[10] return
to:@return

View File

@ -1,17 +1,8 @@
Culled Empty Block (label) main::@2
Adding memory variable constant pointer (const byte*) idx_ptr
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
*((const byte*) idx_ptr) ← (byte) 0
(byte) idx ← (byte) 0
(byte*) SCREEN ← ((byte*)) (number) $400
to:@1
@ -21,21 +12,19 @@ main: scope:[main] from @1
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*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr)
*((const byte*) idx_ptr)*((const byte*) idx_ptr) + (byte) main::i#2
*((byte*) SCREEN + (byte) main::i#2) ← (byte) idx
(byte) idx ← (byte) idx + (byte) main::i#2
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,5)
(bool~) main::$0 ← (byte) main::i#1 != rangelast(0,5)
if((bool~) main::$0) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
*((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
*((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
to:@end
@end: scope:[] from @2
@ -46,7 +35,6 @@ SYMBOL TABLE SSA
(label) @end
(byte*) SCREEN
(byte) idx memory
(const byte*) idx_ptr = &(byte) idx
(void()) main()
(bool~) main::$0
(label) main::@1
@ -78,14 +66,16 @@ Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1)
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
CALL GRAPH
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [13] main::i#3 ← main::i#1
Coalesced [12] main::i#3 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
@ -93,37 +83,33 @@ Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] *((const byte*) idx_ptr) ← (byte) 0
[0] (byte) idx ← (byte) 0
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@2
@2: scope:[] from @1
[3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
to:@end
@end: scope:[] from @2
[4] phi()
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[5] phi()
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[7] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr)
[8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2
[9] (byte) main::i#1 ← ++ (byte) main::i#2
[10] if((byte) main::i#1!=(byte) 6) goto main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] *((const byte*) SCREEN + (byte) main::i#2) ← (byte) idx
[7] (byte) idx ← (byte) idx + (byte) main::i#2
[8] (byte) main::i#1 ← ++ (byte) main::i#2
[9] if((byte) main::i#1!=(byte) 6) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr)
[12] return
[10] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) idx memory
(byte) idx memory 5.0
(void()) main()
(byte) main::i
(byte) main::i#1 16.5
@ -131,9 +117,12 @@ VARIABLE REGISTER WEIGHTS
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable idx to zero page equivalence class [ idx ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ idx ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated mem [ idx ]
INITIAL ASM
Target platform is c64basic / MOS6502X
@ -144,95 +133,82 @@ Target platform is c64basic / MOS6502X
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label idx_ptr = idx
.label SCREEN = $400
// @begin
__bbegin:
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
// [0] (byte) idx ← (byte) 0 -- vbum1=vbuc1
lda #0
sta idx_ptr
sta idx
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [5] phi from @1 to main [phi:@1->main]
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
jmp __b2
// @2
__b2:
// [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [4] phi from @2 to @end [phi:@2->@end]
__bend_from___b2:
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label i = 2
// [6] phi from main to main::@1 [phi:main->main::@1]
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
jmp __b1
// main::@1
__b1:
// [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
lda idx_ptr
// [6] *((const byte*) SCREEN + (byte) main::i#2) ← (byte) idx -- pbuc1_derefidx_vbuz1=vbum1
lda idx
ldy.z i
sta SCREEN,y
// [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuz1
lda idx_ptr
// [7] (byte) idx ← (byte) idx + (byte) main::i#2 -- vbum1=vbum2_plus_vbuz1
lda idx
clc
adc.z i
sta idx_ptr
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
sta idx
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #6
cmp.z i
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [12] return
// [10] return
rts
}
// File Data
idx: .byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Statement [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [0] (byte) idx ← (byte) 0 [ idx ] ( [ idx ] ) always clobbers reg byte a
Statement [6] *((const byte*) SCREEN + (byte) main::i#2) ← (byte) idx [ main::i#2 ] ( main:2 [ main::i#2 ] ) 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 [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Statement [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [7] (byte) idx ← (byte) idx + (byte) main::i#2 [ idx main::i#2 ] ( main:2 [ idx main::i#2 ] ) always clobbers reg byte a
Statement [0] (byte) idx ← (byte) 0 [ idx ] ( [ idx ] ) always clobbers reg byte a
Statement [6] *((const byte*) SCREEN + (byte) main::i#2) ← (byte) idx [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [7] (byte) idx ← (byte) idx + (byte) main::i#2 [ idx main::i#2 ] ( main:2 [ idx main::i#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 mem [ idx ] : mem ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 31.17: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplift Scope []
Uplift Scope [] 5: mem [ idx ]
Uplifting [main] best 428 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 428 combination
Uplifting [main] best 449 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 449 combination mem [ idx ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@ -242,66 +218,57 @@ ASSEMBLER BEFORE OPTIMIZATION
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label idx_ptr = idx
.label SCREEN = $400
// @begin
__bbegin:
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
// [0] (byte) idx ← (byte) 0 -- vbum1=vbuc1
lda #0
sta idx_ptr
sta idx
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [5] phi from @1 to main [phi:@1->main]
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
jmp __b2
// @2
__b2:
// [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [4] phi from @2 to @end [phi:@2->@end]
__bend_from___b2:
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [6] phi from main to main::@1 [phi:main->main::@1]
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
jmp __b1
// main::@1
__b1:
// [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuxx=_deref_pbuc2
lda idx_ptr
// [6] *((const byte*) SCREEN + (byte) main::i#2) ← (byte) idx -- pbuc1_derefidx_vbuxx=vbum1
lda idx
sta SCREEN,x
// [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx
txa
// [7] (byte) idx ← (byte) idx + (byte) main::i#2 -- vbum1=vbum2_plus_vbuxx
lda idx
stx.z $ff
clc
adc idx_ptr
sta idx_ptr
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
adc.z $ff
sta idx
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #6
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
lda idx_ptr
sta idx_ptr
// [12] return
// [10] return
rts
}
// File Data
@ -309,19 +276,19 @@ main: {
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __b2
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda idx
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label __b1_from___b1 with __b1
Removing instruction __b1_from___bbegin:
Removing instruction main_from___b1:
Removing instruction __bend_from___b2:
Removing instruction __bend_from___b1:
Removing instruction __b1_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1:
Removing instruction __b2:
Removing instruction __bend:
Removing instruction __b1_from_main:
Removing instruction __breturn:
@ -330,20 +297,13 @@ Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp __b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda idx_ptr
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Removing unreachable instruction lda idx_ptr
Removing unreachable instruction sta idx_ptr
Succesful ASM optimization Pass5UnreachableCodeElimination
FINAL SYMBOL TABLE
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte*) SCREEN SCREEN = (byte*) 1024
(byte) idx memory
(const byte*) idx_ptr idx_ptr = &(byte) idx
(byte) idx memory mem 5.0
(void()) main()
(label) main::@1
(label) main::@return
@ -352,10 +312,11 @@ FINAL SYMBOL TABLE
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
mem [ idx ]
FINAL ASSEMBLER
Score: 323
Score: 319
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
@ -364,54 +325,49 @@ Score: 323
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label idx_ptr = idx
.label SCREEN = $400
// @begin
__bbegin:
// idx
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
// [0] (byte) idx ← (byte) 0 -- vbum1=vbuc1
lda #0
sta idx_ptr
sta idx
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [5] phi from @1 to main [phi:@1->main]
// [4] phi from @1 to main [phi:@1->main]
jsr main
rts
// @2
// [3] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
// [4] phi from @2 to @end [phi:@2->@end]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [6] phi from main to main::@1 [phi:main->main::@1]
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// main::@1
__b1:
// SCREEN[i] = idx
// [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_ptr) -- pbuc1_derefidx_vbuxx=_deref_pbuc2
lda idx_ptr
// [6] *((const byte*) SCREEN + (byte) main::i#2) ← (byte) idx -- pbuc1_derefidx_vbuxx=vbum1
lda idx
sta SCREEN,x
// idx +=i
// [8] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx
txa
// [7] (byte) idx ← (byte) idx + (byte) main::i#2 -- vbum1=vbum2_plus_vbuxx
stx.z $ff
clc
adc idx_ptr
sta idx_ptr
adc.z $ff
sta idx
// for( char i: 0..5 )
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #6
bne __b1
// main::@return
// }
// [11] *((const byte*) idx_ptr) ← *((const byte*) idx_ptr) -- _deref_pbuc1=_deref_pbuc1
sta idx_ptr
// [12] return
// [10] return
rts
}
// File Data

View File

@ -1,10 +1,8 @@
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte*) SCREEN SCREEN = (byte*) 1024
(byte) idx memory
(const byte*) idx_ptr idx_ptr = &(byte) idx
(byte) idx memory mem 5.0
(void()) main()
(label) main::@1
(label) main::@return
@ -13,3 +11,4 @@
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
mem [ idx ]

View File

@ -3,28 +3,22 @@
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.label idx_ptr = idx
.label idx_p = idx
.label SCREEN = $400
.label idx_p = 2
__bbegin:
lda #0
sta idx_ptr
lda #<idx_ptr
sta.z idx_p
lda #>idx_ptr
sta.z idx_p+1
sta idx
jsr main
rts
main: {
ldx #0
__b1:
ldy #0
lda (idx_p),y
lda idx_p
sta SCREEN,x
txa
clc
adc (idx_p),y
sta (idx_p),y
adc idx_p
sta idx_p
inx
cpx #6
bne __b1

View File

@ -1,25 +1,24 @@
@begin: scope:[] from
[0] *((const byte*) idx_ptr) ← (byte) 0
[1] (byte*) idx_p#0 ← & *((const byte*) idx_ptr)
[0] (byte) idx ← (byte) 0
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[4] phi()
[3] phi()
(void()) main()
main: scope:[main] from @1
[5] phi()
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[7] *((const byte*) SCREEN + (byte) main::i#2) ← *((byte*) idx_p#0)
[8] *((byte*) idx_p#0) ← *((byte*) idx_p#0) + (byte) main::i#2
[9] (byte) main::i#1 ← ++ (byte) main::i#2
[10] if((byte) main::i#1!=(byte) 6) goto main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_p#0)
[7] *((const byte*) idx_p#0) ← *((const byte*) idx_p#0) + (byte) main::i#2
[8] (byte) main::i#1 ← ++ (byte) main::i#2
[9] if((byte) main::i#1!=(byte) 6) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[11] return
[10] return
to:@return

View File

@ -1,13 +1,10 @@
Setting inferred volatile on symbol affected by address-of (byte*~) $0 ← & (byte) idx
Culled Empty Block (label) main::@2
Adding memory variable constant pointer (const byte*) idx_ptr
Updating memory variable reference *((const byte*) idx_ptr)
Updating memory variable reference *((const byte*) idx_ptr)
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
*((const byte*) idx_ptr) ← (byte) 0
(byte*~) $0 ← & *((const byte*) idx_ptr)
(byte) idx ← (byte) 0
(byte*~) $0 ← & (byte) idx
(byte*) idx_p#0 ← (byte*~) $0
(byte*) SCREEN ← ((byte*)) (number) $400
to:@1
@ -50,7 +47,6 @@ SYMBOL TABLE SSA
(byte*) idx_p#1
(byte*) idx_p#2
(byte*) idx_p#3
(const byte*) idx_ptr = &(byte) idx
(void()) main()
(bool~) main::$0
(label) main::@1
@ -71,6 +67,9 @@ Identical Phi Values (byte*) idx_p#1 (byte*) idx_p#2
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$0 [11] if((byte) main::i#1!=rangelast(0,5)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant right-side identified [1] (byte*) idx_p#0 ← & (byte) idx
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) idx_p#0 = &idx
Constant (const byte*) SCREEN = (byte*) 1024
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
@ -91,10 +90,10 @@ Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
CALL GRAPH
Calls in [] to main:3
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [13] main::i#3 ← main::i#1
Coalesced [12] main::i#3 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3
@ -104,36 +103,34 @@ Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] *((const byte*) idx_ptr) ← (byte) 0
[1] (byte*) idx_p#0 ← & *((const byte*) idx_ptr)
[0] (byte) idx ← (byte) 0
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[4] phi()
[3] phi()
(void()) main()
main: scope:[main] from @1
[5] phi()
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[7] *((const byte*) SCREEN + (byte) main::i#2) ← *((byte*) idx_p#0)
[8] *((byte*) idx_p#0) ← *((byte*) idx_p#0) + (byte) main::i#2
[9] (byte) main::i#1 ← ++ (byte) main::i#2
[10] if((byte) main::i#1!=(byte) 6) goto main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_p#0)
[7] *((const byte*) idx_p#0) ← *((const byte*) idx_p#0) + (byte) main::i#2
[8] (byte) main::i#1 ← ++ (byte) main::i#2
[9] if((byte) main::i#1!=(byte) 6) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[11] return
[10] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) idx memory
(byte) idx memory 20.0
(byte*) idx_p
(byte*) idx_p#0 4.375
(void()) main()
(byte) main::i
(byte) main::i#1 16.5
@ -141,12 +138,12 @@ VARIABLE REGISTER WEIGHTS
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable idx_p#0 to zero page equivalence class [ idx_p#0 ]
Added variable idx to zero page equivalence class [ idx ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ idx_p#0 ]
[ idx ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated zp ZP_WORD:3 [ idx_p#0 ]
Allocated mem [ idx ]
INITIAL ASM
Target platform is c64basic / MOS6502X
@ -158,29 +155,23 @@ Target platform is c64basic / MOS6502X
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label idx_ptr = idx
.label idx_p = idx
.label SCREEN = $400
.label idx_p = 3
// @begin
__bbegin:
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
// [0] (byte) idx ← (byte) 0 -- vbum1=vbuc1
lda #0
sta idx_ptr
// [1] (byte*) idx_p#0 ← & *((const byte*) idx_ptr) -- pbuz1=_addr__deref_pbuc1
lda #<idx_ptr
sta.z idx_p
lda #>idx_ptr
sta.z idx_p+1
// [2] phi from @begin to @1 [phi:@begin->@1]
sta idx
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
// [5] phi from @1 to main [phi:@1->main]
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
@ -188,66 +179,59 @@ __bend:
// main
main: {
.label i = 2
// [6] phi from main to main::@1 [phi:main->main::@1]
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
jmp __b1
// main::@1
__b1:
// [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((byte*) idx_p#0) -- pbuc1_derefidx_vbuz1=_deref_pbuz2
ldx.z i
ldy #0
lda (idx_p),y
sta SCREEN,x
// [8] *((byte*) idx_p#0) ← *((byte*) idx_p#0) + (byte) main::i#2 -- _deref_pbuz1=_deref_pbuz1_plus_vbuz2
lda.z i
// [6] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_p#0) -- pbuc1_derefidx_vbuz1=_deref_pbuc2
lda idx_p
ldy.z i
sta SCREEN,y
// [7] *((const byte*) idx_p#0) ← *((const byte*) idx_p#0) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuz1
lda idx_p
clc
ldy #0
adc (idx_p),y
ldy #0
sta (idx_p),y
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
adc.z i
sta idx_p
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #6
cmp.z i
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [11] return
// [10] return
rts
}
// File Data
idx: .byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte*) idx_p#0 ← & *((const byte*) idx_ptr) [ idx_p#0 ] ( [ idx_p#0 ] ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((byte*) idx_p#0) [ idx_p#0 main::i#2 ] ( main:3 [ idx_p#0 main::i#2 ] ) always clobbers reg byte a reg byte y
Statement [0] (byte) idx ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Statement [6] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_p#0) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [8] *((byte*) idx_p#0) ← *((byte*) idx_p#0) + (byte) main::i#2 [ idx_p#0 main::i#2 ] ( main:3 [ idx_p#0 main::i#2 ] ) always clobbers reg byte a reg byte y
Statement [0] *((const byte*) idx_ptr) ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte*) idx_p#0 ← & *((const byte*) idx_ptr) [ idx_p#0 ] ( [ idx_p#0 ] ) always clobbers reg byte a
Statement [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((byte*) idx_p#0) [ idx_p#0 main::i#2 ] ( main:3 [ idx_p#0 main::i#2 ] ) always clobbers reg byte a reg byte y
Statement [8] *((byte*) idx_p#0) ← *((byte*) idx_p#0) + (byte) main::i#2 [ idx_p#0 main::i#2 ] ( main:3 [ idx_p#0 main::i#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_WORD:3 [ idx_p#0 ] : zp ZP_WORD:3 ,
Statement [7] *((const byte*) idx_p#0) ← *((const byte*) idx_p#0) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [0] (byte) idx ← (byte) 0 [ ] ( [ ] ) always clobbers reg byte a
Statement [6] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_p#0) [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [7] *((const byte*) idx_p#0) ← *((const byte*) idx_p#0) + (byte) main::i#2 [ main::i#2 ] ( main:2 [ main::i#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 mem [ idx ] : mem ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 31.17: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplift Scope [] 4.38: zp ZP_WORD:3 [ idx_p#0 ]
Uplift Scope [] 20: mem [ idx ]
Uplifting [main] best 529 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 529 combination zp ZP_WORD:3 [ idx_p#0 ]
Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ idx_p#0 ]
Uplifting [main] best 409 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 409 combination mem [ idx ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@ -258,66 +242,57 @@ ASSEMBLER BEFORE OPTIMIZATION
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label idx_ptr = idx
.label idx_p = idx
.label SCREEN = $400
.label idx_p = 2
// @begin
__bbegin:
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
// [0] (byte) idx ← (byte) 0 -- vbum1=vbuc1
lda #0
sta idx_ptr
// [1] (byte*) idx_p#0 ← & *((const byte*) idx_ptr) -- pbuz1=_addr__deref_pbuc1
lda #<idx_ptr
sta.z idx_p
lda #>idx_ptr
sta.z idx_p+1
// [2] phi from @begin to @1 [phi:@begin->@1]
sta idx
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
// [5] phi from @1 to main [phi:@1->main]
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [6] phi from main to main::@1 [phi:main->main::@1]
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
jmp __b1
// main::@1
__b1:
// [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((byte*) idx_p#0) -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (idx_p),y
// [6] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_p#0) -- pbuc1_derefidx_vbuxx=_deref_pbuc2
lda idx_p
sta SCREEN,x
// [8] *((byte*) idx_p#0) ← *((byte*) idx_p#0) + (byte) main::i#2 -- _deref_pbuz1=_deref_pbuz1_plus_vbuxx
// [7] *((const byte*) idx_p#0) ← *((const byte*) idx_p#0) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx
txa
clc
ldy #0
adc (idx_p),y
ldy #0
sta (idx_p),y
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
adc idx_p
sta idx_p
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #6
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [11] return
// [10] return
rts
}
// File Data
@ -329,9 +304,6 @@ Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction ldy #0
Removing instruction ldy #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label __b1_from___b1 with __b1
Removing instruction __b1_from___bbegin:
Removing instruction main_from___b1:
@ -353,10 +325,9 @@ FINAL SYMBOL TABLE
(label) @begin
(label) @end
(const byte*) SCREEN SCREEN = (byte*) 1024
(byte) idx memory
(byte) idx memory mem 20.0
(byte*) idx_p
(byte*) idx_p#0 idx_p zp ZP_WORD:2 4.375
(const byte*) idx_ptr idx_ptr = &(byte) idx
(const byte*) idx_p#0 idx_p = &(byte) idx
(void()) main()
(label) main::@1
(label) main::@return
@ -365,11 +336,11 @@ FINAL SYMBOL TABLE
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ idx_p#0 ]
mem [ idx ]
FINAL ASSEMBLER
Score: 399
Score: 319
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
@ -379,58 +350,50 @@ Score: 399
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label idx_ptr = idx
.label idx_p = idx
.label SCREEN = $400
.label idx_p = 2
// @begin
__bbegin:
// idx
// [0] *((const byte*) idx_ptr) ← (byte) 0 -- _deref_pbuc1=vbuc2
// [0] (byte) idx ← (byte) 0 -- vbum1=vbuc1
lda #0
sta idx_ptr
// idx_p = &idx
// [1] (byte*) idx_p#0 ← & *((const byte*) idx_ptr) -- pbuz1=_addr__deref_pbuc1
lda #<idx_ptr
sta.z idx_p
lda #>idx_ptr
sta.z idx_p+1
// [2] phi from @begin to @1 [phi:@begin->@1]
sta idx
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [3] call main
// [5] phi from @1 to main [phi:@1->main]
// [2] call main
// [4] phi from @1 to main [phi:@1->main]
jsr main
rts
// [4] phi from @1 to @end [phi:@1->@end]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [6] phi from main to main::@1 [phi:main->main::@1]
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// main::@1
__b1:
// SCREEN[i] = *idx_p
// [7] *((const byte*) SCREEN + (byte) main::i#2) ← *((byte*) idx_p#0) -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (idx_p),y
// [6] *((const byte*) SCREEN + (byte) main::i#2) ← *((const byte*) idx_p#0) -- pbuc1_derefidx_vbuxx=_deref_pbuc2
lda idx_p
sta SCREEN,x
// *idx_p +=i
// [8] *((byte*) idx_p#0) ← *((byte*) idx_p#0) + (byte) main::i#2 -- _deref_pbuz1=_deref_pbuz1_plus_vbuxx
// [7] *((const byte*) idx_p#0) ← *((const byte*) idx_p#0) + (byte) main::i#2 -- _deref_pbuc1=_deref_pbuc1_plus_vbuxx
txa
clc
adc (idx_p),y
sta (idx_p),y
adc idx_p
sta idx_p
// for( char i: 0..5 )
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) 6) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #6
bne __b1
// main::@return
// }
// [11] return
// [10] return
rts
}
// File Data

View File

@ -2,10 +2,9 @@
(label) @begin
(label) @end
(const byte*) SCREEN SCREEN = (byte*) 1024
(byte) idx memory
(byte) idx memory mem 20.0
(byte*) idx_p
(byte*) idx_p#0 idx_p zp ZP_WORD:2 4.375
(const byte*) idx_ptr idx_ptr = &(byte) idx
(const byte*) idx_p#0 idx_p = &(byte) idx
(void()) main()
(label) main::@1
(label) main::@return
@ -14,4 +13,4 @@
(byte) main::i#2 reg byte x 14.666666666666666
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ idx_p#0 ]
mem [ idx ]

View File

@ -3,32 +3,31 @@
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.label cursor_ptr = cursor
.label SCREEN = $400
__bbegin:
lda #<SCREEN
sta cursor_ptr
sta cursor
lda #>SCREEN
sta cursor_ptr+1
sta cursor+1
jsr main
rts
main: {
ldx #0
__b1:
lda #'*'
ldy cursor_ptr
ldy cursor
sty.z $fe
ldy cursor_ptr+1
ldy cursor+1
sty.z $ff
ldy #0
sta ($fe),y
lda cursor_ptr
lda #$29
clc
adc #$29
sta cursor_ptr
lda cursor_ptr+1
adc #0
sta cursor_ptr+1
adc cursor
sta cursor
tya
adc cursor+1
sta cursor+1
inx
cpx #$19
bne __b1

View File

@ -1,28 +1,24 @@
@begin: scope:[] from
[0] *((const byte**) cursor_ptr) ← (const byte*) SCREEN
[0] (byte*) cursor ← (const byte*) SCREEN
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@2
@2: scope:[] from @1
[3] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr)
to:@end
@end: scope:[] from @2
[4] phi()
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[5] phi()
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[7] *(*((const byte**) cursor_ptr)) ← (byte) '*'
[8] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) + (byte) $29
[9] (byte) main::i#1 ← ++ (byte) main::i#2
[10] if((byte) main::i#1!=(byte) $19) goto main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] *((byte*) cursor) ← (byte) '*'
[7] (byte*) cursor ← (byte*) cursor + (byte) $29
[8] (byte) main::i#1 ← ++ (byte) main::i#2
[9] if((byte) main::i#1!=(byte) $19) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[11] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr)
[12] return
[10] return
to:@return

View File

@ -1,18 +1,9 @@
Culled Empty Block (label) main::@2
Adding memory variable constant pointer (const byte**) cursor_ptr
Updating memory variable reference *((const byte**) cursor_ptr)
Updating memory variable reference *((const byte**) cursor_ptr)
Updating memory variable reference *((const byte**) cursor_ptr)
Updating memory variable reference *((const byte**) cursor_ptr)
Updating memory variable reference *((const byte**) cursor_ptr)
Updating memory variable reference *((const byte**) cursor_ptr)
Updating memory variable reference *((const byte**) cursor_ptr)
Updating memory variable reference *((const byte**) cursor_ptr)
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte*) SCREEN ← ((byte*)) (number) $400
*((const byte**) cursor_ptr) ← (byte*) SCREEN
(byte*) cursor ← (byte*) SCREEN
to:@1
(void()) main()
@ -21,21 +12,19 @@ main: scope:[main] from @1
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 )
*(*((const byte**) cursor_ptr)) ← (byte) '*'
*((const byte**) cursor_ptr)*((const byte**) cursor_ptr) + (number) $29
*((byte*) cursor) ← (byte) '*'
(byte*) cursor ← (byte*) cursor + (number) $29
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,$18)
(bool~) main::$0 ← (byte) main::i#1 != rangelast(0,$18)
if((bool~) main::$0) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
*((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr)
return
to:@return
@1: scope:[] from @begin
call main
to:@2
@2: scope:[] from @1
*((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr)
to:@end
@end: scope:[] from @2
@ -46,7 +35,6 @@ SYMBOL TABLE SSA
(label) @end
(byte*) SCREEN
(byte*) cursor memory
(const byte**) cursor_ptr = &(byte*) cursor
(void()) main()
(bool~) main::$0
(label) main::@1
@ -56,7 +44,7 @@ SYMBOL TABLE SSA
(byte) main::i#1
(byte) main::i#2
Adding number conversion cast (unumber) $29 in *((const byte**) cursor_ptr)*((const byte**) cursor_ptr) + (number) $29
Adding number conversion cast (unumber) $29 in (byte*) cursor ← (byte*) cursor + (number) $29
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) SCREEN ← (byte*)(number) $400
Successful SSA optimization Pass2InlineCast
@ -65,6 +53,7 @@ Simplifying constant integer cast $29
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $29
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias candidate removed (volatile)(byte*) SCREEN = (byte*) cursor
Simple Condition (bool~) main::$0 [8] if((byte) main::i#1!=rangelast(0,$18)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) SCREEN = (byte*) 1024
@ -83,14 +72,16 @@ Constant inlined main::i#0 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@3(between main::@1 and main::@1)
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
CALL GRAPH
Calls in [] to main:2
Created 1 initial phi equivalence classes
Coalesced [13] main::i#3 ← main::i#1
Coalesced [12] main::i#3 ← main::i#1
Coalesced down to 1 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
@ -98,37 +89,33 @@ Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] *((const byte**) cursor_ptr) ← (const byte*) SCREEN
[0] (byte*) cursor ← (const byte*) SCREEN
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@2
@2: scope:[] from @1
[3] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr)
to:@end
@end: scope:[] from @2
[4] phi()
@end: scope:[] from @1
[3] phi()
(void()) main()
main: scope:[main] from @1
[5] phi()
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[6] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[7] *(*((const byte**) cursor_ptr)) ← (byte) '*'
[8] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) + (byte) $29
[9] (byte) main::i#1 ← ++ (byte) main::i#2
[10] if((byte) main::i#1!=(byte) $19) goto main::@1
[5] (byte) main::i#2 ← phi( main/(byte) 0 main::@1/(byte) main::i#1 )
[6] *((byte*) cursor) ← (byte) '*'
[7] (byte*) cursor ← (byte*) cursor + (byte) $29
[8] (byte) main::i#1 ← ++ (byte) main::i#2
[9] if((byte) main::i#1!=(byte) $19) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[11] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr)
[12] return
[10] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) cursor memory
(byte*) cursor memory 5.0
(void()) main()
(byte) main::i
(byte) main::i#1 16.5
@ -136,9 +123,12 @@ VARIABLE REGISTER WEIGHTS
Initial phi equivalence classes
[ main::i#2 main::i#1 ]
Added variable cursor to zero page equivalence class [ cursor ]
Complete equivalence classes
[ main::i#2 main::i#1 ]
[ cursor ]
Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated mem [ cursor ]
INITIAL ASM
Target platform is c64basic / MOS6502X
@ -150,97 +140,92 @@ Target platform is c64basic / MOS6502X
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label cursor_ptr = cursor
.label SCREEN = $400
// @begin
__bbegin:
// [0] *((const byte**) cursor_ptr) ← (const byte*) SCREEN -- _deref_pptc1=pbuc2
// [0] (byte*) cursor ← (const byte*) SCREEN -- pbum1=pbuc1
lda #<SCREEN
sta cursor_ptr
sta cursor
lda #>SCREEN
sta cursor_ptr+1
sta cursor+1
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [5] phi from @1 to main [phi:@1->main]
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
jmp __b2
// @2
__b2:
// [3] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) -- _deref_pptc1=_deref_pptc1
// [4] phi from @2 to @end [phi:@2->@end]
__bend_from___b2:
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label i = 2
// [6] phi from main to main::@1 [phi:main->main::@1]
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta.z i
jmp __b1
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
jmp __b1
// main::@1
__b1:
// [7] *(*((const byte**) cursor_ptr)) ← (byte) '*' -- _deref_(_deref_pptc1)=vbuc2
// [6] *((byte*) cursor) ← (byte) '*' -- _deref_pbum1=vbuc1
lda #'*'
ldy cursor_ptr
ldy cursor
sty.z $fe
ldy cursor_ptr+1
ldy cursor+1
sty.z $ff
ldy #0
sta ($fe),y
// [8] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) + (byte) $29 -- _deref_pptc1=_deref_pptc1_plus_vbuc2
lda cursor_ptr
// [7] (byte*) cursor ← (byte*) cursor + (byte) $29 -- pbum1=pbum2_plus_vbuc1
lda #$29
clc
adc #$29
sta cursor_ptr
lda cursor_ptr+1
adc #0
sta cursor_ptr+1
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
adc cursor
sta cursor
lda #0
adc cursor+1
sta cursor+1
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc.z i
// [10] if((byte) main::i#1!=(byte) $19) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) $19) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$19
cmp.z i
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [11] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) -- _deref_pptc1=_deref_pptc1
// [12] return
// [10] return
rts
}
// File Data
cursor: .word 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] *((const byte**) cursor_ptr) ← (const byte*) SCREEN [ ] ( [ ] ) always clobbers reg byte a
Statement [7] *(*((const byte**) cursor_ptr)) ← (byte) '*' [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y
Statement [0] (byte*) cursor ← (const byte*) SCREEN [ cursor ] ( [ cursor ] ) always clobbers reg byte a
Statement [6] *((byte*) cursor) ← (byte) '*' [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Statement [8] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) + (byte) $29 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [0] *((const byte**) cursor_ptr) ← (const byte*) SCREEN [ ] ( [ ] ) always clobbers reg byte a
Statement [7] *(*((const byte**) cursor_ptr)) ← (byte) '*' [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y
Statement [8] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) + (byte) $29 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a
Statement [7] (byte*) cursor ← (byte*) cursor + (byte) $29 [ cursor main::i#2 ] ( main:2 [ cursor main::i#2 ] ) always clobbers reg byte a
Statement [0] (byte*) cursor ← (const byte*) SCREEN [ cursor ] ( [ cursor ] ) always clobbers reg byte a
Statement [6] *((byte*) cursor) ← (byte) '*' [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte a reg byte y
Statement [7] (byte*) cursor ← (byte*) cursor + (byte) $29 [ cursor main::i#2 ] ( main:2 [ cursor main::i#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 ,
Potential registers mem [ cursor ] : mem ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 23.83: zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplift Scope []
Uplift Scope [] 5: mem [ cursor ]
Uplifting [main] best 668 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 668 combination
Uplifting [main] best 665 combination reg byte x [ main::i#2 main::i#1 ]
Uplifting [] best 665 combination mem [ cursor ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@ -251,72 +236,66 @@ ASSEMBLER BEFORE OPTIMIZATION
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label cursor_ptr = cursor
.label SCREEN = $400
// @begin
__bbegin:
// [0] *((const byte**) cursor_ptr) ← (const byte*) SCREEN -- _deref_pptc1=pbuc2
// [0] (byte*) cursor ← (const byte*) SCREEN -- pbum1=pbuc1
lda #<SCREEN
sta cursor_ptr
sta cursor
lda #>SCREEN
sta cursor_ptr+1
sta cursor+1
// [1] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [2] call main
// [5] phi from @1 to main [phi:@1->main]
// [4] phi from @1 to main [phi:@1->main]
main_from___b1:
jsr main
jmp __b2
// @2
__b2:
// [3] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) -- _deref_pptc1=_deref_pptc1
// [4] phi from @2 to @end [phi:@2->@end]
__bend_from___b2:
// [3] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
// [6] phi from main to main::@1 [phi:main->main::@1]
// [5] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
jmp __b1
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
jmp __b1
// main::@1
__b1:
// [7] *(*((const byte**) cursor_ptr)) ← (byte) '*' -- _deref_(_deref_pptc1)=vbuc2
// [6] *((byte*) cursor) ← (byte) '*' -- _deref_pbum1=vbuc1
lda #'*'
ldy cursor_ptr
ldy cursor
sty.z $fe
ldy cursor_ptr+1
ldy cursor+1
sty.z $ff
ldy #0
sta ($fe),y
// [8] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) + (byte) $29 -- _deref_pptc1=_deref_pptc1_plus_vbuc2
lda cursor_ptr
// [7] (byte*) cursor ← (byte*) cursor + (byte) $29 -- pbum1=pbum2_plus_vbuc1
lda #$29
clc
adc #$29
sta cursor_ptr
lda cursor_ptr+1
adc #0
sta cursor_ptr+1
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
adc cursor
sta cursor
lda #0
adc cursor+1
sta cursor+1
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::i#1!=(byte) $19) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) $19) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #$19
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [11] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) -- _deref_pptc1=_deref_pptc1
// [12] return
// [10] return
rts
}
// File Data
@ -324,20 +303,19 @@ main: {
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __b2
Removing instruction jmp __bend
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction lda #0 with TYA
Replacing label __b1_from___b1 with __b1
Removing instruction __b1_from___bbegin:
Removing instruction main_from___b1:
Removing instruction __bend_from___b2:
Removing instruction __bend:
Removing instruction __bend_from___b1:
Removing instruction __b1_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1:
Removing instruction __b2:
Removing instruction __bend:
Removing instruction __b1_from_main:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
@ -348,12 +326,10 @@ Succesful ASM optimization Pass5NextJumpElimination
FINAL SYMBOL TABLE
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte*) SCREEN SCREEN = (byte*) 1024
(byte*) cursor memory
(const byte**) cursor_ptr cursor_ptr = &(byte*) cursor
(byte*) cursor memory mem 5.0
(void()) main()
(label) main::@1
(label) main::@return
@ -362,6 +338,7 @@ FINAL SYMBOL TABLE
(byte) main::i#2 reg byte x 7.333333333333333
reg byte x [ main::i#2 main::i#1 ]
mem [ cursor ]
FINAL ASSEMBLER
@ -375,63 +352,59 @@ Score: 575
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
.label cursor_ptr = cursor
.label SCREEN = $400
// @begin
__bbegin:
// cursor = SCREEN
// [0] *((const byte**) cursor_ptr) ← (const byte*) SCREEN -- _deref_pptc1=pbuc2
// [0] (byte*) cursor ← (const byte*) SCREEN -- pbum1=pbuc1
lda #<SCREEN
sta cursor_ptr
sta cursor
lda #>SCREEN
sta cursor_ptr+1
sta cursor+1
// [1] phi from @begin to @1 [phi:@begin->@1]
// @1
// [2] call main
// [5] phi from @1 to main [phi:@1->main]
// [4] phi from @1 to main [phi:@1->main]
jsr main
rts
// @2
// [3] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) -- _deref_pptc1=_deref_pptc1
// [4] phi from @2 to @end [phi:@2->@end]
// [3] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
// [6] phi from main to main::@1 [phi:main->main::@1]
// [6] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [5] phi from main to main::@1 [phi:main->main::@1]
// [5] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
// [6] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [6] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// [5] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [5] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@1->main::@1#0] -- register_copy
// main::@1
__b1:
// *cursor = '*'
// [7] *(*((const byte**) cursor_ptr)) ← (byte) '*' -- _deref_(_deref_pptc1)=vbuc2
// [6] *((byte*) cursor) ← (byte) '*' -- _deref_pbum1=vbuc1
lda #'*'
ldy cursor_ptr
ldy cursor
sty.z $fe
ldy cursor_ptr+1
ldy cursor+1
sty.z $ff
ldy #0
sta ($fe),y
// cursor += 41
// [8] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) + (byte) $29 -- _deref_pptc1=_deref_pptc1_plus_vbuc2
lda cursor_ptr
// [7] (byte*) cursor ← (byte*) cursor + (byte) $29 -- pbum1=pbum2_plus_vbuc1
lda #$29
clc
adc #$29
sta cursor_ptr
lda cursor_ptr+1
adc #0
sta cursor_ptr+1
adc cursor
sta cursor
tya
adc cursor+1
sta cursor+1
// for( char i: 0..24 )
// [9] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
// [8] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
// [10] if((byte) main::i#1!=(byte) $19) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
// [9] if((byte) main::i#1!=(byte) $19) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #$19
bne __b1
// main::@return
// }
// [11] *((const byte**) cursor_ptr) ← *((const byte**) cursor_ptr) -- _deref_pptc1=_deref_pptc1
// [12] return
// [10] return
rts
}
// File Data

View File

@ -1,10 +1,8 @@
(label) @1
(label) @2
(label) @begin
(label) @end
(const byte*) SCREEN SCREEN = (byte*) 1024
(byte*) cursor memory
(const byte**) cursor_ptr cursor_ptr = &(byte*) cursor
(byte*) cursor memory mem 5.0
(void()) main()
(label) main::@1
(label) main::@return
@ -13,3 +11,4 @@
(byte) main::i#2 reg byte x 7.333333333333333
reg byte x [ main::i#2 main::i#1 ]
mem [ cursor ]

View File

@ -4,28 +4,21 @@
:BasicUpstart(__bbegin)
.pc = $80d "Program"
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
__bbegin:
lda #'a'
sta.z bar_thing1
sta bar_thing1
lda #'b'
sta.z bar_thing2
sta bar_thing2
jsr main
rts
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label barp = 4
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
ldy #0
lda (barp),y
lda barp
sta SCREEN
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
rts
}
bar_thing1: .byte 0
bar_thing2: .byte 0

View File

@ -1,6 +1,6 @@
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
[0] (byte) bar_thing1 ← (byte) 'a'
[1] (byte) bar_thing2 ← (byte) 'b'
to:@1
@1: scope:[] from @begin
[2] phi()
@ -11,10 +11,9 @@
(void()) main()
main: scope:[main] from @1
[5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
[5] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0)
[6] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@return
main::@return: scope:[main] from main
[8] return
[7] return
to:@return

View File

@ -6,19 +6,17 @@ Adding struct value list initializer (byte) bar_thing1 ← (byte) 'a'
Adding struct value list initializer (byte) bar_thing2 ← (byte) 'b'
Rewriting struct pointer member access *((struct foo*) main::barp).thing1
Rewriting struct pointer member access *((struct foo*) main::barp).thing2
Adding memory variable constant pointer (const struct foo*) bar_ptr
Updating memory variable reference *((const struct foo*) bar_ptr)
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte) bar_thing1#0 ← (byte) 'a'
(byte) bar_thing2#0 ← (byte) 'b'
(struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0}
(byte) bar_thing1 ← (byte) 'a'
(byte) bar_thing2 ← (byte) 'b'
(struct foo) bar ← struct-unwound {(byte) bar_thing1, (byte) bar_thing2}
to:@1
(void()) main()
main: scope:[main] from @1
(struct foo*~) main::$0 ← & *((const struct foo*) bar_ptr)
(struct foo*~) main::$0 ← & (struct foo) bar
(struct foo*) main::barp#0 ← (struct foo*~) main::$0
(byte*) main::SCREEN ← ((byte*)) (number) $400
(byte) main::i#0 ← (number) 0
@ -47,11 +45,8 @@ SYMBOL TABLE SSA
(const byte) OFFSET_STRUCT_FOO_THING1 = (byte) 0
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
(struct foo) bar memory
(const struct foo*) bar_ptr = &(struct foo) bar
(byte) bar_thing1
(byte) bar_thing1#0
(byte) bar_thing2
(byte) bar_thing2#0
(byte) bar_thing1 memory
(byte) bar_thing2 memory
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
@ -79,25 +74,29 @@ Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (struct foo*) main::barp#0 = (struct foo*~) main::$0
Successful SSA optimization Pass2AliasElimination
Rewriting struct address-of to first member &(struct foo) bar
Rewriting struct address-of to first member [3] (struct foo*) main::barp#0 ← (struct foo*)&(byte) bar_thing1
Successful SSA optimization PassNStructAddressOfRewriting
Constant (const struct foo*) main::barp#0 = (struct foo*)&bar_thing1
Constant (const byte*) main::SCREEN = (byte*) 1024
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte*)main::barp#0 in [7] (byte*) main::$1 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Constant value identified (byte*)main::barp#0 in [10] (byte*) main::$2 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Successful SSA optimization Pass2ConstantValues
Converting *(pointer+n) to pointer[n] [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*) main::$1) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING1)
Converting *(pointer+n) to pointer[n] [11] *((const byte*) main::SCREEN + (byte) main::i#1) ← *((byte*) main::$2) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING2)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)main::barp#0 in [7] (byte*) main::$1 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Simplifying expression containing zero (byte*)main::barp#0 in [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1)
Simplifying expression containing zero main::SCREEN in [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0)
Simplifying expression containing zero (byte*)main::barp#0 in [7] (byte*) main::$1 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Simplifying expression containing zero (byte*)main::barp#0 in [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1)
Simplifying expression containing zero main::SCREEN in [8] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(const struct foo*) main::barp#0)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (struct foo) bar and assignment [2] (struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0}
Eliminating unused variable (byte*) main::$1 and assignment [4] (byte*) main::$1 ← (byte*)(struct foo*) main::barp#0
Eliminating unused variable (byte*) main::$2 and assignment [7] (byte*) main::$2 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Eliminating unused variable (byte) main::i#2 and assignment [9] (byte) main::i#2 ← ++ (byte) main::i#1
Eliminating unused variable (struct foo) bar and assignment [2] (struct foo) bar ← struct-unwound {(byte) bar_thing1, (byte) bar_thing2}
Eliminating unused variable (byte*) main::$1 and assignment [3] (byte*) main::$1 ← (byte*)(const struct foo*) main::barp#0
Eliminating unused variable (byte*) main::$2 and assignment [6] (byte*) main::$2 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Eliminating unused variable (byte) main::i#2 and assignment [8] (byte) main::i#2 ← ++ (byte) main::i#1
Eliminating unused constant (const byte) OFFSET_STRUCT_FOO_THING1
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [4] (byte) main::i#1 ← ++ (const byte) main::i#0
Constant right-side identified [3] (byte) main::i#1 ← ++ (const byte) main::i#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::i#1 = ++main::i#0
Successful SSA optimization Pass2ConstantIdentification
@ -106,6 +105,7 @@ Inlining constant with different constant siblings (const byte) main::i#1
Constant inlined main::i#0 = (byte) 0
Constant inlined main::i#1 = ++(byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *((byte*)main::barp#0+OFFSET_STRUCT_FOO_THING2)
Consolidated array index constant in *(main::SCREEN+++0)
Successful SSA optimization Pass2ConstantAdditionElimination
Simplifying constant integer increment ++0
@ -124,8 +124,8 @@ Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
[0] (byte) bar_thing1 ← (byte) 'a'
[1] (byte) bar_thing2 ← (byte) 'b'
to:@1
@1: scope:[] from @begin
[2] phi()
@ -136,36 +136,31 @@ FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from @1
[5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
[5] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0)
[6] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@return
main::@return: scope:[main] from main
[8] return
[7] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) bar_thing1
(byte) bar_thing1#0 20.0
(byte) bar_thing2
(byte) bar_thing2#0 20.0
(byte) bar_thing1 memory 20.0
(byte) bar_thing2 memory 20.0
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(struct foo*) main::barp
(struct foo*) main::barp#0 1.0
(byte) main::i
Initial phi equivalence classes
Added variable main::barp#0 to zero page equivalence class [ main::barp#0 ]
Added variable bar_thing1 to zero page equivalence class [ bar_thing1 ]
Added variable bar_thing2 to zero page equivalence class [ bar_thing2 ]
Complete equivalence classes
[ bar_thing1#0 ]
[ bar_thing2#0 ]
[ main::barp#0 ]
Allocated zp ZP_BYTE:2 [ bar_thing1#0 ]
Allocated zp ZP_BYTE:3 [ bar_thing2#0 ]
Allocated zp ZP_WORD:4 [ main::barp#0 ]
[ bar_thing1 ]
[ bar_thing2 ]
Allocated mem [ bar_thing1 ]
Allocated mem [ bar_thing2 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
@ -178,17 +173,14 @@ Target platform is c64basic / MOS6502X
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta.z bar_thing2
sta bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
@ -203,51 +195,40 @@ __bend_from___b1:
__bend:
// main
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label barp = 4
// [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
// [5] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuc2
lda barp
sta SCREEN
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
// [6] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=_deref_pbuc2
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [8] return
// [7] return
rts
}
// File Data
bar_thing1: .byte 0
bar_thing2: .byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] (byte) bar_thing1#0 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2#0 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) [ main::barp#0 ] ( main:3 [ main::barp#0 ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) [ main::barp#0 ] ( main:3 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:3 [ ] ) always clobbers reg byte a reg byte y
Potential registers zp ZP_BYTE:2 [ bar_thing1#0 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_BYTE:3 [ bar_thing2#0 ] : zp ZP_BYTE:3 ,
Potential registers zp ZP_WORD:4 [ main::barp#0 ] : zp ZP_WORD:4 ,
Statement [0] (byte) bar_thing1 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [5] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:3 [ ] ) always clobbers reg byte a
Potential registers mem [ bar_thing1 ] : mem ,
Potential registers mem [ bar_thing2 ] : mem ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 20: zp ZP_BYTE:2 [ bar_thing1#0 ] 20: zp ZP_BYTE:3 [ bar_thing2#0 ]
Uplift Scope [main] 1: zp ZP_WORD:4 [ main::barp#0 ]
Uplift Scope [] 20: mem [ bar_thing1 ] 20: mem [ bar_thing2 ]
Uplift Scope [foo]
Uplift Scope [main]
Uplifting [] best 63 combination zp ZP_BYTE:2 [ bar_thing1#0 ] zp ZP_BYTE:3 [ bar_thing2#0 ]
Uplifting [main] best 63 combination zp ZP_WORD:4 [ main::barp#0 ]
Uplifting [foo] best 63 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ bar_thing1#0 ]
Uplifting [] best 63 combination zp ZP_BYTE:2 [ bar_thing1#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:3 [ bar_thing2#0 ]
Uplifting [] best 63 combination zp ZP_BYTE:3 [ bar_thing2#0 ]
Uplifting [] best 49 combination mem [ bar_thing1 ] mem [ bar_thing2 ]
Uplifting [foo] best 49 combination
Uplifting [main] best 49 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@ -259,17 +240,14 @@ ASSEMBLER BEFORE OPTIMIZATION
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta.z bar_thing2
sta bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
@ -284,28 +262,23 @@ __bend_from___b1:
__bend:
// main
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label barp = 4
// [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
// [5] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuc2
lda barp
sta SCREEN
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
// [6] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=_deref_pbuc2
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [8] return
// [7] return
rts
}
// File Data
bar_thing1: .byte 0
bar_thing2: .byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
@ -327,27 +300,23 @@ FINAL SYMBOL TABLE
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte) bar_thing1 memory mem 20.0
(byte) bar_thing2 memory mem 20.0
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:4 1.0
(const struct foo*) main::barp#0 barp = (struct foo*)&(byte) bar_thing1
(byte) main::i
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ main::barp#0 ]
mem [ bar_thing1 ]
mem [ bar_thing2 ]
FINAL ASSEMBLER
Score: 60
Score: 46
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
@ -358,18 +327,15 @@ Score: 60
.pc = $80d "Program"
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
// @begin
__bbegin:
// bar = { 'a', 'b' }
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta.z bar_thing2
sta bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
// @1
// [3] call main
@ -379,28 +345,22 @@ __bbegin:
// @end
// main
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label barp = 4
// barp = &bar
// [5] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// SCREEN[i++] = barp->thing1
// [6] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
// [5] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuc2
lda barp
sta SCREEN
// SCREEN[i++] = barp->thing2
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
// [6] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=_deref_pbuc2
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
// main::@return
// }
// [8] return
// [7] return
rts
}
// File Data
bar_thing1: .byte 0
bar_thing2: .byte 0

View File

@ -2,20 +2,16 @@
(label) @begin
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte) bar_thing1 memory mem 20.0
(byte) bar_thing2 memory mem 20.0
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:4 1.0
(const struct foo*) main::barp#0 barp = (struct foo*)&(byte) bar_thing1
(byte) main::i
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ main::barp#0 ]
mem [ bar_thing1 ]
mem [ bar_thing2 ]

View File

@ -5,15 +5,12 @@
.pc = $80d "Program"
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
.label bar_thing3 = 4
.label bar_thing3 = 2
__bbegin:
lda #'a'
sta.z bar_thing1
sta bar_thing1
lda #'b'
sta.z bar_thing2
sta bar_thing2
lda #<__0
sta.z bar_thing3
lda #>__0
@ -21,30 +18,16 @@ __bbegin:
jsr main
rts
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label __4 = 8
.label barp = 6
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
ldy #0
lda (barp),y
lda barp
sta SCREEN
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
ldx #2
ldy #0
__b1:
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
lda (__4),y
lda barp+OFFSET_STRUCT_FOO_THING3,y
sta SCREEN,x
inx
iny
@ -54,3 +37,5 @@ main: {
}
__0: .text "qwe"
.byte 0
bar_thing1: .byte 0
bar_thing2: .byte 0

View File

@ -1,6 +1,6 @@
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
[0] (byte) bar_thing1 ← (byte) 'a'
[1] (byte) bar_thing2 ← (byte) 'b'
[2] (byte[$c]) bar_thing3#0 ← (const string) $0
to:@1
@1: scope:[] from @begin
@ -12,19 +12,17 @@
(void()) main()
main: scope:[main] from @1
[6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
[6] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0)
[7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@1
main::@1: scope:[main] from main main::@1
[9] (byte) main::i#4 ← phi( main/(byte) 2 main::@1/(byte) main::i#3 )
[9] (byte) main::j#2 ← phi( main/(byte) 0 main::@1/(byte) main::j#1 )
[10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3
[11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2)
[12] (byte) main::i#3 ← ++ (byte) main::i#4
[13] (byte) main::j#1 ← ++ (byte) main::j#2
[14] if((byte) main::j#1!=(byte) $c) goto main::@1
[8] (byte) main::i#4 ← phi( main/(byte) 2 main::@1/(byte) main::i#3 )
[8] (byte) main::j#2 ← phi( main/(byte) 0 main::@1/(byte) main::j#1 )
[9] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2)
[10] (byte) main::i#3 ← ++ (byte) main::i#4
[11] (byte) main::j#1 ← ++ (byte) main::j#2
[12] if((byte) main::j#1!=(byte) $c) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[15] return
[13] return
to:@return

View File

@ -12,20 +12,18 @@ Rewriting struct pointer member access *((struct foo*) main::barp).thing1
Rewriting struct pointer member access *((struct foo*) main::barp).thing2
Rewriting struct pointer member access *((struct foo*) main::barp).thing3
Culled Empty Block (label) main::@2
Adding memory variable constant pointer (const struct foo*) bar_ptr
Updating memory variable reference *((const struct foo*) bar_ptr)
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte) bar_thing1#0 ← (byte) 'a'
(byte) bar_thing2#0 ← (byte) 'b'
(byte) bar_thing1 ← (byte) 'a'
(byte) bar_thing2 ← (byte) 'b'
(byte[$c]) bar_thing3#0 ← (const string) $0
(struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0, (byte[$c]) bar_thing3#0}
(struct foo) bar ← struct-unwound {(byte) bar_thing1, (byte) bar_thing2, (byte[$c]) bar_thing3#0}
to:@1
(void()) main()
main: scope:[main] from @1
(struct foo*~) main::$0 ← & *((const struct foo*) bar_ptr)
(struct foo*~) main::$0 ← & (struct foo) bar
(struct foo*) main::barp#0 ← (struct foo*~) main::$0
(byte*) main::SCREEN ← ((byte*)) (number) $400
(byte) main::i#0 ← (number) 0
@ -68,11 +66,8 @@ SYMBOL TABLE SSA
(const byte) OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const byte) OFFSET_STRUCT_FOO_THING3 = (byte) 2
(struct foo) bar memory
(const struct foo*) bar_ptr = &(struct foo) bar
(byte) bar_thing1
(byte) bar_thing1#0
(byte) bar_thing2
(byte) bar_thing2#0
(byte) bar_thing1 memory
(byte) bar_thing2 memory
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0
(byte) foo::thing1
@ -117,24 +112,29 @@ Identical Phi Values (struct foo*) main::barp#1 (struct foo*) main::barp#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition (bool~) main::$1 [21] if((byte) main::j#1!=rangelast(0,$b)) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Rewriting struct address-of to first member &(struct foo) bar
Rewriting struct address-of to first member [4] (struct foo*) main::barp#0 ← (struct foo*)&(byte) bar_thing1
Successful SSA optimization PassNStructAddressOfRewriting
Constant (const struct foo*) main::barp#0 = (struct foo*)&bar_thing1
Constant (const byte*) main::SCREEN = (byte*) 1024
Constant (const byte) main::i#0 = 0
Constant (const byte) main::j#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (byte*)main::barp#0 in [8] (byte*) main::$2 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Constant value identified (byte*)main::barp#0 in [11] (byte*) main::$3 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Constant value identified (byte[$c])main::barp#0 in [16] (byte[$c]) main::$4 ← (byte[$c])(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3
Successful SSA optimization Pass2ConstantValues
Resolved ranged next value [19] main::j#1 ← ++ main::j#2 to ++
Resolved ranged comparison value [21] if(main::j#1!=rangelast(0,$b)) goto main::@1 to (number) $c
Converting *(pointer+n) to pointer[n] [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*) main::$2) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING1)
Converting *(pointer+n) to pointer[n] [12] *((const byte*) main::SCREEN + (byte) main::i#1) ← *((byte*) main::$3) -- *((byte*)main::barp#0 + OFFSET_STRUCT_FOO_THING2)
Successful SSA optimization Pass2InlineDerefIdx
Simplifying expression containing zero (byte*)main::barp#0 in [8] (byte*) main::$2 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Simplifying expression containing zero (byte*)main::barp#0 in [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1)
Simplifying expression containing zero main::SCREEN in [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(struct foo*) main::barp#0)
Simplifying expression containing zero (byte*)main::barp#0 in [8] (byte*) main::$2 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1
Simplifying expression containing zero (byte*)main::barp#0 in [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING1)
Simplifying expression containing zero main::SCREEN in [9] *((const byte*) main::SCREEN + (const byte) main::i#0) ← *((byte*)(const struct foo*) main::barp#0)
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (struct foo) bar and assignment [3] (struct foo) bar ← struct-unwound {(byte) bar_thing1#0, (byte) bar_thing2#0, (byte[$c]) bar_thing3#0}
Eliminating unused variable (byte*) main::$2 and assignment [5] (byte*) main::$2 ← (byte*)(struct foo*) main::barp#0
Eliminating unused variable (byte*) main::$3 and assignment [8] (byte*) main::$3 ← (byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Eliminating unused variable (struct foo) bar and assignment [3] (struct foo) bar ← struct-unwound {(byte) bar_thing1, (byte) bar_thing2, (byte[$c]) bar_thing3#0}
Eliminating unused variable (byte*) main::$2 and assignment [4] (byte*) main::$2 ← (byte*)(const struct foo*) main::barp#0
Eliminating unused variable (byte*) main::$3 and assignment [7] (byte*) main::$3 ← (byte*)(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2
Eliminating unused constant (const byte) OFFSET_STRUCT_FOO_THING1
Successful SSA optimization PassNEliminateUnusedVars
Adding number conversion cast (unumber) $c in if((byte) main::j#1!=(number) $c) goto main::@1
@ -143,11 +143,13 @@ Simplifying constant integer cast $c
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $c
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant right-side identified [5] (byte) main::i#1 ← ++ (const byte) main::i#0
Constant right-side identified [4] (byte) main::i#1 ← ++ (const byte) main::i#0
Constant right-side identified [8] (byte[$c]) main::$4 ← (byte[$c])(const struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::i#1 = ++main::i#0
Constant (const byte[$c]) main::$4 = (byte[$c])main::barp#0+OFFSET_STRUCT_FOO_THING3
Successful SSA optimization Pass2ConstantIdentification
Constant right-side identified [6] (byte) main::i#2 ← ++ (const byte) main::i#1
Constant right-side identified [5] (byte) main::i#2 ← ++ (const byte) main::i#1
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::i#2 = ++main::i#1
Successful SSA optimization Pass2ConstantIdentification
@ -157,9 +159,11 @@ Inlining constant with var siblings (const byte) main::i#1
Inlining constant with var siblings (const byte) main::i#2
Constant inlined main::i#0 = (byte) 0
Constant inlined main::i#2 = ++++(byte) 0
Constant inlined main::$4 = (byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3
Constant inlined main::j#0 = (byte) 0
Constant inlined main::i#1 = ++(byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *((byte*)main::barp#0+OFFSET_STRUCT_FOO_THING2)
Consolidated array index constant in *(main::SCREEN+++0)
Successful SSA optimization Pass2ConstantAdditionElimination
Simplifying constant integer increment ++0
@ -175,8 +179,8 @@ CALL GRAPH
Calls in [] to main:4
Created 2 initial phi equivalence classes
Coalesced [17] main::j#3 ← main::j#1
Coalesced [18] main::i#5 ← main::i#3
Coalesced [15] main::j#3 ← main::j#1
Coalesced [16] main::i#5 ← main::i#3
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @2
Culled Empty Block (label) main::@3
@ -185,8 +189,8 @@ Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] (byte) bar_thing1#0 ← (byte) 'a'
[1] (byte) bar_thing2#0 ← (byte) 'b'
[0] (byte) bar_thing1 ← (byte) 'a'
[1] (byte) bar_thing2 ← (byte) 'b'
[2] (byte[$c]) bar_thing3#0 ← (const string) $0
to:@1
@1: scope:[] from @begin
@ -198,65 +202,55 @@ FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from @1
[6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr)
[7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0)
[8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2)
[6] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0)
[7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2)
to:main::@1
main::@1: scope:[main] from main main::@1
[9] (byte) main::i#4 ← phi( main/(byte) 2 main::@1/(byte) main::i#3 )
[9] (byte) main::j#2 ← phi( main/(byte) 0 main::@1/(byte) main::j#1 )
[10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3
[11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2)
[12] (byte) main::i#3 ← ++ (byte) main::i#4
[13] (byte) main::j#1 ← ++ (byte) main::j#2
[14] if((byte) main::j#1!=(byte) $c) goto main::@1
[8] (byte) main::i#4 ← phi( main/(byte) 2 main::@1/(byte) main::i#3 )
[8] (byte) main::j#2 ← phi( main/(byte) 0 main::@1/(byte) main::j#1 )
[9] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2)
[10] (byte) main::i#3 ← ++ (byte) main::i#4
[11] (byte) main::j#1 ← ++ (byte) main::j#2
[12] if((byte) main::j#1!=(byte) $c) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[15] return
[13] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) bar_thing1
(byte) bar_thing1#0 20.0
(byte) bar_thing2
(byte) bar_thing2#0 20.0
(byte) bar_thing1 memory 20.0
(byte) bar_thing2 memory 20.0
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0 20.0
(byte) foo::thing1
(byte) foo::thing2
(byte[$c]) foo::thing3
(void()) main()
(byte[$c]) main::$4 22.0
(struct foo*) main::barp
(struct foo*) main::barp#0 0.2222222222222222
(byte) main::i
(byte) main::i#3 7.333333333333333
(byte) main::i#4 11.0
(byte) main::i#4 16.5
(byte) main::j
(byte) main::j#1 16.5
(byte) main::j#2 8.25
(byte) main::j#2 11.0
Initial phi equivalence classes
[ main::j#2 main::j#1 ]
[ main::i#4 main::i#3 ]
Added variable main::barp#0 to zero page equivalence class [ main::barp#0 ]
Added variable main::$4 to zero page equivalence class [ main::$4 ]
Added variable bar_thing1 to zero page equivalence class [ bar_thing1 ]
Added variable bar_thing2 to zero page equivalence class [ bar_thing2 ]
Complete equivalence classes
[ main::j#2 main::j#1 ]
[ main::i#4 main::i#3 ]
[ bar_thing1#0 ]
[ bar_thing2#0 ]
[ bar_thing3#0 ]
[ main::barp#0 ]
[ main::$4 ]
[ bar_thing1 ]
[ bar_thing2 ]
Allocated zp ZP_BYTE:2 [ main::j#2 main::j#1 ]
Allocated zp ZP_BYTE:3 [ main::i#4 main::i#3 ]
Allocated zp ZP_BYTE:4 [ bar_thing1#0 ]
Allocated zp ZP_BYTE:5 [ bar_thing2#0 ]
Allocated zp ZP_WORD:6 [ bar_thing3#0 ]
Allocated zp ZP_WORD:8 [ main::barp#0 ]
Allocated zp ZP_WORD:10 [ main::$4 ]
Allocated zp ZP_WORD:4 [ bar_thing3#0 ]
Allocated mem [ bar_thing1 ]
Allocated mem [ bar_thing2 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
@ -270,18 +264,15 @@ Target platform is c64basic / MOS6502X
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 4
.label bar_thing2 = 5
.label bar_thing3 = 6
.label bar_thing3 = 4
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta.z bar_thing2
sta bar_thing2
// [2] (byte[$c]) bar_thing3#0 ← (const string) $0 -- pbuz1=pbuc1
lda #<__0
sta.z bar_thing3
@ -301,115 +292,87 @@ __bend_from___b1:
__bend:
// main
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label __4 = $a
.label barp = 8
.label i = 3
.label j = 2
// [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
// [6] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuc2
lda barp
sta SCREEN
// [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=_deref_pbuc2
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
// [9] phi from main to main::@1 [phi:main->main::@1]
// [8] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [9] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuz1=vbuc1
// [8] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #2
sta.z i
// [9] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
// [8] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1
lda #0
sta.z j
jmp __b1
// [9] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [8] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [9] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [9] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
// [8] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [8] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
jmp __b1
// main::@1
__b1:
// [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
// [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz3
ldx.z i
// [9] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2
ldy.z j
lda (__4),y
sta SCREEN,x
// [12] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuz1=_inc_vbuz1
lda barp+OFFSET_STRUCT_FOO_THING3,y
ldy.z i
sta SCREEN,y
// [10] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuz1=_inc_vbuz1
inc.z i
// [13] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuz1=_inc_vbuz1
// [11] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuz1=_inc_vbuz1
inc.z j
// [14] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
// [12] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$c
cmp.z j
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [15] return
// [13] return
rts
}
// File Data
__0: .text "qwe"
.byte 0
bar_thing1: .byte 0
bar_thing2: .byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] (byte) bar_thing1#0 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2#0 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [0] (byte) bar_thing1 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [2] (byte[$c]) bar_thing3#0 ← (const string) $0 [ ] ( [ ] ) always clobbers reg byte a
Statement [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [9] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2) [ main::j#2 main::i#4 ] ( main:4 [ main::j#2 main::i#4 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::j#2 main::j#1 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ main::i#4 main::i#3 ]
Statement [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) [ main::barp#0 main::j#2 main::i#4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 ] ) always clobbers reg byte a
Statement [0] (byte) bar_thing1#0 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2#0 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [0] (byte) bar_thing1 ← (byte) 'a' [ ] ( [ ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2 ← (byte) 'b' [ ] ( [ ] ) always clobbers reg byte a
Statement [2] (byte[$c]) bar_thing3#0 ← (const string) $0 [ ] ( [ ] ) always clobbers reg byte a
Statement [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) [ main::barp#0 ] ( main:4 [ main::barp#0 ] ) always clobbers reg byte a reg byte y
Statement [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 main::$4 ] ) always clobbers reg byte a
Statement [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) [ main::barp#0 main::j#2 main::i#4 ] ( main:4 [ main::barp#0 main::j#2 main::i#4 ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [9] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2) [ main::j#2 main::i#4 ] ( main:4 [ main::j#2 main::i#4 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ main::j#2 main::j#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:3 [ main::i#4 main::i#3 ] : zp ZP_BYTE:3 , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:4 [ bar_thing1#0 ] : zp ZP_BYTE:4 ,
Potential registers zp ZP_BYTE:5 [ bar_thing2#0 ] : zp ZP_BYTE:5 ,
Potential registers zp ZP_WORD:6 [ bar_thing3#0 ] : zp ZP_WORD:6 ,
Potential registers zp ZP_WORD:8 [ main::barp#0 ] : zp ZP_WORD:8 ,
Potential registers zp ZP_WORD:10 [ main::$4 ] : zp ZP_WORD:10 ,
Potential registers zp ZP_WORD:4 [ bar_thing3#0 ] : zp ZP_WORD:4 ,
Potential registers mem [ bar_thing1 ] : mem ,
Potential registers mem [ bar_thing2 ] : mem ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 24.75: zp ZP_BYTE:2 [ main::j#2 main::j#1 ] 22: zp ZP_WORD:10 [ main::$4 ] 18.33: zp ZP_BYTE:3 [ main::i#4 main::i#3 ] 0.22: zp ZP_WORD:8 [ main::barp#0 ]
Uplift Scope [] 20: zp ZP_BYTE:4 [ bar_thing1#0 ] 20: zp ZP_BYTE:5 [ bar_thing2#0 ] 20: zp ZP_WORD:6 [ bar_thing3#0 ]
Uplift Scope [] 20: zp ZP_WORD:4 [ bar_thing3#0 ] 20: mem [ bar_thing1 ] 20: mem [ bar_thing2 ]
Uplift Scope [main] 27.5: zp ZP_BYTE:2 [ main::j#2 main::j#1 ] 23.83: zp ZP_BYTE:3 [ main::i#4 main::i#3 ]
Uplift Scope [foo]
Uplifting [main] best 570 combination reg byte y [ main::j#2 main::j#1 ] zp ZP_WORD:10 [ main::$4 ] reg byte x [ main::i#4 main::i#3 ] zp ZP_WORD:8 [ main::barp#0 ]
Uplifting [] best 570 combination zp ZP_BYTE:4 [ bar_thing1#0 ] zp ZP_BYTE:5 [ bar_thing2#0 ] zp ZP_WORD:6 [ bar_thing3#0 ]
Uplifting [foo] best 570 combination
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ bar_thing1#0 ]
Uplifting [] best 570 combination zp ZP_BYTE:4 [ bar_thing1#0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:5 [ bar_thing2#0 ]
Uplifting [] best 570 combination zp ZP_BYTE:5 [ bar_thing2#0 ]
Allocated (was zp ZP_BYTE:4) zp ZP_BYTE:2 [ bar_thing1#0 ]
Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:3 [ bar_thing2#0 ]
Allocated (was zp ZP_WORD:6) zp ZP_WORD:4 [ bar_thing3#0 ]
Allocated (was zp ZP_WORD:8) zp ZP_WORD:6 [ main::barp#0 ]
Allocated (was zp ZP_WORD:10) zp ZP_WORD:8 [ main::$4 ]
Uplifting [] best 576 combination zp ZP_WORD:4 [ bar_thing3#0 ] mem [ bar_thing1 ] mem [ bar_thing2 ]
Uplifting [main] best 366 combination reg byte y [ main::j#2 main::j#1 ] reg byte x [ main::i#4 main::i#3 ]
Uplifting [foo] best 366 combination
Allocated (was zp ZP_WORD:4) zp ZP_WORD:2 [ bar_thing3#0 ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@ -422,18 +385,15 @@ ASSEMBLER BEFORE OPTIMIZATION
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
.label bar_thing3 = 4
.label bar_thing3 = 2
// @begin
__bbegin:
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta.z bar_thing2
sta bar_thing2
// [2] (byte[$c]) bar_thing3#0 ← (const string) $0 -- pbuz1=pbuc1
lda #<__0
sta.z bar_thing3
@ -453,63 +413,49 @@ __bend_from___b1:
__bend:
// main
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label __4 = 8
.label barp = 6
// [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
// [6] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuc2
lda barp
sta SCREEN
// [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=_deref_pbuc2
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
// [9] phi from main to main::@1 [phi:main->main::@1]
// [8] phi from main to main::@1 [phi:main->main::@1]
__b1_from_main:
// [9] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [8] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #2
// [9] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
// [8] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
ldy #0
jmp __b1
// [9] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [8] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
__b1_from___b1:
// [9] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [9] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
// [8] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [8] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
jmp __b1
// main::@1
__b1:
// [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
// [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (__4),y
// [9] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy
lda barp+OFFSET_STRUCT_FOO_THING3,y
sta SCREEN,x
// [12] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
// [10] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
// [13] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuyy=_inc_vbuyy
// [11] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuyy=_inc_vbuyy
iny
// [14] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
// [12] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
cpy #$c
bne __b1_from___b1
jmp __breturn
// main::@return
__breturn:
// [15] return
// [13] return
rts
}
// File Data
__0: .text "qwe"
.byte 0
bar_thing1: .byte 0
bar_thing2: .byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
@ -539,41 +485,35 @@ FINAL SYMBOL TABLE
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const byte) OFFSET_STRUCT_FOO_THING3 OFFSET_STRUCT_FOO_THING3 = (byte) 2
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte) bar_thing1 memory mem 20.0
(byte) bar_thing2 memory mem 20.0
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0 bar_thing3 zp ZP_WORD:4 20.0
(byte[$c]) bar_thing3#0 bar_thing3 zp ZP_WORD:2 20.0
(byte) foo::thing1
(byte) foo::thing2
(byte[$c]) foo::thing3
(void()) main()
(byte[$c]) main::$4 $4 zp ZP_WORD:8 22.0
(label) main::@1
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:6 0.2222222222222222
(const struct foo*) main::barp#0 barp = (struct foo*)&(byte) bar_thing1
(byte) main::i
(byte) main::i#3 reg byte x 7.333333333333333
(byte) main::i#4 reg byte x 11.0
(byte) main::i#4 reg byte x 16.5
(byte) main::j
(byte) main::j#1 reg byte y 16.5
(byte) main::j#2 reg byte y 8.25
(byte) main::j#2 reg byte y 11.0
reg byte y [ main::j#2 main::j#1 ]
reg byte x [ main::i#4 main::i#3 ]
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ bar_thing3#0 ]
zp ZP_WORD:6 [ main::barp#0 ]
zp ZP_WORD:8 [ main::$4 ]
zp ZP_WORD:2 [ bar_thing3#0 ]
mem [ bar_thing1 ]
mem [ bar_thing2 ]
FINAL ASSEMBLER
Score: 480
Score: 276
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
@ -585,19 +525,16 @@ Score: 480
// Global Constants & labels
.const OFFSET_STRUCT_FOO_THING2 = 1
.const OFFSET_STRUCT_FOO_THING3 = 2
.label bar_ptr = bar_thing1
.label bar_thing1 = 2
.label bar_thing2 = 3
.label bar_thing3 = 4
.label bar_thing3 = 2
// @begin
__bbegin:
// bar = { 'a', 'b', "qwe" }
// [0] (byte) bar_thing1#0 ← (byte) 'a' -- vbuz1=vbuc1
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta.z bar_thing1
// [1] (byte) bar_thing2#0 ← (byte) 'b' -- vbuz1=vbuc1
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta.z bar_thing2
sta bar_thing2
// [2] (byte[$c]) bar_thing3#0 ← (const string) $0 -- pbuz1=pbuc1
lda #<__0
sta.z bar_thing3
@ -612,62 +549,47 @@ __bbegin:
// @end
// main
main: {
.label barp = bar_thing1
.label SCREEN = $400
.label __4 = 8
.label barp = 6
// barp = &bar
// [6] (struct foo*) main::barp#0 ← & *((const struct foo*) bar_ptr) -- pssz1=_addr__deref_pssc1
lda #<bar_ptr
sta.z barp
lda #>bar_ptr
sta.z barp+1
// SCREEN[i++] = barp->thing1
// [7] *((const byte*) main::SCREEN) ← *((byte*)(struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuz1
ldy #0
lda (barp),y
// [6] *((const byte*) main::SCREEN) ← *((byte*)(const struct foo*) main::barp#0) -- _deref_pbuc1=_deref_pbuc2
lda barp
sta SCREEN
// SCREEN[i++] = barp->thing2
// [8] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=pbuz1_derefidx_vbuc2
ldy #OFFSET_STRUCT_FOO_THING2
lda (barp),y
// [7] *((const byte*) main::SCREEN+(byte) 1) ← *((byte*)(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING2) -- _deref_pbuc1=_deref_pbuc2
lda barp+OFFSET_STRUCT_FOO_THING2
sta SCREEN+1
// [9] phi from main to main::@1 [phi:main->main::@1]
// [9] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuxx=vbuc1
// [8] phi from main to main::@1 [phi:main->main::@1]
// [8] phi (byte) main::i#4 = (byte) 2 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #2
// [9] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
// [8] phi (byte) main::j#2 = (byte) 0 [phi:main->main::@1#1] -- vbuyy=vbuc1
ldy #0
// [9] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [9] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [9] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
// [8] phi from main::@1 to main::@1 [phi:main::@1->main::@1]
// [8] phi (byte) main::i#4 = (byte) main::i#3 [phi:main::@1->main::@1#0] -- register_copy
// [8] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@1->main::@1#1] -- register_copy
// main::@1
__b1:
// SCREEN[i++] = barp->thing3[j]
// [10] (byte[$c]) main::$4 ← (byte[$c])(struct foo*) main::barp#0 + (const byte) OFFSET_STRUCT_FOO_THING3 -- pbuz1=pbuz2_plus_vbuc1
lda #OFFSET_STRUCT_FOO_THING3
clc
adc.z barp
sta.z __4
lda #0
adc.z barp+1
sta.z __4+1
// [11] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c]) main::$4 + (byte) main::j#2) -- pbuc1_derefidx_vbuxx=pbuz1_derefidx_vbuyy
lda (__4),y
// [9] *((const byte*) main::SCREEN + (byte) main::i#4) ← *((byte[$c])(const struct foo*) main::barp#0+(const byte) OFFSET_STRUCT_FOO_THING3 + (byte) main::j#2) -- pbuc1_derefidx_vbuxx=pbuc2_derefidx_vbuyy
lda barp+OFFSET_STRUCT_FOO_THING3,y
sta SCREEN,x
// SCREEN[i++] = barp->thing3[j];
// [12] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
// [10] (byte) main::i#3 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx
inx
// for( char j: 0..11)
// [13] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuyy=_inc_vbuyy
// [11] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuyy=_inc_vbuyy
iny
// [14] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
// [12] if((byte) main::j#1!=(byte) $c) goto main::@1 -- vbuyy_neq_vbuc1_then_la1
cpy #$c
bne __b1
// main::@return
// }
// [15] return
// [13] return
rts
}
// File Data
__0: .text "qwe"
.byte 0
bar_thing1: .byte 0
bar_thing2: .byte 0

View File

@ -4,34 +4,28 @@
(label) @end
(const byte) OFFSET_STRUCT_FOO_THING2 OFFSET_STRUCT_FOO_THING2 = (byte) 1
(const byte) OFFSET_STRUCT_FOO_THING3 OFFSET_STRUCT_FOO_THING3 = (byte) 2
(const struct foo*) bar_ptr bar_ptr = (struct foo*)&(byte) bar_thing1#0
(byte) bar_thing1
(byte) bar_thing1#0 bar_thing1 zp ZP_BYTE:2 20.0
(byte) bar_thing2
(byte) bar_thing2#0 bar_thing2 zp ZP_BYTE:3 20.0
(byte) bar_thing1 memory mem 20.0
(byte) bar_thing2 memory mem 20.0
(byte[$c]) bar_thing3
(byte[$c]) bar_thing3#0 bar_thing3 zp ZP_WORD:4 20.0
(byte[$c]) bar_thing3#0 bar_thing3 zp ZP_WORD:2 20.0
(byte) foo::thing1
(byte) foo::thing2
(byte[$c]) foo::thing3
(void()) main()
(byte[$c]) main::$4 $4 zp ZP_WORD:8 22.0
(label) main::@1
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(struct foo*) main::barp
(struct foo*) main::barp#0 barp zp ZP_WORD:6 0.2222222222222222
(const struct foo*) main::barp#0 barp = (struct foo*)&(byte) bar_thing1
(byte) main::i
(byte) main::i#3 reg byte x 7.333333333333333
(byte) main::i#4 reg byte x 11.0
(byte) main::i#4 reg byte x 16.5
(byte) main::j
(byte) main::j#1 reg byte y 16.5
(byte) main::j#2 reg byte y 8.25
(byte) main::j#2 reg byte y 11.0
reg byte y [ main::j#2 main::j#1 ]
reg byte x [ main::i#4 main::i#3 ]
zp ZP_BYTE:2 [ bar_thing1#0 ]
zp ZP_BYTE:3 [ bar_thing2#0 ]
zp ZP_WORD:4 [ bar_thing3#0 ]
zp ZP_WORD:6 [ main::barp#0 ]
zp ZP_WORD:8 [ main::$4 ]
zp ZP_WORD:2 [ bar_thing3#0 ]
mem [ bar_thing1 ]
mem [ bar_thing2 ]

View File

@ -0,0 +1,22 @@
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
__bbegin:
lda #'a'
sta bar_thing1
lda #'b'
sta bar_thing2
jsr main
rts
main: {
.label SCREEN = $400
lda bar_thing1
sta SCREEN
lda bar_thing2
sta SCREEN+1
rts
}
bar_thing1: .byte 0
bar_thing2: .byte 0

View File

@ -0,0 +1,19 @@
@begin: scope:[] from
[0] (byte) bar_thing1 ← (byte) 'a'
[1] (byte) bar_thing2 ← (byte) 'b'
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
to:@end
@end: scope:[] from @1
[4] phi()
(void()) main()
main: scope:[main] from @1
[5] *((const byte*) main::SCREEN) ← (byte) bar_thing1
[6] *((const byte*) main::SCREEN+(byte) 1) ← (byte) bar_thing2
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return

View File

@ -0,0 +1,324 @@
Created struct value member variable (byte) bar_thing1
Created struct value member variable (byte) bar_thing2
Converted struct value to member variables (struct foo) bar
Adding struct value list initializer (byte) bar_thing1 ← (byte) 'a'
Adding struct value list initializer (byte) bar_thing2 ← (byte) 'b'
Replacing struct member reference (struct foo) bar.thing1 with member unwinding reference (byte) bar_thing1
Replacing struct member reference (struct foo) bar.thing2 with member unwinding reference (byte) bar_thing2
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(byte) bar_thing1 ← (byte) 'a'
(byte) bar_thing2 ← (byte) 'b'
to:@1
(void()) main()
main: scope:[main] from @1
(byte*) main::SCREEN ← ((byte*)) (number) $400
(byte) main::i#0 ← (number) 0
*((byte*) main::SCREEN + (byte) main::i#0) ← (byte) bar_thing1
(byte) main::i#1 ← ++ (byte) main::i#0
*((byte*) main::SCREEN + (byte) main::i#1) ← (byte) bar_thing2
(byte) main::i#2 ← ++ (byte) main::i#1
to:main::@return
main::@return: scope:[main] from main
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) bar_thing1 memory
(byte) bar_thing2 memory
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
Adding number conversion cast (unumber) 0 in (byte) main::i#0 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (byte*) main::SCREEN ← (byte*)(number) $400
Inlining cast (byte) main::i#0 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant (const byte*) main::SCREEN = (byte*) 1024
Constant (const byte) main::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Simplifying expression containing zero main::SCREEN in [4] *((const byte*) main::SCREEN + (const byte) main::i#0) ← (byte) bar_thing1
Successful SSA optimization PassNSimplifyExpressionWithZero
Eliminating unused variable (byte) main::i#2 and assignment [5] (byte) main::i#2 ← ++ (byte) main::i#1
Successful SSA optimization PassNEliminateUnusedVars
Constant right-side identified [3] (byte) main::i#1 ← ++ (const byte) main::i#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte) main::i#1 = ++main::i#0
Successful SSA optimization Pass2ConstantIdentification
Inlining constant with different constant siblings (const byte) main::i#0
Inlining constant with different constant siblings (const byte) main::i#1
Constant inlined main::i#0 = (byte) 0
Constant inlined main::i#1 = ++(byte) 0
Successful SSA optimization Pass2ConstantInlining
Consolidated array index constant in *(main::SCREEN+++0)
Successful SSA optimization Pass2ConstantAdditionElimination
Simplifying constant integer increment ++0
Successful SSA optimization Pass2ConstantSimplification
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:3
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Culled Empty Block (label) @2
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] (byte) bar_thing1 ← (byte) 'a'
[1] (byte) bar_thing2 ← (byte) 'b'
to:@1
@1: scope:[] from @begin
[2] phi()
[3] call main
to:@end
@end: scope:[] from @1
[4] phi()
(void()) main()
main: scope:[main] from @1
[5] *((const byte*) main::SCREEN) ← (byte) bar_thing1
[6] *((const byte*) main::SCREEN+(byte) 1) ← (byte) bar_thing2
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte) bar_thing1 memory 1.3333333333333333
(byte) bar_thing2 memory 1.3333333333333333
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(byte) main::i
Initial phi equivalence classes
Added variable bar_thing1 to zero page equivalence class [ bar_thing1 ]
Added variable bar_thing2 to zero page equivalence class [ bar_thing2 ]
Complete equivalence classes
[ bar_thing1 ]
[ bar_thing2 ]
Allocated mem [ bar_thing1 ]
Allocated mem [ bar_thing2 ]
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
// @begin
__bbegin:
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label SCREEN = $400
// [5] *((const byte*) main::SCREEN) ← (byte) bar_thing1 -- _deref_pbuc1=vbum1
lda bar_thing1
sta SCREEN
// [6] *((const byte*) main::SCREEN+(byte) 1) ← (byte) bar_thing2 -- _deref_pbuc1=vbum1
lda bar_thing2
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [7] return
rts
}
// File Data
bar_thing1: .byte 0
bar_thing2: .byte 0
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] (byte) bar_thing1 ← (byte) 'a' [ bar_thing1 ] ( [ bar_thing1 ] ) always clobbers reg byte a
Statement [1] (byte) bar_thing2 ← (byte) 'b' [ bar_thing1 bar_thing2 ] ( [ bar_thing1 bar_thing2 ] ) always clobbers reg byte a
Statement [5] *((const byte*) main::SCREEN) ← (byte) bar_thing1 [ bar_thing2 ] ( main:3 [ bar_thing2 ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN+(byte) 1) ← (byte) bar_thing2 [ ] ( main:3 [ ] ) always clobbers reg byte a
Potential registers mem [ bar_thing1 ] : mem ,
Potential registers mem [ bar_thing2 ] : mem ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 1.33: mem [ bar_thing1 ] 1.33: mem [ bar_thing2 ]
Uplift Scope [foo]
Uplift Scope [main]
Uplifting [] best 49 combination mem [ bar_thing1 ] mem [ bar_thing2 ]
Uplifting [foo] best 49 combination
Uplifting [main] best 49 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
// @begin
__bbegin:
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
__b1_from___bbegin:
jmp __b1
// @1
__b1:
// [3] call main
jsr main
// [4] phi from @1 to @end [phi:@1->@end]
__bend_from___b1:
jmp __bend
// @end
__bend:
// main
main: {
.label SCREEN = $400
// [5] *((const byte*) main::SCREEN) ← (byte) bar_thing1 -- _deref_pbuc1=vbum1
lda bar_thing1
sta SCREEN
// [6] *((const byte*) main::SCREEN+(byte) 1) ← (byte) bar_thing2 -- _deref_pbuc1=vbum1
lda bar_thing2
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [7] return
rts
}
// File Data
bar_thing1: .byte 0
bar_thing2: .byte 0
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __bend
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __b1_from___bbegin:
Removing instruction __bend_from___b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction __b1:
Removing instruction __bend:
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(byte) bar_thing1 memory mem 1.3333333333333333
(byte) bar_thing2 memory mem 1.3333333333333333
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(byte) main::i
mem [ bar_thing1 ]
mem [ bar_thing2 ]
FINAL ASSEMBLER
Score: 46
// File Comments
// Test declaring a variable as "memory", meaning it will be stored in memory and accessed through an implicit pointer (using load/store)
// Test a memory variable struct value
// Upstart
.pc = $801 "Basic"
:BasicUpstart(__bbegin)
.pc = $80d "Program"
// Global Constants & labels
// @begin
__bbegin:
// bar = { 'a', 'b' }
// [0] (byte) bar_thing1 ← (byte) 'a' -- vbum1=vbuc1
lda #'a'
sta bar_thing1
// [1] (byte) bar_thing2 ← (byte) 'b' -- vbum1=vbuc1
lda #'b'
sta bar_thing2
// [2] phi from @begin to @1 [phi:@begin->@1]
// @1
// [3] call main
jsr main
rts
// [4] phi from @1 to @end [phi:@1->@end]
// @end
// main
main: {
.label SCREEN = $400
// SCREEN[i++] = bar.thing1
// [5] *((const byte*) main::SCREEN) ← (byte) bar_thing1 -- _deref_pbuc1=vbum1
lda bar_thing1
sta SCREEN
// SCREEN[i++] = bar.thing2
// [6] *((const byte*) main::SCREEN+(byte) 1) ← (byte) bar_thing2 -- _deref_pbuc1=vbum1
lda bar_thing2
sta SCREEN+1
// main::@return
// }
// [7] return
rts
}
// File Data
bar_thing1: .byte 0
bar_thing2: .byte 0

View File

@ -0,0 +1,14 @@
(label) @1
(label) @begin
(label) @end
(byte) bar_thing1 memory mem 1.3333333333333333
(byte) bar_thing2 memory mem 1.3333333333333333
(byte) foo::thing1
(byte) foo::thing2
(void()) main()
(label) main::@return
(const byte*) main::SCREEN SCREEN = (byte*) 1024
(byte) main::i
mem [ bar_thing1 ]
mem [ bar_thing2 ]