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

Improved pointer-to-pointer functionality significantly.

This commit is contained in:
jespergravgaard 2019-04-05 01:05:15 +02:00
parent 44b6ed1fb8
commit 9ccc5d828f
20 changed files with 1575 additions and 106 deletions

View File

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

View File

@ -0,0 +1,6 @@
ldy #0
lda #<{c1}
sta ({z1}),y
iny
lda #>{c1}
sta ({z1}),y

View File

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

View File

@ -0,0 +1,2 @@
ldy #0
lda ({c1}),y

View File

@ -123,10 +123,20 @@ public class CompileLog {
this.verboseSequencePlan = verboseSequencePlan; this.verboseSequencePlan = verboseSequencePlan;
} }
public CompileLog verboseParse() {
setVerboseParse(true);
return this;
}
public void setVerboseParse(boolean verboseParse) { public void setVerboseParse(boolean verboseParse) {
this.verboseParse = verboseParse; this.verboseParse = verboseParse;
} }
public CompileLog verboseCreateSsa() {
setVerboseCreateSsa(true);
return this;
}
public void setVerboseCreateSsa(boolean verboseCreateSsa) { public void setVerboseCreateSsa(boolean verboseCreateSsa) {
this.verboseCreateSsa = verboseCreateSsa; this.verboseCreateSsa = verboseCreateSsa;
} }
@ -135,6 +145,11 @@ public class CompileLog {
return verboseUplift; return verboseUplift;
} }
public CompileLog verboseUplift() {
setVerboseUplift(true);
return this;
}
public void setVerboseUplift(boolean verboseUplift) { public void setVerboseUplift(boolean verboseUplift) {
this.verboseUplift = verboseUplift; this.verboseUplift = verboseUplift;
} }
@ -167,6 +182,12 @@ public class CompileLog {
return verboseSSAOptimize; return verboseSSAOptimize;
} }
public CompileLog setVerboseSSAOptimize() {
setVerboseSSAOptimize(true);
return this;
}
public void setVerboseSSAOptimize(boolean verboseSSAOptimize) { public void setVerboseSSAOptimize(boolean verboseSSAOptimize) {
this.verboseSSAOptimize = verboseSSAOptimize; this.verboseSSAOptimize = verboseSSAOptimize;
} }

View File

@ -45,13 +45,26 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
for(VariableRef constRef : constVars) { for(VariableRef constRef : constVars) {
Variable variable = getProgram().getScope().getVariable(constRef); Variable variable = getProgram().getScope().getVariable(constRef);
ConstantVariableValue constVarVal = constants.get(constRef);
// Weed out all variables that are affected by the address-of operator // Weed out all variables that are affected by the address-of operator
if(isAddressOfUsed(constRef, getProgram())) { if(isAddressOfUsed(constRef, getProgram())) {
// If the assignment has an operator then replace it with the single constant value
if(constVarVal.getAssignment() instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) constVarVal.getAssignment();
if(assignment.getOperator()!=null) {
getLog().append("Constant right-side identified " + assignment.toString(getProgram(), false));
assignment.setOperator(null);
assignment.setrValue1(null);
assignment.setrValue2(constVarVal.getConstantValue());
}
}
// But do not remove the variable
constants.remove(constRef); constants.remove(constRef);
continue; continue;
} }
ConstantVariableValue constVarVal = constants.get(constRef);
Scope constScope = variable.getScope(); Scope constScope = variable.getScope();
ConstantValue constVal = constVarVal.getConstantValue(); ConstantValue constVal = constVarVal.getConstantValue();
@ -80,7 +93,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
constVal); constVal);
constantVar.setDeclaredAlignment(variable.getDeclaredAlignment()); constantVar.setDeclaredAlignment(variable.getDeclaredAlignment());
constantVar.setDeclaredRegister(variable.getDeclaredRegister()); constantVar.setDeclaredRegister(variable.getDeclaredRegister());
if(variable.getComments().size()>0) { if(variable.getComments().size() > 0) {
constantVar.setComments(variable.getComments()); constantVar.setComments(variable.getComments());
} else { } else {
constantVar.setComments(constVarVal.getAssignment().getComments()); constantVar.setComments(constVarVal.getAssignment().getComments());
@ -111,7 +124,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
/** /**
* The statement that assigns the variable its value (the assignment will be removed at the end). * The statement that assigns the variable its value (the assignment will be removed at the end).
* Either a {@link StatementAssignment} or a {@link StatementPhiBlock}. * Either a {@link StatementAssignment} or a {@link StatementPhiBlock}.
* */ */
private Statement assignment; private Statement assignment;
public ConstantVariableValue(VariableRef variableRef, ConstantValue constantValue, Statement assignment) { public ConstantVariableValue(VariableRef variableRef, ConstantValue constantValue, Statement assignment) {
@ -182,83 +195,85 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
// Volatile variables cannot be constant // Volatile variables cannot be constant
return; return;
} }
if(assignment.getrValue1() == null && getConstant(assignment.getrValue2()) != null) { ConstantValue constant = getConstantAssignmentValue(assignment, var.getType());
if(assignment.getOperator() == null) { if(constant != null) {
// Constant assignment constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
ConstantValue constant = getConstant(assignment.getrValue2());
if(constant != null) {
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
} else {
// Constant unary expression
ConstantValue constant = createUnary(
(OperatorUnary) assignment.getOperator(),
getConstant(assignment.getrValue2())
);
if(constant != null) {
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
}
} else if(getConstant(assignment.getrValue1()) != null && getConstant(assignment.getrValue2()) != null) {
// Constant binary expression
ConstantValue constant = createBinary(
getConstant(assignment.getrValue1()),
(OperatorBinary) assignment.getOperator(),
getConstant(assignment.getrValue2()),
getScope());
if(constant != null) {
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
} else if(assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
// A candidate for a constant list - examine to confirm
Variable lVariable = getScope().getVariable((VariableRef) lValue);
if(lVariable.getType() instanceof SymbolTypeArray) {
ValueList valueList = (ValueList) assignment.getrValue2();
List<RValue> values = valueList.getList();
boolean allConstant = true;
// Type of the elements of the list (deducted from the type of all elements)
SymbolType listType = null;
List<ConstantValue> elements = new ArrayList<>();
for(RValue elmValue : values) {
if(elmValue instanceof ConstantValue) {
ConstantValue constantValue = (ConstantValue) elmValue;
SymbolType elmType = constantValue.getType(getScope());
if(listType == null) {
listType = elmType;
} else {
if(!SymbolTypeInference.typeMatch(listType, elmType)) {
SymbolType intersectType = SymbolTypeInference.intersectTypes(listType, elmType);
if(intersectType == null) {
// No overlap between list type and element type
throw new RuntimeException("Array type " + listType + " does not match element type" + elmType + ". Array: " + valueList.toString(getProgram()));
} else {
listType = intersectType;
}
}
}
elements.add(constantValue);
} else {
allConstant = false;
listType = null;
break;
}
}
if(allConstant && listType != null) {
// Constant list confirmed!
ConstantValue constant = new ConstantArrayList(elements, listType);
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
}
}
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
// Constant address-of variable
if(assignment.getrValue2() instanceof SymbolRef) {
ConstantSymbolPointer constantSymbolPointer = new ConstantSymbolPointer((SymbolRef) assignment.getrValue2());
constants.put(variable, new ConstantVariableValue(variable, constantSymbolPointer, assignment));
}
} }
} }
} }
/**
* Examine the right side of an assignment and if it is constant then return the constant value.
* @param assignment The assignment to examine
* @param lValueType The type of the lvalue
* @return The constant value if the right side is constant
*/
private ConstantValue getConstantAssignmentValue(StatementAssignment assignment, SymbolType lValueType) {
if(assignment.getrValue1() == null && getConstant(assignment.getrValue2()) != null) {
if(assignment.getOperator() == null) {
// Constant assignment
return getConstant(assignment.getrValue2());
} else {
// Constant unary expression
return createUnary(
(OperatorUnary) assignment.getOperator(),
getConstant(assignment.getrValue2())
);
}
} else if(getConstant(assignment.getrValue1()) != null && getConstant(assignment.getrValue2()) != null) {
// Constant binary expression
return createBinary(
getConstant(assignment.getrValue1()),
(OperatorBinary) assignment.getOperator(),
getConstant(assignment.getrValue2()),
getScope());
} else if(assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
// A candidate for a constant list - examine to confirm
if(lValueType instanceof SymbolTypeArray) {
ValueList valueList = (ValueList) assignment.getrValue2();
List<RValue> values = valueList.getList();
boolean allConstant = true;
// Type of the elements of the list (deducted from the type of all elements)
SymbolType listType = null;
List<ConstantValue> elements = new ArrayList<>();
for(RValue elmValue : values) {
if(elmValue instanceof ConstantValue) {
ConstantValue constantValue = (ConstantValue) elmValue;
SymbolType elmType = constantValue.getType(getScope());
if(listType == null) {
listType = elmType;
} else {
if(!SymbolTypeInference.typeMatch(listType, elmType)) {
SymbolType intersectType = SymbolTypeInference.intersectTypes(listType, elmType);
if(intersectType == null) {
// No overlap between list type and element type
throw new RuntimeException("Array type " + listType + " does not match element type" + elmType + ". Array: " + valueList.toString(getProgram()));
} else {
listType = intersectType;
}
}
}
elements.add(constantValue);
} else {
allConstant = false;
listType = null;
break;
}
}
if(allConstant && listType != null) {
// Constant list confirmed!
return new ConstantArrayList(elements, listType);
}
}
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
// Constant address-of variable
if(assignment.getrValue2() instanceof SymbolRef) {
return new ConstantSymbolPointer((SymbolRef) assignment.getrValue2());
}
}
return null;
}
/** /**
* If the rValue is a known constant return the constant value. * If the rValue is a known constant return the constant value.
* *

View File

@ -154,6 +154,7 @@ public class Pass4CodeGeneration {
*/ */
private void generateScopeEnding(AsmProgram asm, ScopeRef currentScope) { private void generateScopeEnding(AsmProgram asm, ScopeRef currentScope) {
if(!ScopeRef.ROOT.equals(currentScope)) { if(!ScopeRef.ROOT.equals(currentScope)) {
// Generate any indirect calls pending
for(String indirectCallAsmName : indirectCallAsmNames) { for(String indirectCallAsmName : indirectCallAsmNames) {
asm.addLabel("bi_"+indirectCallAsmName); asm.addLabel("bi_"+indirectCallAsmName);
asm.addInstruction("jmp", AsmAddressingMode.IND, indirectCallAsmName, false); asm.addInstruction("jmp", AsmAddressingMode.IND, indirectCallAsmName, false);
@ -164,6 +165,20 @@ public class Pass4CodeGeneration {
} }
} }
/**
* Add an indirect call to the assembler program. Also queues ASM for the indirect jump to be added at the end of the block.
* @param asm The ASM program being built
* @param procedureVariable The variable containing the function pointer
* @param codeScopeRef The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
*/
private void generateIndirectCall(AsmProgram asm, Variable procedureVariable, ScopeRef codeScopeRef) {
String varAsmName = AsmFormat.getAsmParamName(procedureVariable, codeScopeRef);
indirectCallAsmNames.add(varAsmName);
asm.addInstruction("jsr", AsmAddressingMode.ABS, "bi_" + varAsmName, false);
}
/** /**
* Generate a comment that describes the procedure signature and parameter transfer * Generate a comment that describes the procedure signature and parameter transfer
* @param asm The assembler program being generated * @param asm The assembler program being generated
@ -601,9 +616,7 @@ public class Pass4CodeGeneration {
supported = true; supported = true;
} else if(pointer instanceof VariableRef) { } else if(pointer instanceof VariableRef) {
Variable variable = getScope().getVariable((VariableRef) pointer); Variable variable = getScope().getVariable((VariableRef) pointer);
String varAsmName = AsmFormat.getAsmParamName(variable, block.getScope()); generateIndirectCall(asm, variable, block.getScope());
indirectCallAsmNames.add(varAsmName);
asm.addInstruction("jsr", AsmAddressingMode.ABS, "bi_"+varAsmName,false);
supported = true; supported = true;
} }
} else if(procedure instanceof VariableRef) { } else if(procedure instanceof VariableRef) {
@ -611,9 +624,7 @@ public class Pass4CodeGeneration {
SymbolType procedureVariableType = procedureVariable.getType(); SymbolType procedureVariableType = procedureVariable.getType();
if(procedureVariableType instanceof SymbolTypePointer) { if(procedureVariableType instanceof SymbolTypePointer) {
if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) { if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) {
String varAsmName = AsmFormat.getAsmParamName(procedureVariable, block.getScope()); generateIndirectCall(asm, procedureVariable, block.getScope());
indirectCallAsmNames.add(varAsmName);
asm.addInstruction("jsr", AsmAddressingMode.ABS, "bi_"+varAsmName,false);
supported = true; supported = true;
} }
} }

View File

@ -1,10 +1,7 @@
package dk.camelot64.kickc.passes; package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.*; import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.values.ConstantSymbolPointer;
import dk.camelot64.kickc.model.values.SymbolRef;
import dk.camelot64.kickc.model.values.VariableRef; import dk.camelot64.kickc.model.values.VariableRef;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.symbols.Variable; import dk.camelot64.kickc.model.symbols.Variable;
import java.util.ArrayList; import java.util.ArrayList;
@ -49,12 +46,12 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
Registers.RegisterType registerType = defaultRegister.getType(); Registers.RegisterType registerType = defaultRegister.getType();
List<Registers.Register> potentials = new ArrayList<>(); List<Registers.Register> potentials = new ArrayList<>();
potentials.add(defaultRegister); potentials.add(defaultRegister);
if(registerType.equals(Registers.RegisterType.ZP_BYTE) && !varRefExtracted(equivalenceClass) &&!varVolatile(equivalenceClass)) { if(registerType.equals(Registers.RegisterType.ZP_BYTE) && !isAddressOfUsed(equivalenceClass) &&!varVolatile(equivalenceClass)) {
potentials.add(Registers.getRegisterA()); potentials.add(Registers.getRegisterA());
potentials.add(Registers.getRegisterX()); potentials.add(Registers.getRegisterX());
potentials.add(Registers.getRegisterY()); potentials.add(Registers.getRegisterY());
} }
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !varRefExtracted(equivalenceClass) &&!varVolatile(equivalenceClass)) { if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !isAddressOfUsed(equivalenceClass) &&!varVolatile(equivalenceClass)) {
potentials.add(Registers.getRegisterA()); potentials.add(Registers.getRegisterA());
} }
registerPotentials.setPotentialRegisters(equivalenceClass, potentials); registerPotentials.setPotentialRegisters(equivalenceClass, potentials);
@ -83,14 +80,10 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
* @param equivalenceClass The equivalence class * @param equivalenceClass The equivalence class
* @return true if a variable reference is extracted * @return true if a variable reference is extracted
*/ */
private boolean varRefExtracted(LiveRangeEquivalenceClass equivalenceClass) { private boolean isAddressOfUsed(LiveRangeEquivalenceClass equivalenceClass) {
Collection<ConstantVar> allConstants = getProgram().getScope().getAllConstants(true); for(VariableRef variableRef : equivalenceClass.getVariables()) {
for(ConstantVar allConstant : allConstants) { if(Pass2ConstantIdentification.isAddressOfUsed(variableRef, getProgram())) {
if(allConstant.getValue() instanceof ConstantSymbolPointer) { return true;
SymbolRef toSym = ((ConstantSymbolPointer) allConstant.getValue()).getToSymbol();
if(equivalenceClass.getVariables().contains(toSym)) {
return true;
}
} }
} }
return false; return false;

View File

@ -32,6 +32,16 @@ public class TestPrograms {
public TestPrograms() { public TestPrograms() {
} }
@Test
public void testPointerPointer2() throws IOException, URISyntaxException {
compileAndCompare("pointer-pointer-2");
}
@Test
public void testPointerPointer1() throws IOException, URISyntaxException {
compileAndCompare("pointer-pointer-1" );
}
@Test @Test
public void testFunctionPointerNoargCall6() throws IOException, URISyntaxException { public void testFunctionPointerNoargCall6() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-6"); compileAndCompare("function-pointer-noarg-call-6");
@ -109,7 +119,7 @@ public class TestPrograms {
@Test @Test
public void testLocalScopeLoops() throws IOException, URISyntaxException { public void testLocalScopeLoops() throws IOException, URISyntaxException {
compileAndCompare("localscope-loops", getLogSysout()); compileAndCompare("localscope-loops");
} }
@Test @Test
@ -1470,11 +1480,11 @@ public class TestPrograms {
@AfterClass @AfterClass
public static void tearDown() { public static void tearDown() {
CompileLog log = getLogSysout(); CompileLog log = log();
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false); AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
} }
private static CompileLog getLogSysout() { private static CompileLog log() {
CompileLog log = new CompileLog(); CompileLog log = new CompileLog();
log.setSysOut(true); log.setSysOut(true);
return log; return log;

View File

@ -0,0 +1,11 @@
// Tests a simple pointer to a pointer
void main() {
const byte* SCREEN = $400;
byte b = 'a';
byte* pb = &b;
byte** ppb = &pb;
*SCREEN = **ppb;
}

View File

@ -0,0 +1,30 @@
// Tests pointer to pointer in a more complex setup
void main() {
byte* screen = $400;
byte* text;
for(byte i: 0..20) {
nexttext(&text);
while(*text!='@') {
*screen++ = *text++;
}
}
}
byte[] text1 = "camelot @";
byte[] text2 = "rex @";
byte textid = 0;
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
void nexttext(byte** textp) {
if((textid++&1)==0) {
*textp = text1;
} else {
*textp = text2;
}
}

View File

@ -0,0 +1,20 @@
// Tests a simple pointer to a pointer
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label SCREEN = $400
.label ppb = pb
.label b = 2
.label pb = 3
lda #'a'
sta b
lda #<b
sta pb
lda #>b
sta pb+1
ldy #0
lda (ppb),y
sta SCREEN
rts
}

View File

@ -0,0 +1,17 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] (byte) main::b#0 ← (byte) 'a'
[5] (byte*) main::pb#0 ← &(byte) main::b#0
[6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0))
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return

View File

@ -0,0 +1,286 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @1
(byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte) main::b#0 ← (byte) 'a'
(byte*~) main::$0 ← & (byte) main::b#0
(byte*) main::pb#0 ← (byte*~) main::$0
(byte**~) main::$1 ← & (byte*) main::pb#0
(byte**) main::ppb#0 ← (byte**~) main::$1
*((byte*) main::SCREEN#0) ← *(*((byte**) main::ppb#0))
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
(void()) main()
(byte*~) main::$0
(byte**~) main::$1
(label) main::@return
(byte*) main::SCREEN
(byte*) main::SCREEN#0
(byte) main::b
(byte) main::b#0
(byte*) main::pb
(byte*) main::pb#0
(byte**) main::ppb
(byte**) main::ppb#0
Culled Empty Block (label) @2
Successful SSA optimization Pass2CullEmptyBlocks
Alias (byte*) main::pb#0 = (byte*~) main::$0
Alias (byte**) main::ppb#0 = (byte**~) main::$1
Successful SSA optimization Pass2AliasElimination
Constant (const byte*) main::SCREEN#0 = ((byte*))$400
Constant right-side identified [2] (byte*) main::pb#0 ← & (byte) main::b#0
Constant (const byte**) main::ppb#0 = &main::pb#0
Successful SSA optimization Pass2ConstantIdentification
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] (byte) main::b#0 ← (byte) 'a'
[5] (byte*) main::pb#0 ← &(byte) main::b#0
[6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0))
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte*) main::SCREEN
(byte) main::b
(byte) main::b#0 2.0
(byte*) main::pb
(byte*) main::pb#0 20.0
(byte**) main::ppb
Initial phi equivalence classes
Added variable main::b#0 to zero page equivalence class [ main::b#0 ]
Added variable main::pb#0 to zero page equivalence class [ main::pb#0 ]
Complete equivalence classes
[ main::b#0 ]
[ main::pb#0 ]
Allocated zp ZP_BYTE:2 [ main::b#0 ]
Allocated zp ZP_WORD:3 [ main::pb#0 ]
INITIAL ASM
//SEG0 File Comments
// Tests a simple pointer to a pointer
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
.label ppb = pb
.label b = 2
.label pb = 3
//SEG10 [4] (byte) main::b#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta b
//SEG11 [5] (byte*) main::pb#0 ← &(byte) main::b#0 -- pbuz1=pbuc1
lda #<b
sta pb
lda #>b
sta pb+1
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref__deref_pptc2
ldy #0
lda (ppb),y
sta SCREEN
jmp breturn
//SEG13 main::@return
breturn:
//SEG14 [7] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] (byte) main::b#0 ← (byte) 'a' [ main::b#0 ] ( main:2 [ main::b#0 ] ) always clobbers reg byte a
Statement [5] (byte*) main::pb#0 ← &(byte) main::b#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y
Potential registers zp ZP_BYTE:2 [ main::b#0 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_WORD:3 [ main::pb#0 ] : zp ZP_WORD:3 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 20: zp ZP_WORD:3 [ main::pb#0 ] 2: zp ZP_BYTE:2 [ main::b#0 ]
Uplift Scope []
Uplifting [main] best 47 combination zp ZP_WORD:3 [ main::pb#0 ] zp ZP_BYTE:2 [ main::b#0 ]
Uplifting [] best 47 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::b#0 ]
Uplifting [main] best 47 combination zp ZP_BYTE:2 [ main::b#0 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests a simple pointer to a pointer
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label SCREEN = $400
.label ppb = pb
.label b = 2
.label pb = 3
//SEG10 [4] (byte) main::b#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta b
//SEG11 [5] (byte*) main::pb#0 ← &(byte) main::b#0 -- pbuz1=pbuc1
lda #<b
sta pb
lda #>b
sta pb+1
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref__deref_pptc2
ldy #0
lda (ppb),y
sta SCREEN
jmp breturn
//SEG13 main::@return
breturn:
//SEG14 [7] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction bend_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(byte) main::b
(byte) main::b#0 b zp ZP_BYTE:2 2.0
(byte*) main::pb
(byte*) main::pb#0 pb zp ZP_WORD:3 20.0
(byte**) main::ppb
(const byte**) main::ppb#0 ppb = &(byte*) main::pb#0
zp ZP_BYTE:2 [ main::b#0 ]
zp ZP_WORD:3 [ main::pb#0 ]
FINAL ASSEMBLER
Score: 32
//SEG0 File Comments
// Tests a simple pointer to a pointer
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
//SEG8 @end
//SEG9 main
main: {
.label SCREEN = $400
.label ppb = pb
.label b = 2
.label pb = 3
//SEG10 [4] (byte) main::b#0 ← (byte) 'a' -- vbuz1=vbuc1
lda #'a'
sta b
//SEG11 [5] (byte*) main::pb#0 ← &(byte) main::b#0 -- pbuz1=pbuc1
lda #<b
sta pb
lda #>b
sta pb+1
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref__deref_pptc2
ldy #0
lda (ppb),y
sta SCREEN
//SEG13 main::@return
//SEG14 [7] return
rts
}

View File

@ -0,0 +1,16 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@return
(byte*) main::SCREEN
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(byte) main::b
(byte) main::b#0 b zp ZP_BYTE:2 2.0
(byte*) main::pb
(byte*) main::pb#0 pb zp ZP_WORD:3 20.0
(byte**) main::ppb
(const byte**) main::ppb#0 ppb = &(byte*) main::pb#0
zp ZP_BYTE:2 [ main::b#0 ]
zp ZP_WORD:3 [ main::pb#0 ]

View File

@ -0,0 +1,65 @@
// Tests pointer to pointer in a more complex setup
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label textid = 4
main: {
.label screen = 5
.label text = 2
ldx #0
lda #<$400
sta screen
lda #>$400
sta screen+1
txa
sta textid
sta text
sta text+1
b1:
jsr nexttext
b2:
ldy #0
lda (text),y
cmp #'@'
bne b3
inx
cpx #$15
bne b1
rts
b3:
ldy #0
lda (text),y
sta (screen),y
inc screen
bne !+
inc screen+1
!:
inc text
bne !+
inc text+1
!:
jmp b2
}
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
nexttext: {
.label textp = main.text
lda #1
and textid
inc textid
cmp #0
beq b1
lda #<text2
sta textp
lda #>text2
sta textp+1
breturn:
rts
b1:
lda #<text1
sta textp
lda #>text1
sta textp+1
jmp breturn
}
text1: .text "camelot @"
text2: .text "rex @"

View File

@ -0,0 +1,50 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@4
[5] (byte) main::i#5 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) main::i#1 )
[5] (byte*) main::screen#4 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@4/(byte*) main::screen#2 )
[5] (byte) textid#11 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) textid#13 )
[5] (byte*) main::text#2 ← phi( main/(byte*) 0 main::@4/(byte*) main::text#3 )
[6] call nexttext
to:main::@2
main::@2: scope:[main] from main::@1 main::@3
[7] (byte*) main::screen#2 ← phi( main::@3/(byte*) main::screen#1 main::@1/(byte*) main::screen#4 )
[7] (byte*) main::text#3 ← phi( main::@3/(byte*) main::text#1 main::@1/(byte*) main::text#2 )
[8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[9] (byte) main::i#1 ← ++ (byte) main::i#5
[10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@4
[11] return
to:@return
main::@3: scope:[main] from main::@2
[12] *((byte*) main::screen#2) ← *((byte*) main::text#3)
[13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
[14] (byte*) main::text#1 ← ++ (byte*) main::text#3
to:main::@2
nexttext: scope:[nexttext] from main::@1
[15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1
[16] (byte) textid#13 ← ++ (byte) textid#11
[17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1
to:nexttext::@2
nexttext::@2: scope:[nexttext] from nexttext
[18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0
to:nexttext::@return
nexttext::@return: scope:[nexttext] from nexttext::@1 nexttext::@2
[19] return
to:@return
nexttext::@1: scope:[nexttext] from nexttext
[20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0
to:nexttext::@return

View File

@ -0,0 +1,866 @@
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @2
(byte) textid#16 ← phi( @2/(byte) textid#15 )
(byte*) main::screen#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte*) main::text#0 ← (byte*) 0
(byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:main::@1
main::@1: scope:[main] from main main::@4
(byte) main::i#6 ← phi( main/(byte) main::i#0 main::@4/(byte) main::i#1 )
(byte*) main::screen#5 ← phi( main/(byte*) main::screen#0 main::@4/(byte*) main::screen#6 )
(byte) textid#11 ← phi( main/(byte) textid#16 main::@4/(byte) textid#12 )
(byte*) main::text#2 ← phi( main/(byte*) main::text#0 main::@4/(byte*) main::text#5 )
(byte**~) main::$0 ← & (byte*) main::text#2
(byte**) nexttext::textp#0 ← (byte**~) main::$0
call nexttext
to:main::@9
main::@9: scope:[main] from main::@1
(byte) main::i#5 ← phi( main::@1/(byte) main::i#6 )
(byte*) main::screen#4 ← phi( main::@1/(byte*) main::screen#5 )
(byte*) main::text#6 ← phi( main::@1/(byte*) main::text#2 )
(byte) textid#6 ← phi( main::@1/(byte) textid#4 )
(byte) textid#0 ← (byte) textid#6
to:main::@2
main::@2: scope:[main] from main::@3 main::@9
(byte) textid#17 ← phi( main::@3/(byte) textid#18 main::@9/(byte) textid#0 )
(byte) main::i#3 ← phi( main::@3/(byte) main::i#4 main::@9/(byte) main::i#5 )
(byte*) main::screen#3 ← phi( main::@3/(byte*) main::screen#1 main::@9/(byte*) main::screen#4 )
(byte*) main::text#3 ← phi( main::@3/(byte*) main::text#1 main::@9/(byte*) main::text#6 )
(bool~) main::$2 ← *((byte*) main::text#3) != (byte) '@'
if((bool~) main::$2) goto main::@3
to:main::@4
main::@3: scope:[main] from main::@2
(byte) textid#18 ← phi( main::@2/(byte) textid#17 )
(byte) main::i#4 ← phi( main::@2/(byte) main::i#3 )
(byte*) main::screen#2 ← phi( main::@2/(byte*) main::screen#3 )
(byte*) main::text#4 ← phi( main::@2/(byte*) main::text#3 )
*((byte*) main::screen#2) ← *((byte*) main::text#4)
(byte*) main::screen#1 ← ++ (byte*) main::screen#2
(byte*) main::text#1 ← ++ (byte*) main::text#4
to:main::@2
main::@4: scope:[main] from main::@2
(byte*) main::screen#6 ← phi( main::@2/(byte*) main::screen#3 )
(byte) textid#12 ← phi( main::@2/(byte) textid#17 )
(byte*) main::text#5 ← phi( main::@2/(byte*) main::text#3 )
(byte) main::i#2 ← phi( main::@2/(byte) main::i#3 )
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,$14)
(bool~) main::$3 ← (byte) main::i#1 != rangelast(0,$14)
if((bool~) main::$3) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@4
(byte) textid#7 ← phi( main::@4/(byte) textid#12 )
(byte) textid#1 ← (byte) textid#7
return
to:@return
@1: scope:[] from @begin
(byte[]) text1#0 ← (const string) $0
(byte[]) text2#0 ← (const string) $1
(byte) textid#2 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@2
nexttext: scope:[nexttext] from main::@1
(byte**) nexttext::textp#3 ← phi( main::@1/(byte**) nexttext::textp#0 )
(byte) textid#8 ← phi( main::@1/(byte) textid#11 )
(byte~) nexttext::$0 ← (byte) textid#8 & (byte/signed byte/word/signed word/dword/signed dword) 1
(bool~) nexttext::$1 ← (byte~) nexttext::$0 == (byte/signed byte/word/signed word/dword/signed dword) 0
(byte) textid#3 ← ++ (byte) textid#8
if((bool~) nexttext::$1) goto nexttext::@1
to:nexttext::@3
nexttext::@1: scope:[nexttext] from nexttext
(byte) textid#13 ← phi( nexttext/(byte) textid#3 )
(byte**) nexttext::textp#1 ← phi( nexttext/(byte**) nexttext::textp#3 )
*((byte**) nexttext::textp#1) ← (byte[]) text1#0
to:nexttext::@return
nexttext::@3: scope:[nexttext] from nexttext
(byte) textid#14 ← phi( nexttext/(byte) textid#3 )
(byte**) nexttext::textp#2 ← phi( nexttext/(byte**) nexttext::textp#3 )
*((byte**) nexttext::textp#2) ← (byte[]) text2#0
to:nexttext::@return
nexttext::@return: scope:[nexttext] from nexttext::@1 nexttext::@3
(byte) textid#9 ← phi( nexttext::@1/(byte) textid#13 nexttext::@3/(byte) textid#14 )
(byte) textid#4 ← (byte) textid#9
return
to:@return
@2: scope:[] from @1
(byte) textid#15 ← phi( @1/(byte) textid#2 )
call main
to:@3
@3: scope:[] from @2
(byte) textid#10 ← phi( @2/(byte) textid#1 )
(byte) textid#5 ← (byte) textid#10
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(const string) $0 = (string) "camelot @"
(const string) $1 = (string) "rex @"
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(void()) main()
(byte**~) main::$0
(bool~) main::$2
(bool~) main::$3
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@9
(label) main::@return
(byte) main::i
(byte) main::i#0
(byte) main::i#1
(byte) main::i#2
(byte) main::i#3
(byte) main::i#4
(byte) main::i#5
(byte) main::i#6
(byte*) main::screen
(byte*) main::screen#0
(byte*) main::screen#1
(byte*) main::screen#2
(byte*) main::screen#3
(byte*) main::screen#4
(byte*) main::screen#5
(byte*) main::screen#6
(byte*) main::text
(byte*) main::text#0
(byte*) main::text#1
(byte*) main::text#2
(byte*) main::text#3
(byte*) main::text#4
(byte*) main::text#5
(byte*) main::text#6
(void()) nexttext((byte**) nexttext::textp)
(byte~) nexttext::$0
(bool~) nexttext::$1
(label) nexttext::@1
(label) nexttext::@3
(label) nexttext::@return
(byte**) nexttext::textp
(byte**) nexttext::textp#0
(byte**) nexttext::textp#1
(byte**) nexttext::textp#2
(byte**) nexttext::textp#3
(byte[]) text1
(byte[]) text1#0
(byte[]) text2
(byte[]) text2#0
(byte) textid
(byte) textid#0
(byte) textid#1
(byte) textid#10
(byte) textid#11
(byte) textid#12
(byte) textid#13
(byte) textid#14
(byte) textid#15
(byte) textid#16
(byte) textid#17
(byte) textid#18
(byte) textid#2
(byte) textid#3
(byte) textid#4
(byte) textid#5
(byte) textid#6
(byte) textid#7
(byte) textid#8
(byte) textid#9
Alias (byte**) nexttext::textp#0 = (byte**~) main::$0
Alias (byte*) main::text#2 = (byte*) main::text#6
Alias (byte*) main::screen#4 = (byte*) main::screen#5
Alias (byte) main::i#5 = (byte) main::i#6
Alias (byte) textid#0 = (byte) textid#6
Alias (byte*) main::text#3 = (byte*) main::text#4 (byte*) main::text#5
Alias (byte*) main::screen#2 = (byte*) main::screen#3 (byte*) main::screen#6
Alias (byte) main::i#2 = (byte) main::i#4 (byte) main::i#3
Alias (byte) textid#1 = (byte) textid#18 (byte) textid#17 (byte) textid#12 (byte) textid#7
Alias (byte**) nexttext::textp#1 = (byte**) nexttext::textp#3 (byte**) nexttext::textp#2
Alias (byte) textid#13 = (byte) textid#3 (byte) textid#14
Alias (byte) textid#4 = (byte) textid#9
Alias (byte) textid#15 = (byte) textid#2
Alias (byte) textid#10 = (byte) textid#5
Successful SSA optimization Pass2AliasElimination
Alias (byte) textid#13 = (byte) textid#4
Successful SSA optimization Pass2AliasElimination
Self Phi Eliminated (byte) main::i#2
Self Phi Eliminated (byte) textid#1
Successful SSA optimization Pass2SelfPhiElimination
Redundant Phi (byte) textid#16 (byte) textid#15
Redundant Phi (byte) textid#0 (byte) textid#13
Redundant Phi (byte) main::i#2 (byte) main::i#5
Redundant Phi (byte) textid#1 (byte) textid#0
Redundant Phi (byte) textid#8 (byte) textid#11
Redundant Phi (byte**) nexttext::textp#1 (byte**) nexttext::textp#0
Redundant Phi (byte) textid#10 (byte) textid#1
Successful SSA optimization Pass2RedundantPhiElimination
Simple Condition (bool~) main::$2 [12] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3
Simple Condition (bool~) main::$3 [20] if((byte) main::i#1!=rangelast(0,$14)) goto main::@1
Simple Condition (bool~) nexttext::$1 [31] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const byte*) main::screen#0 = ((byte*))$400
Constant (const byte*) main::text#0 = 0
Constant (const byte) main::i#0 = 0
Constant (const byte**) nexttext::textp#0 = &main::text#2
Constant (const byte[]) text1#0 = $0
Constant (const byte[]) text2#0 = $1
Constant (const byte) textid#15 = 0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value main::i#1 ← ++ main::i#5 to ++
Resolved ranged comparison value if(main::i#1!=rangelast(0,$14)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) $15
Culled Empty Block (label) main::@9
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Successful SSA optimization Pass2CullEmptyBlocks
Inlining constant with var siblings (const byte*) main::screen#0
Inlining constant with var siblings (const byte*) main::text#0
Inlining constant with var siblings (const byte) main::i#0
Inlining constant with var siblings (const byte) textid#15
Constant inlined main::screen#0 = ((byte*))(word/signed word/dword/signed dword) $400
Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined main::text#0 = (byte*) 0
Constant inlined textid#15 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined $0 = (const byte[]) text1#0
Constant inlined $1 = (const byte[]) text2#0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting main::@10(between main::@4 and main::@1)
Adding NOP phi() at start of @begin
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
Calls in [main] to nexttext:6
Created 6 initial phi equivalence classes
Coalesced [7] main::text#9 ← main::text#2
Coalesced [8] main::screen#9 ← main::screen#4
Coalesced (already) [14] main::text#7 ← main::text#3
Coalesced [15] textid#19 ← textid#13
Coalesced (already) [16] main::screen#7 ← main::screen#2
Coalesced [17] main::i#7 ← main::i#1
Coalesced [21] main::text#8 ← main::text#1
Coalesced [22] main::screen#8 ← main::screen#1
Coalesced down to 4 phi equivalence classes
Culled Empty Block (label) main::@10
Renumbering block @2 to @1
Renumbering block nexttext::@3 to nexttext::@2
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] phi()
[2] call main
to:@end
@end: scope:[] from @1
[3] phi()
main: scope:[main] from @1
[4] phi()
to:main::@1
main::@1: scope:[main] from main main::@4
[5] (byte) main::i#5 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) main::i#1 )
[5] (byte*) main::screen#4 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@4/(byte*) main::screen#2 )
[5] (byte) textid#11 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) textid#13 )
[5] (byte*) main::text#2 ← phi( main/(byte*) 0 main::@4/(byte*) main::text#3 )
[6] call nexttext
to:main::@2
main::@2: scope:[main] from main::@1 main::@3
[7] (byte*) main::screen#2 ← phi( main::@3/(byte*) main::screen#1 main::@1/(byte*) main::screen#4 )
[7] (byte*) main::text#3 ← phi( main::@3/(byte*) main::text#1 main::@1/(byte*) main::text#2 )
[8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3
to:main::@4
main::@4: scope:[main] from main::@2
[9] (byte) main::i#1 ← ++ (byte) main::i#5
[10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@4
[11] return
to:@return
main::@3: scope:[main] from main::@2
[12] *((byte*) main::screen#2) ← *((byte*) main::text#3)
[13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
[14] (byte*) main::text#1 ← ++ (byte*) main::text#3
to:main::@2
nexttext: scope:[nexttext] from main::@1
[15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1
[16] (byte) textid#13 ← ++ (byte) textid#11
[17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1
to:nexttext::@2
nexttext::@2: scope:[nexttext] from nexttext
[18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0
to:nexttext::@return
nexttext::@return: scope:[nexttext] from nexttext::@1 nexttext::@2
[19] return
to:@return
nexttext::@1: scope:[nexttext] from nexttext
[20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0
to:nexttext::@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte) main::i
(byte) main::i#1 16.5
(byte) main::i#5 3.142857142857143
(byte*) main::screen
(byte*) main::screen#1 101.0
(byte*) main::screen#2 65.0
(byte*) main::screen#4 11.0
(byte*) main::text
(byte*) main::text#1 202.0
(byte*) main::text#2 11.0
(byte*) main::text#3 70.99999999999999
(void()) nexttext((byte**) nexttext::textp)
(byte~) nexttext::$0 2.0
(byte**) nexttext::textp
(byte[]) text1
(byte[]) text2
(byte) textid
(byte) textid#11 7.5
(byte) textid#13 1.0
Initial phi equivalence classes
[ main::text#2 main::text#3 main::text#1 ]
[ textid#11 textid#13 ]
[ main::screen#4 main::screen#2 main::screen#1 ]
[ main::i#5 main::i#1 ]
Added variable nexttext::$0 to zero page equivalence class [ nexttext::$0 ]
Complete equivalence classes
[ main::text#2 main::text#3 main::text#1 ]
[ textid#11 textid#13 ]
[ main::screen#4 main::screen#2 main::screen#1 ]
[ main::i#5 main::i#1 ]
[ nexttext::$0 ]
Allocated zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ]
Allocated zp ZP_BYTE:4 [ textid#11 textid#13 ]
Allocated zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ]
Allocated zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
Allocated zp ZP_BYTE:8 [ nexttext::$0 ]
INITIAL ASM
//SEG0 File Comments
// Tests pointer to pointer in a more complex setup
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label textid = 4
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
.label screen = 5
.label text = 2
.label i = 7
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG13 [5] phi (byte*) main::screen#4 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG14 [5] phi (byte) textid#11 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuz1=vbuc1
lda #0
sta textid
//SEG15 [5] phi (byte*) main::text#2 = (byte*) 0 [phi:main->main::@1#3] -- pbuz1=pbuc1
lda #<0
sta text
lda #>0
sta text+1
jmp b1
//SEG16 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
b1_from_b4:
//SEG17 [5] phi (byte) main::i#5 = (byte) main::i#1 [phi:main::@4->main::@1#0] -- register_copy
//SEG18 [5] phi (byte*) main::screen#4 = (byte*) main::screen#2 [phi:main::@4->main::@1#1] -- register_copy
//SEG19 [5] phi (byte) textid#11 = (byte) textid#13 [phi:main::@4->main::@1#2] -- register_copy
//SEG20 [5] phi (byte*) main::text#2 = (byte*) main::text#3 [phi:main::@4->main::@1#3] -- register_copy
jmp b1
//SEG21 main::@1
b1:
//SEG22 [6] call nexttext
jsr nexttext
//SEG23 [7] phi from main::@1 main::@3 to main::@2 [phi:main::@1/main::@3->main::@2]
b2_from_b1:
b2_from_b3:
//SEG24 [7] phi (byte*) main::screen#2 = (byte*) main::screen#4 [phi:main::@1/main::@3->main::@2#0] -- register_copy
//SEG25 [7] phi (byte*) main::text#3 = (byte*) main::text#2 [phi:main::@1/main::@3->main::@2#1] -- register_copy
jmp b2
//SEG26 main::@2
b2:
//SEG27 [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 -- _deref_pbuz1_neq_vbuc1_then_la1
ldy #0
lda (text),y
cmp #'@'
bne b3
jmp b4
//SEG28 main::@4
b4:
//SEG29 [9] (byte) main::i#1 ← ++ (byte) main::i#5 -- vbuz1=_inc_vbuz1
inc i
//SEG30 [10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$15
cmp i
bne b1_from_b4
jmp breturn
//SEG31 main::@return
breturn:
//SEG32 [11] return
rts
//SEG33 main::@3
b3:
//SEG34 [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) -- _deref_pbuz1=_deref_pbuz2
ldy #0
lda (text),y
ldy #0
sta (screen),y
//SEG35 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG36 [14] (byte*) main::text#1 ← ++ (byte*) main::text#3 -- pbuz1=_inc_pbuz1
inc text
bne !+
inc text+1
!:
jmp b2_from_b3
}
//SEG37 nexttext
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
nexttext: {
.label textp = main.text
.label _0 = 8
//SEG38 [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuz1=vbuz2_band_vbuc1
lda #1
and textid
sta _0
//SEG39 [16] (byte) textid#13 ← ++ (byte) textid#11 -- vbuz1=_inc_vbuz1
inc textid
//SEG40 [17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1 -- vbuz1_eq_0_then_la1
lda _0
cmp #0
beq b1
jmp b2
//SEG41 nexttext::@2
b2:
//SEG42 [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 -- _deref_pptc1=pbuc2
lda #<text2
sta textp
lda #>text2
sta textp+1
jmp breturn
//SEG43 nexttext::@return
breturn:
//SEG44 [19] return
rts
//SEG45 nexttext::@1
b1:
//SEG46 [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 -- _deref_pptc1=pbuc2
lda #<text1
sta textp
lda #>text1
sta textp+1
jmp breturn
}
text1: .text "camelot @"
text2: .text "rex @"
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ textid#11 textid#13 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ textid#11 textid#13 ]
Statement [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
Statement [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ textid#11 nexttext::$0 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#11 nexttext::$0 ] ) always clobbers reg byte a
Statement [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
Statement [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
Statement [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
Statement [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
Statement [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ textid#11 nexttext::$0 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#11 nexttext::$0 ] ) always clobbers reg byte a
Statement [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
Statement [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
Potential registers zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_BYTE:4 [ textid#11 textid#13 ] : zp ZP_BYTE:4 , reg byte x ,
Potential registers zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ] : zp ZP_WORD:5 ,
Potential registers zp ZP_BYTE:7 [ main::i#5 main::i#1 ] : zp ZP_BYTE:7 , reg byte x ,
Potential registers zp ZP_BYTE:8 [ nexttext::$0 ] : zp ZP_BYTE:8 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 284: zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ] 177: zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ] 19.64: zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
Uplift Scope [] 8.5: zp ZP_BYTE:4 [ textid#11 textid#13 ]
Uplift Scope [nexttext] 2: zp ZP_BYTE:8 [ nexttext::$0 ]
Uplifting [main] best 6712 combination zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ] zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ] reg byte x [ main::i#5 main::i#1 ]
Uplifting [] best 6712 combination zp ZP_BYTE:4 [ textid#11 textid#13 ]
Uplifting [nexttext] best 6706 combination reg byte a [ nexttext::$0 ]
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ textid#11 textid#13 ]
Uplifting [] best 6706 combination zp ZP_BYTE:4 [ textid#11 textid#13 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests pointer to pointer in a more complex setup
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label textid = 4
//SEG3 @begin
bbegin:
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
b1_from_bbegin:
jmp b1
//SEG5 @1
b1:
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
main_from_b1:
jsr main
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG9 @end
bend:
//SEG10 main
main: {
.label screen = 5
.label text = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG13 [5] phi (byte*) main::screen#4 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG14 [5] phi (byte) textid#11 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuz1=vbuc1
lda #0
sta textid
//SEG15 [5] phi (byte*) main::text#2 = (byte*) 0 [phi:main->main::@1#3] -- pbuz1=pbuc1
lda #<0
sta text
lda #>0
sta text+1
jmp b1
//SEG16 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
b1_from_b4:
//SEG17 [5] phi (byte) main::i#5 = (byte) main::i#1 [phi:main::@4->main::@1#0] -- register_copy
//SEG18 [5] phi (byte*) main::screen#4 = (byte*) main::screen#2 [phi:main::@4->main::@1#1] -- register_copy
//SEG19 [5] phi (byte) textid#11 = (byte) textid#13 [phi:main::@4->main::@1#2] -- register_copy
//SEG20 [5] phi (byte*) main::text#2 = (byte*) main::text#3 [phi:main::@4->main::@1#3] -- register_copy
jmp b1
//SEG21 main::@1
b1:
//SEG22 [6] call nexttext
jsr nexttext
//SEG23 [7] phi from main::@1 main::@3 to main::@2 [phi:main::@1/main::@3->main::@2]
b2_from_b1:
b2_from_b3:
//SEG24 [7] phi (byte*) main::screen#2 = (byte*) main::screen#4 [phi:main::@1/main::@3->main::@2#0] -- register_copy
//SEG25 [7] phi (byte*) main::text#3 = (byte*) main::text#2 [phi:main::@1/main::@3->main::@2#1] -- register_copy
jmp b2
//SEG26 main::@2
b2:
//SEG27 [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 -- _deref_pbuz1_neq_vbuc1_then_la1
ldy #0
lda (text),y
cmp #'@'
bne b3
jmp b4
//SEG28 main::@4
b4:
//SEG29 [9] (byte) main::i#1 ← ++ (byte) main::i#5 -- vbuxx=_inc_vbuxx
inx
//SEG30 [10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #$15
bne b1_from_b4
jmp breturn
//SEG31 main::@return
breturn:
//SEG32 [11] return
rts
//SEG33 main::@3
b3:
//SEG34 [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) -- _deref_pbuz1=_deref_pbuz2
ldy #0
lda (text),y
ldy #0
sta (screen),y
//SEG35 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG36 [14] (byte*) main::text#1 ← ++ (byte*) main::text#3 -- pbuz1=_inc_pbuz1
inc text
bne !+
inc text+1
!:
jmp b2_from_b3
}
//SEG37 nexttext
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
nexttext: {
.label textp = main.text
//SEG38 [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
lda #1
and textid
//SEG39 [16] (byte) textid#13 ← ++ (byte) textid#11 -- vbuz1=_inc_vbuz1
inc textid
//SEG40 [17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1 -- vbuaa_eq_0_then_la1
cmp #0
beq b1
jmp b2
//SEG41 nexttext::@2
b2:
//SEG42 [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 -- _deref_pptc1=pbuc2
lda #<text2
sta textp
lda #>text2
sta textp+1
jmp breturn
//SEG43 nexttext::@return
breturn:
//SEG44 [19] return
rts
//SEG45 nexttext::@1
b1:
//SEG46 [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 -- _deref_pptc1=pbuc2
lda #<text1
sta textp
lda #>text1
sta textp+1
jmp breturn
}
text1: .text "camelot @"
text2: .text "rex @"
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp b4
Removing instruction jmp breturn
Removing instruction jmp b2
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing instruction lda #0 with TXA
Removing instruction lda #<0
Removing instruction lda #>0
Removing instruction ldy #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label b1_from_b4 with b1
Replacing label b2_from_b3 with b2
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_b4:
Removing instruction b2_from_b1:
Removing instruction b2_from_b3:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction b1_from_main:
Removing instruction b4:
Removing instruction breturn:
Removing instruction b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Updating BasicUpstart to call main directly
Removing instruction jsr main
Succesful ASM optimization Pass5SkipBegin
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#5 reg byte x 3.142857142857143
(byte*) main::screen
(byte*) main::screen#1 screen zp ZP_WORD:5 101.0
(byte*) main::screen#2 screen zp ZP_WORD:5 65.0
(byte*) main::screen#4 screen zp ZP_WORD:5 11.0
(byte*) main::text
(byte*) main::text#1 text zp ZP_WORD:2 202.0
(byte*) main::text#2 text zp ZP_WORD:2 11.0
(byte*) main::text#3 text zp ZP_WORD:2 70.99999999999999
(void()) nexttext((byte**) nexttext::textp)
(byte~) nexttext::$0 reg byte a 2.0
(label) nexttext::@1
(label) nexttext::@2
(label) nexttext::@return
(byte**) nexttext::textp
(const byte**) nexttext::textp#0 textp = &(byte*) main::text#2
(byte[]) text1
(const byte[]) text1#0 text1 = (string) "camelot @"
(byte[]) text2
(const byte[]) text2#0 text2 = (string) "rex @"
(byte) textid
(byte) textid#11 textid zp ZP_BYTE:4 7.5
(byte) textid#13 textid zp ZP_BYTE:4 1.0
zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ]
zp ZP_BYTE:4 [ textid#11 textid#13 ]
zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ]
reg byte x [ main::i#5 main::i#1 ]
reg byte a [ nexttext::$0 ]
FINAL ASSEMBLER
Score: 5758
//SEG0 File Comments
// Tests pointer to pointer in a more complex setup
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label textid = 4
//SEG3 @begin
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
//SEG5 @1
//SEG6 [2] call main
//SEG7 [4] phi from @1 to main [phi:@1->main]
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main
main: {
.label screen = 5
.label text = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte) main::i#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG13 [5] phi (byte*) main::screen#4 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
lda #<$400
sta screen
lda #>$400
sta screen+1
//SEG14 [5] phi (byte) textid#11 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuz1=vbuc1
txa
sta textid
//SEG15 [5] phi (byte*) main::text#2 = (byte*) 0 [phi:main->main::@1#3] -- pbuz1=pbuc1
sta text
sta text+1
//SEG16 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
//SEG17 [5] phi (byte) main::i#5 = (byte) main::i#1 [phi:main::@4->main::@1#0] -- register_copy
//SEG18 [5] phi (byte*) main::screen#4 = (byte*) main::screen#2 [phi:main::@4->main::@1#1] -- register_copy
//SEG19 [5] phi (byte) textid#11 = (byte) textid#13 [phi:main::@4->main::@1#2] -- register_copy
//SEG20 [5] phi (byte*) main::text#2 = (byte*) main::text#3 [phi:main::@4->main::@1#3] -- register_copy
//SEG21 main::@1
b1:
//SEG22 [6] call nexttext
jsr nexttext
//SEG23 [7] phi from main::@1 main::@3 to main::@2 [phi:main::@1/main::@3->main::@2]
//SEG24 [7] phi (byte*) main::screen#2 = (byte*) main::screen#4 [phi:main::@1/main::@3->main::@2#0] -- register_copy
//SEG25 [7] phi (byte*) main::text#3 = (byte*) main::text#2 [phi:main::@1/main::@3->main::@2#1] -- register_copy
//SEG26 main::@2
b2:
//SEG27 [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 -- _deref_pbuz1_neq_vbuc1_then_la1
ldy #0
lda (text),y
cmp #'@'
bne b3
//SEG28 main::@4
//SEG29 [9] (byte) main::i#1 ← ++ (byte) main::i#5 -- vbuxx=_inc_vbuxx
inx
//SEG30 [10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
cpx #$15
bne b1
//SEG31 main::@return
//SEG32 [11] return
rts
//SEG33 main::@3
b3:
//SEG34 [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) -- _deref_pbuz1=_deref_pbuz2
ldy #0
lda (text),y
sta (screen),y
//SEG35 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
inc screen
bne !+
inc screen+1
!:
//SEG36 [14] (byte*) main::text#1 ← ++ (byte*) main::text#3 -- pbuz1=_inc_pbuz1
inc text
bne !+
inc text+1
!:
jmp b2
}
//SEG37 nexttext
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
nexttext: {
.label textp = main.text
//SEG38 [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
lda #1
and textid
//SEG39 [16] (byte) textid#13 ← ++ (byte) textid#11 -- vbuz1=_inc_vbuz1
inc textid
//SEG40 [17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1 -- vbuaa_eq_0_then_la1
cmp #0
beq b1
//SEG41 nexttext::@2
//SEG42 [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 -- _deref_pptc1=pbuc2
lda #<text2
sta textp
lda #>text2
sta textp+1
//SEG43 nexttext::@return
breturn:
//SEG44 [19] return
rts
//SEG45 nexttext::@1
b1:
//SEG46 [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 -- _deref_pptc1=pbuc2
lda #<text1
sta textp
lda #>text1
sta textp+1
jmp breturn
}
text1: .text "camelot @"
text2: .text "rex @"

View File

@ -0,0 +1,40 @@
(label) @1
(label) @begin
(label) @end
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@return
(byte) main::i
(byte) main::i#1 reg byte x 16.5
(byte) main::i#5 reg byte x 3.142857142857143
(byte*) main::screen
(byte*) main::screen#1 screen zp ZP_WORD:5 101.0
(byte*) main::screen#2 screen zp ZP_WORD:5 65.0
(byte*) main::screen#4 screen zp ZP_WORD:5 11.0
(byte*) main::text
(byte*) main::text#1 text zp ZP_WORD:2 202.0
(byte*) main::text#2 text zp ZP_WORD:2 11.0
(byte*) main::text#3 text zp ZP_WORD:2 70.99999999999999
(void()) nexttext((byte**) nexttext::textp)
(byte~) nexttext::$0 reg byte a 2.0
(label) nexttext::@1
(label) nexttext::@2
(label) nexttext::@return
(byte**) nexttext::textp
(const byte**) nexttext::textp#0 textp = &(byte*) main::text#2
(byte[]) text1
(const byte[]) text1#0 text1 = (string) "camelot @"
(byte[]) text2
(const byte[]) text2#0 text2 = (string) "rex @"
(byte) textid
(byte) textid#11 textid zp ZP_BYTE:4 7.5
(byte) textid#13 textid zp ZP_BYTE:4 1.0
zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ]
zp ZP_BYTE:4 [ textid#11 textid#13 ]
zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ]
reg byte x [ main::i#5 main::i#1 ]
reg byte a [ nexttext::$0 ]

View File

@ -345,16 +345,18 @@ setByte: {
} }
REGISTER UPLIFT POTENTIAL REGISTERS REGISTER UPLIFT POTENTIAL REGISTERS
Statement [17] *((byte*) setByte::ptr#3) ← (byte) setByte::b#3 [ main::b1#0 main::b2#0 main::b3#0 ] ( main:2::setByte:7 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:9 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:11 [ main::b1#0 main::b2#0 main::b3#0 ] ) always clobbers reg byte y Statement [4] (byte) main::b1#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::b1#0 ] ( main:2 [ main::b1#0 ] ) always clobbers reg byte a
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:5 [ main::b1#0 ] Statement [5] (byte) main::b2#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::b1#0 main::b2#0 ] ( main:2 [ main::b1#0 main::b2#0 ] ) always clobbers reg byte a
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:6 [ main::b2#0 ] Statement [6] (byte) main::b3#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::b1#0 main::b2#0 main::b3#0 ] ( main:2 [ main::b1#0 main::b2#0 main::b3#0 ] ) always clobbers reg byte a
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:7 [ main::b3#0 ] Statement [12] *((const byte*) main::SCREEN#0) ← (byte) main::b1#0 [ main::b2#0 main::b3#0 ] ( main:2 [ main::b2#0 main::b3#0 ] ) always clobbers reg byte a
Statement [13] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte) main::b2#0 [ main::b3#0 ] ( main:2 [ main::b3#0 ] ) always clobbers reg byte a
Statement [14] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte) main::b3#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [17] *((byte*) setByte::ptr#3) ← (byte) setByte::b#3 [ main::b1#0 main::b2#0 main::b3#0 ] ( main:2::setByte:7 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:9 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:11 [ main::b1#0 main::b2#0 main::b3#0 ] ) always clobbers reg byte y Statement [17] *((byte*) setByte::ptr#3) ← (byte) setByte::b#3 [ main::b1#0 main::b2#0 main::b3#0 ] ( main:2::setByte:7 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:9 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:11 [ main::b1#0 main::b2#0 main::b3#0 ] ) always clobbers reg byte y
Potential registers zp ZP_BYTE:2 [ setByte::b#3 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:2 [ setByte::b#3 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:3 [ setByte::ptr#3 ] : zp ZP_WORD:3 , Potential registers zp ZP_WORD:3 [ setByte::ptr#3 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_BYTE:5 [ main::b1#0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , Potential registers zp ZP_BYTE:5 [ main::b1#0 ] : zp ZP_BYTE:5 ,
Potential registers zp ZP_BYTE:6 [ main::b2#0 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , Potential registers zp ZP_BYTE:6 [ main::b2#0 ] : zp ZP_BYTE:6 ,
Potential registers zp ZP_BYTE:7 [ main::b3#0 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , Potential registers zp ZP_BYTE:7 [ main::b3#0 ] : zp ZP_BYTE:7 ,
REGISTER UPLIFT SCOPES REGISTER UPLIFT SCOPES
Uplift Scope [setByte] 2: zp ZP_BYTE:2 [ setByte::b#3 ] 2: zp ZP_WORD:3 [ setByte::ptr#3 ] Uplift Scope [setByte] 2: zp ZP_BYTE:2 [ setByte::b#3 ] 2: zp ZP_WORD:3 [ setByte::ptr#3 ]