1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-22 03:38:31 +00:00

Added missing RTS after jsr main

This commit is contained in:
jespergravgaard 2019-04-06 11:53:56 +02:00
parent 9ccc5d828f
commit ca9453346b
58 changed files with 2225 additions and 162 deletions
src
main/java/dk/camelot64/kickc
test
java/dk/camelot64/kickc/test
kc
ref

@ -249,6 +249,7 @@ public class Compiler {
optimizations.add(new Pass2NopCastElimination(program));
optimizations.add(new Pass2EliminateUnusedBlocks(program));
optimizations.add(new Pass2RangeResolving(program));
// optimizations.add(new Pass2ConstantCallPointerIdentification(program));
pass2Execute(optimizations);
}
@ -487,6 +488,8 @@ public class Compiler {
pass5Optimizations.add(new Pass5DoubleJumpElimination(program));
pass5Optimizations.add(new Pass5UnreachableCodeElimination(program));
pass5Optimizations.add(new Pass5RelabelLongLabels(program));
pass5Optimizations.add(new Pass5SkipBegin(program));
pass5Optimizations.add(new Pass5AddMainRts(program));
boolean asmOptimized = true;
while(asmOptimized) {
asmOptimized = false;

@ -17,9 +17,9 @@ public class StatementCall extends StatementBase implements StatementLValue {
/** The variable being assigned a value by the call. Can be null. */
private LValue lValue;
/** The name of the procedure called (if the call is simple). Null if the called procedure is calculated through an expression. */
/** The name of the procedure called */
private String procedureName;
/** The procedure called (if the call is simple). Null if the called procedure is calculated through an expression. */
/** The procedure called. */
private ProcedureRef procedure;
/** The parameter values passed to the procedure. */
private List<RValue> parameters;

@ -249,7 +249,8 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
List<ControlFlowBlock> predecessors = getGraph().getPredecessors(block);
Symbol symbol = getScope().getSymbol(block.getLabel());
if(symbol instanceof Procedure) {
if(((Procedure) symbol).getInterruptType()!=null) {
Procedure procedure = (Procedure) symbol;
if(procedure.getInterruptType()!=null || Pass2ConstantIdentification.isAddressOfUsed(procedure.getRef(), getProgram())) {
// Find all root-level predecessors to the main block
ControlFlowBlock mainBlock = getGraph().getBlock(new LabelRef(SymbolRef.MAIN_PROC_NAME));
List<ControlFlowBlock> mainPredecessors = getGraph().getPredecessors(mainBlock);

@ -0,0 +1,74 @@
package dk.camelot64.kickc.passes;
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.StatementCall;
import dk.camelot64.kickc.model.statements.StatementCallPointer;
import dk.camelot64.kickc.model.symbols.ConstantVar;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.types.SymbolTypeProcedure;
import dk.camelot64.kickc.model.values.*;
import java.util.ListIterator;
/** Pass that identified indirect calls to constant function pointers */
public class Pass2ConstantCallPointerIdentification extends Pass2SsaOptimization {
public Pass2ConstantCallPointerIdentification(Program program) {
super(program);
}
@Override
public boolean step() {
boolean optimized = false;
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
ListIterator<Statement> statementsIt = block.getStatements().listIterator();
while(statementsIt.hasNext()) {
Statement statement = statementsIt.next();
if(statement instanceof StatementCallPointer) {
StatementCallPointer callPointer = (StatementCallPointer) statement;
RValue procedure = callPointer.getProcedure();
if(procedure instanceof PointerDereferenceSimple) {
RValue pointer = ((PointerDereferenceSimple) procedure).getPointer();
ProcedureRef constProcedureRef = findConstProcedure(pointer);
if(constProcedureRef != null) {
statementsIt.remove();
StatementCall call = new StatementCall(callPointer.getlValue(), constProcedureRef.getFullName(), callPointer.getParameters(), callPointer.getSource(), callPointer.getComments());
call.setProcedure(constProcedureRef);
call.setIndex(callPointer.getIndex());
block.setCallSuccessor(constProcedureRef.getLabelRef());
statementsIt.add(call);
getLog().append("Replacing constant pointer function " + call.toString(getProgram(), false));
}
} else if(procedure instanceof ConstantRef) {
ConstantVar procedureVariable = getScope().getConstant((ConstantRef) procedure);
SymbolType procedureVariableType = procedureVariable.getType();
if(procedureVariableType instanceof SymbolTypePointer) {
if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) {
optimized = true;
throw new RuntimeException("not implemented!");
}
}
}
}
}
}
return optimized;
}
private ProcedureRef findConstProcedure(RValue procedurePointer) {
if(procedurePointer instanceof ConstantRef) {
ConstantVar constant = getScope().getConstant((ConstantRef) procedurePointer);
return findConstProcedure(constant.getValue());
} else if(procedurePointer instanceof ConstantSymbolPointer) {
ConstantSymbolPointer pointer = (ConstantSymbolPointer) procedurePointer;
if(pointer.getToSymbol() instanceof ProcedureRef) {
return (ProcedureRef) pointer.getToSymbol();
}
}
return null;
}
}

@ -61,7 +61,7 @@ public class Pass3LiveRangesEffectiveAnalysis extends Pass2Base {
if(callPaths == null) {
callPaths = new LiveRangeVariablesEffective.CallPaths(procedureRef);
if(procedure.getInterruptType()!=null) {
if(procedure.getInterruptType()!=null || Pass2ConstantIdentification.isAddressOfUsed(procedureRef, getProgram())) {
// Interrupt is called outside procedure scope - create initial call-path.
ArrayList<CallGraph.CallBlock.Call> rootPath = new ArrayList<>();
ArrayList<VariableRef> rootAlive = new ArrayList<>();

@ -639,6 +639,9 @@ public class Pass4CodeGeneration {
}
}
}
if(supported) {
asm.getCurrentSegment().setClobberOverwrite(AsmClobber.CLOBBER_ALL);
}
if(!supported) {
throw new RuntimeException("Call Pointer not supported " + statement);
}

@ -0,0 +1,59 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.values.ScopeRef;
import dk.camelot64.kickc.model.values.SymbolRef;
import java.util.ListIterator;
/**
* If the main method is called by JSR this adds an additional RTS
*/
public class Pass5AddMainRts extends Pass5AsmOptimization {
public Pass5AddMainRts(Program program) {
super(program);
}
public boolean optimize() {
for(AsmSegment segment : getAsmProgram().getSegments()) {
String scopeLabel = segment.getScopeLabel();
if(scopeLabel.equals(ScopeRef.ROOT.getFullName())) {
ListIterator<AsmLine> lineIterator = segment.getLines().listIterator();
while(lineIterator.hasNext()) {
AsmLine line = lineIterator.next();
if(line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
if(instruction.getType().getMnemnonic().equals("jsr")) {
if(instruction.getParameter().equals(SymbolRef.MAIN_PROC_NAME)) {
// Add RTS if it is missing
if(!lineIterator.hasNext()) {
addRts(lineIterator);
return true;
}
AsmLine nextLine = lineIterator.next();
if(!(nextLine instanceof AsmInstruction)) {
addRts(lineIterator);
return true;
}
AsmInstruction nextInstruction = (AsmInstruction) nextLine;
if(!nextInstruction.getType().getMnemnonic().equals("rts")) {
addRts(lineIterator);
return true;
}
}
}
}
}
}
}
return false;
}
private void addRts(ListIterator<AsmLine> lineIterator) {
lineIterator.add(new AsmInstruction(AsmInstructionSet.getInstructionType("rts", AsmAddressingMode.NON, false), null));
getLog().append("Adding RTS to root block ");
}
}

@ -42,6 +42,16 @@ public class TestPrograms {
compileAndCompare("pointer-pointer-1" );
}
@Test
public void testFunctionPointerNoargCall8() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-8");
}
@Test
public void testFunctionPointerNoargCall7() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-7");
}
@Test
public void testFunctionPointerNoargCall6() throws IOException, URISyntaxException {
compileAndCompare("function-pointer-noarg-call-6");

@ -0,0 +1,26 @@
// Tests calling into a function pointer with local variables
void main() {
void()* f = &hello;
do10(f);
}
void do10(void()* fn) {
for( byte i: 0..9)
(*fn)();
}
const byte* SCREEN = $0400;
const byte[] msg = "hello @";
volatile byte idx = 0;
void hello() {
byte i=0;
do {
SCREEN[idx++] = msg[i++];
} while(msg[i]!='@');
}

@ -0,0 +1,31 @@
// Tests calling into a function pointer with local variables
void main() {
void()* f = &hello;
msg = msg1;
do10(f);
msg = msg2;
do10(f);
}
void do10(void()* fn) {
for( byte i: 0..9)
(*fn)();
}
const byte* SCREEN = $0400;
const byte[] msg1 = "hello @";
const byte[] msg2 = "world @";
volatile byte* msg;
volatile byte idx = 0;
void hello() {
byte i=0;
do {
SCREEN[idx++] = msg[i++];
} while(msg[i]!='@');
}

@ -11,6 +11,7 @@ bbegin:
lda #0
sta irq_raster_next
jsr main
rts
main: {
lda #<irq
sta KERNEL_IRQ

@ -463,6 +463,8 @@ Removing instruction bend:
Removing instruction breturn:
Removing instruction b2:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
@ -500,7 +502,7 @@ reg byte a [ irq::$0 ]
FINAL ASSEMBLER
Score: 153
Score: 159
//SEG0 File Comments
//SEG1 Basic Upstart
@ -524,6 +526,7 @@ bbegin:
//SEG7 @2
//SEG8 [3] call main
jsr main
rts
//SEG9 [4] phi from @2 to @end [phi:@2->@end]
//SEG10 @end
//SEG11 main

@ -84,6 +84,7 @@ bbegin:
lda #0
sta irq_cnt
jsr main
rts
main: {
.const toSpritePtr2_return = SIN_SPRITE>>6
.const vicSelectGfxBank1_toDd001_return = 3^(>PLAYFIELD_SCREEN_1)>>6

@ -3781,6 +3781,8 @@ Removing instruction b6:
Removing instruction b7:
Removing instruction b11:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b1
Removing instruction jmp b4
Removing instruction jmp b1
@ -4104,7 +4106,7 @@ reg byte a [ sprites_irq::ptr#2 ]
FINAL ASSEMBLER
Score: 7304
Score: 7310
//SEG0 File Comments
//SEG1 Basic Upstart
@ -4214,6 +4216,7 @@ bbegin:
//SEG20 [11] call main
//SEG21 [13] phi from @4 to main [phi:@4->main]
jsr main
rts
//SEG22 [12] phi from @4 to @end [phi:@4->@end]
//SEG23 @end
//SEG24 main

@ -183,6 +183,7 @@ bbegin:
lda #0
sta irq_cnt
jsr main
rts
main: {
jsr sid_rnd_init
sei

@ -22376,6 +22376,8 @@ Relabelling long label b1_from_b20 to b4
Relabelling long label b9_from_b10 to b5
Relabelling long label b9_from_b19 to b6
Succesful ASM optimization Pass5RelabelLongLabels
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b1
Removing instruction jmp b3
Removing instruction jmp b4
@ -23740,7 +23742,7 @@ reg byte a [ sprites_irq::ptr#2 ]
FINAL ASSEMBLER
Score: 3350872
Score: 3350878
//SEG0 File Comments
// Tetris Game for the Commodore 64
@ -23950,6 +23952,7 @@ bbegin:
//SEG21 [12] call main
//SEG22 [14] phi from @4 to main [phi:@4->main]
jsr main
rts
//SEG23 [13] phi from @4 to @end [phi:@4->@end]
//SEG24 @end
//SEG25 main

@ -9,6 +9,7 @@ bbegin:
lda #'a'
sta A
jsr main
rts
main: {
.const B = 'b'
.label addrA = A

@ -324,6 +324,8 @@ Removing instruction bend:
Removing instruction breturn:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
@ -351,7 +353,7 @@ reg byte x [ sub::D#0 ]
FINAL ASSEMBLER
Score: 65
Score: 71
//SEG0 File Comments
// Tests that constants are identified early
@ -372,6 +374,7 @@ bbegin:
//SEG6 @1
//SEG7 [2] call main
jsr main
rts
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main

@ -3,12 +3,14 @@
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label f = 2
ldx #0
.label i = 2
.label f = 3
lda #0
sta i
b2:
inx
txa
and #1
inc i
lda #1
and i
cmp #0
beq b1
lda #<fn2

@ -326,7 +326,13 @@ fn1: {
}
REGISTER UPLIFT POTENTIAL REGISTERS
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
Statement [11] call *((void()*) main::f#3) [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x 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 x 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 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#1 main::$0 ] ( main:2 [ main::i#1 main::$0 ] ) always clobbers reg byte a
Statement [11] call *((void()*) main::f#3) [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x reg byte y
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_WORD:3 [ main::f#3 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_BYTE:5 [ main::$0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
@ -336,11 +342,12 @@ Uplift Scope [fn1]
Uplift Scope [fn2]
Uplift Scope []
Uplifting [main] best 657 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] zp ZP_WORD:3 [ main::f#3 ]
Uplifting [fn1] best 657 combination
Uplifting [fn2] best 657 combination
Uplifting [] best 657 combination
Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::f#3 ]
Uplifting [main] best 727 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] zp ZP_WORD:3 [ main::f#3 ]
Uplifting [fn1] best 727 combination
Uplifting [fn2] best 727 combination
Uplifting [] best 727 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 727 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
@ -368,22 +375,24 @@ bend_from_b1:
bend:
//SEG10 main
main: {
.label f = 2
.label i = 2
.label f = 3
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG13 main::@1
b1:
jmp b2
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
lda #1
and i
//SEG17 [8] if((byte~) main::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@3 -- vbuaa_eq_0_then_la1
cmp #0
beq b3_from_b2
@ -496,18 +505,18 @@ FINAL SYMBOL TABLE
(label) main::@4
(byte*) main::SCREEN
(void()*) main::f
(void()*) main::f#3 f zp ZP_WORD:2
(void()*) main::f#3 f zp ZP_WORD:3
(byte) main::i
(byte) main::i#1 reg byte x 5.5
(byte) main::i#2 reg byte x 22.0
(byte) main::i#1 i zp ZP_BYTE:2 5.5
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ main::f#3 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
zp ZP_WORD:3 [ main::f#3 ]
reg byte a [ main::$0 ]
FINAL ASSEMBLER
Score: 519
Score: 589
//SEG0 File Comments
// Tests creating, assigning and calling pointers to non-args no-return functions
@ -525,18 +534,20 @@ Score: 519
//SEG9 @end
//SEG10 main
main: {
.label f = 2
.label i = 2
.label f = 3
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG13 main::@1
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
lda #1
and i
//SEG17 [8] if((byte~) main::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto main::@3 -- vbuaa_eq_0_then_la1
cmp #0
beq b1

@ -17,11 +17,11 @@
(label) main::@4
(byte*) main::SCREEN
(void()*) main::f
(void()*) main::f#3 f zp ZP_WORD:2
(void()*) main::f#3 f zp ZP_WORD:3
(byte) main::i
(byte) main::i#1 reg byte x 5.5
(byte) main::i#2 reg byte x 22.0
(byte) main::i#1 i zp ZP_BYTE:2 5.5
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ main::f#3 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
zp ZP_WORD:3 [ main::f#3 ]
reg byte a [ main::$0 ]

@ -3,11 +3,13 @@
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label _1 = 2
ldx #0
.label _1 = 3
.label i = 2
lda #0
sta i
b2:
inx
txa
inc i
lda i
jsr getfn
jsr bi__1
jmp b2
@ -16,7 +18,7 @@ main: {
}
// getfn(byte register(A) b)
getfn: {
.label return = 2
.label return = 3
and #1
cmp #0
beq b1

@ -390,9 +390,13 @@ REGISTER UPLIFT POTENTIAL REGISTERS
Statement [9] (void()*) getfn::return#0 ← (void()*) getfn::return#3 [ main::i#1 getfn::return#0 ] ( main:2 [ main::i#1 getfn::return#0 ] ) 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 [10] (void()*~) main::$1 ← (void()*) getfn::return#0 [ main::i#1 main::$1 ] ( main:2 [ main::i#1 main::$1 ] ) always clobbers reg byte a
Statement [11] call (void()*~) main::$1 [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x reg byte y
Removing always clobbered register reg byte x 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 [9] (void()*) getfn::return#0 ← (void()*) getfn::return#3 [ main::i#1 getfn::return#0 ] ( main:2 [ main::i#1 getfn::return#0 ] ) always clobbers reg byte a
Statement [10] (void()*~) main::$1 ← (void()*) getfn::return#0 [ main::i#1 main::$1 ] ( main:2 [ main::i#1 main::$1 ] ) 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 ,
Statement [11] call (void()*~) main::$1 [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x reg byte y
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_WORD:3 [ getfn::return#3 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_BYTE:5 [ getfn::b#0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:6 [ getfn::return#0 ] : zp ZP_WORD:6 ,
@ -407,13 +411,14 @@ Uplift Scope [fn2]
Uplift Scope []
Uplifting [getfn] best 743 combination zp ZP_WORD:6 [ getfn::return#0 ] reg byte a [ getfn::b#0 ] reg byte a [ getfn::$0 ] zp ZP_WORD:3 [ getfn::return#3 ]
Uplifting [main] best 673 combination reg byte x [ main::i#2 main::i#1 ] zp ZP_WORD:8 [ main::$1 ]
Uplifting [fn1] best 673 combination
Uplifting [fn2] best 673 combination
Uplifting [] best 673 combination
Uplifting [main] best 743 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ] zp ZP_WORD:8 [ main::$1 ]
Uplifting [fn1] best 743 combination
Uplifting [fn2] best 743 combination
Uplifting [] best 743 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 743 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Coalescing zero page register with common assignment [ zp ZP_WORD:3 [ getfn::return#3 ] ] with [ zp ZP_WORD:6 [ getfn::return#0 ] ] - score: 1
Coalescing zero page register with common assignment [ zp ZP_WORD:3 [ getfn::return#3 getfn::return#0 ] ] with [ zp ZP_WORD:8 [ main::$1 ] ] - score: 1
Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ getfn::return#3 getfn::return#0 main::$1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
@ -441,21 +446,23 @@ bend_from_b1:
bend:
//SEG10 main
main: {
.label _1 = 2
.label _1 = 3
.label i = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG13 main::@1
b1:
jmp b2
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1 -- vbuaa=vbuxx
txa
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1 -- vbuaa=vbuz1
lda i
//SEG17 [8] call getfn
jsr getfn
//SEG18 [9] (void()*) getfn::return#0 ← (void()*) getfn::return#3
@ -475,7 +482,7 @@ main: {
//SEG24 getfn
// getfn(byte register(A) b)
getfn: {
.label return = 2
.label return = 3
//SEG25 [12] (byte~) getfn::$0 ← (byte) getfn::b#0 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuaa_band_vbuc1
and #1
//SEG26 [13] if((byte~) getfn::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto getfn::@return -- vbuaa_eq_0_then_la1
@ -585,25 +592,25 @@ FINAL SYMBOL TABLE
(byte) getfn::b
(byte) getfn::b#0 reg byte a 13.0
(void()*) getfn::return
(void()*) getfn::return#0 return zp ZP_WORD:2 22.0
(void()*) getfn::return#3 return zp ZP_WORD:2 3.6666666666666665
(void()*) getfn::return#0 return zp ZP_WORD:3 22.0
(void()*) getfn::return#3 return zp ZP_WORD:3 3.6666666666666665
(void()) main()
(void()*~) main::$1 $1 zp ZP_WORD:2 11.0
(void()*~) main::$1 $1 zp ZP_WORD:3 11.0
(label) main::@1
(label) main::@2
(label) main::@3
(byte) main::i
(byte) main::i#1 reg byte x 5.5
(byte) main::i#2 reg byte x 22.0
(byte) main::i#1 i zp ZP_BYTE:2 5.5
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ getfn::return#3 getfn::return#0 main::$1 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
zp ZP_WORD:3 [ getfn::return#3 getfn::return#0 main::$1 ]
reg byte a [ getfn::b#0 ]
reg byte a [ getfn::$0 ]
FINAL ASSEMBLER
Score: 319
Score: 389
//SEG0 File Comments
// Tests creating, assigning returning and calling pointers to non-args no-return functions
@ -621,17 +628,19 @@ Score: 319
//SEG9 @end
//SEG10 main
main: {
.label _1 = 2
.label _1 = 3
.label i = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG13 main::@1
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1 -- vbuaa=vbuxx
txa
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1 -- vbuaa=vbuz1
lda i
//SEG17 [8] call getfn
jsr getfn
//SEG18 [9] (void()*) getfn::return#0 ← (void()*) getfn::return#3
@ -648,7 +657,7 @@ main: {
//SEG24 getfn
// getfn(byte register(A) b)
getfn: {
.label return = 2
.label return = 3
//SEG25 [12] (byte~) getfn::$0 ← (byte) getfn::b#0 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuaa_band_vbuc1
and #1
//SEG26 [13] if((byte~) getfn::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto getfn::@return -- vbuaa_eq_0_then_la1

@ -16,18 +16,18 @@
(byte) getfn::b
(byte) getfn::b#0 reg byte a 13.0
(void()*) getfn::return
(void()*) getfn::return#0 return zp ZP_WORD:2 22.0
(void()*) getfn::return#3 return zp ZP_WORD:2 3.6666666666666665
(void()*) getfn::return#0 return zp ZP_WORD:3 22.0
(void()*) getfn::return#3 return zp ZP_WORD:3 3.6666666666666665
(void()) main()
(void()*~) main::$1 $1 zp ZP_WORD:2 11.0
(void()*~) main::$1 $1 zp ZP_WORD:3 11.0
(label) main::@1
(label) main::@2
(label) main::@3
(byte) main::i
(byte) main::i#1 reg byte x 5.5
(byte) main::i#2 reg byte x 22.0
(byte) main::i#1 i zp ZP_BYTE:2 5.5
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte x [ main::i#2 main::i#1 ]
zp ZP_WORD:2 [ getfn::return#3 getfn::return#0 main::$1 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
zp ZP_WORD:3 [ getfn::return#3 getfn::return#0 main::$1 ]
reg byte a [ getfn::b#0 ]
reg byte a [ getfn::$0 ]

@ -3,10 +3,12 @@
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label i = 2
lda #0
sta i
b2:
clc
adc #1
inc i
lda i
jsr getfn
jsr getfn.return
jmp b2

@ -267,7 +267,12 @@ fn1: {
}
REGISTER UPLIFT POTENTIAL REGISTERS
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
Statement [9] call (const void()*) getfn::return#1 [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x 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 x 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 [9] call (const void()*) getfn::return#1 [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x reg byte y
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_BYTE:3 [ getfn::b#0 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
@ -277,9 +282,11 @@ Uplift Scope [fn1]
Uplift Scope []
Uplifting [getfn] best 352 combination reg byte a [ getfn::b#0 ]
Uplifting [main] best 282 combination reg byte a [ main::i#2 main::i#1 ]
Uplifting [fn1] best 282 combination
Uplifting [] best 282 combination
Uplifting [main] best 352 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplifting [fn1] best 352 combination
Uplifting [] best 352 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 352 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
@ -307,20 +314,22 @@ bend_from_b1:
bend:
//SEG10 main
main: {
.label i = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuaa=vbuc1
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG13 main::@1
b1:
jmp b2
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuaa=_inc_vbuaa
clc
adc #1
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1 -- vbuaa=vbuz1
lda i
//SEG17 [8] call getfn
//SEG18 [10] phi from main::@2 to getfn [phi:main::@2->getfn]
getfn_from_b2:
@ -406,15 +415,15 @@ FINAL SYMBOL TABLE
(label) main::@2
(label) main::@3
(byte) main::i
(byte) main::i#1 reg byte a 8.25
(byte) main::i#2 reg byte a 22.0
(byte) main::i#1 i zp ZP_BYTE:2 8.25
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte a [ main::i#2 main::i#1 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
reg byte a [ getfn::b#0 ]
FINAL ASSEMBLER
Score: 174
Score: 244
//SEG0 File Comments
// Tests creating, assigning returning and calling pointers to non-args no-return functions
@ -432,16 +441,18 @@ Score: 174
//SEG9 @end
//SEG10 main
main: {
.label i = 2
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuaa=vbuc1
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG13 main::@1
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuaa=_inc_vbuaa
clc
adc #1
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte) getfn::b#0 ← (byte) main::i#1 -- vbuaa=vbuz1
lda i
//SEG17 [8] call getfn
//SEG18 [10] phi from main::@2 to getfn [phi:main::@2->getfn]
jsr getfn

@ -16,8 +16,8 @@
(label) main::@2
(label) main::@3
(byte) main::i
(byte) main::i#1 reg byte a 8.25
(byte) main::i#2 reg byte a 22.0
(byte) main::i#1 i zp ZP_BYTE:2 8.25
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte a [ main::i#2 main::i#1 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
reg byte a [ getfn::b#0 ]

@ -3,12 +3,14 @@
:BasicUpstart(main)
.pc = $80d "Program"
main: {
.label f = 2
ldx #0
.label i = 2
.label f = 3
lda #0
sta i
b2:
inx
txa
and #1
inc i
lda #1
and i
asl
tay
lda fns,y

@ -275,10 +275,14 @@ REGISTER UPLIFT POTENTIAL REGISTERS
Statement [8] (byte~) main::$1 ← (byte~) main::$0 << (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#1 main::$1 ] ( main:2 [ main::i#1 main::$1 ] ) 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 [9] (void()*) main::f#0 ← *((const void()*[2]) fns#0 + (byte~) main::$1) [ main::i#1 main::f#0 ] ( main:2 [ main::i#1 main::f#0 ] ) always clobbers reg byte a
Statement [10] call *((void()*) main::f#0) [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x reg byte y
Removing always clobbered register reg byte x 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 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#1 main::$0 ] ( main:2 [ main::i#1 main::$0 ] ) always clobbers reg byte a
Statement [8] (byte~) main::$1 ← (byte~) main::$0 << (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#1 main::$1 ] ( main:2 [ main::i#1 main::$1 ] ) always clobbers reg byte a
Statement [9] (void()*) main::f#0 ← *((const void()*[2]) fns#0 + (byte~) main::$1) [ main::i#1 main::f#0 ] ( main:2 [ main::i#1 main::f#0 ] ) 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 ,
Statement [10] call *((void()*) main::f#0) [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a reg byte x reg byte y
Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_BYTE:3 [ main::$0 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_BYTE:4 [ main::$1 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:5 [ main::f#0 ] : zp ZP_WORD:5 ,
@ -289,11 +293,13 @@ Uplift Scope [fn1]
Uplift Scope [fn2]
Uplift Scope []
Uplifting [main] best 512 combination reg byte x [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] reg byte a [ main::$1 ] zp ZP_WORD:5 [ main::f#0 ]
Uplifting [fn1] best 512 combination
Uplifting [fn2] best 512 combination
Uplifting [] best 512 combination
Allocated (was zp ZP_WORD:5) zp ZP_WORD:2 [ main::f#0 ]
Uplifting [main] best 582 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ] reg byte a [ main::$0 ] reg byte a [ main::$1 ] zp ZP_WORD:5 [ main::f#0 ]
Uplifting [fn1] best 582 combination
Uplifting [fn2] best 582 combination
Uplifting [] best 582 combination
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Uplifting [main] best 582 combination zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
Allocated (was zp ZP_WORD:5) zp ZP_WORD:3 [ main::f#0 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
@ -321,22 +327,24 @@ bend_from_b1:
bend:
//SEG10 main
main: {
.label f = 2
.label i = 2
.label f = 3
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG13 main::@1
b1:
jmp b2
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
lda #1
and i
//SEG17 [8] (byte~) main::$1 ← (byte~) main::$0 << (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuaa_rol_1
asl
//SEG18 [9] (void()*) main::f#0 ← *((const void()*[2]) fns#0 + (byte~) main::$1) -- pprz1=pptc1_derefidx_vbuaa
@ -425,19 +433,19 @@ FINAL SYMBOL TABLE
(label) main::@1
(label) main::@2
(void()*) main::f
(void()*) main::f#0 f zp ZP_WORD:2 11.0
(void()*) main::f#0 f zp ZP_WORD:3 11.0
(byte) main::i
(byte) main::i#1 reg byte x 6.6000000000000005
(byte) main::i#2 reg byte x 22.0
(byte) main::i#1 i zp ZP_BYTE:2 6.6000000000000005
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte x [ main::i#2 main::i#1 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
reg byte a [ main::$0 ]
reg byte a [ main::$1 ]
zp ZP_WORD:2 [ main::f#0 ]
zp ZP_WORD:3 [ main::f#0 ]
FINAL ASSEMBLER
Score: 434
Score: 504
//SEG0 File Comments
// Tests calling into arrays of pointers to non-args no-return functions
@ -455,18 +463,20 @@ Score: 434
//SEG9 @end
//SEG10 main
main: {
.label f = 2
.label i = 2
.label f = 3
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
ldx #0
//SEG12 [5] phi (byte) main::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG13 main::@1
//SEG14 main::@2
b2:
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuxx_band_vbuc1
txa
and #1
//SEG15 [6] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG16 [7] (byte~) main::$0 ← (byte) main::i#1 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
lda #1
and i
//SEG17 [8] (byte~) main::$1 ← (byte~) main::$0 << (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuaa_rol_1
asl
//SEG18 [9] (void()*) main::f#0 ← *((const void()*[2]) fns#0 + (byte~) main::$1) -- pprz1=pptc1_derefidx_vbuaa

@ -17,12 +17,12 @@
(label) main::@1
(label) main::@2
(void()*) main::f
(void()*) main::f#0 f zp ZP_WORD:2 11.0
(void()*) main::f#0 f zp ZP_WORD:3 11.0
(byte) main::i
(byte) main::i#1 reg byte x 6.6000000000000005
(byte) main::i#2 reg byte x 22.0
(byte) main::i#1 i zp ZP_BYTE:2 6.6000000000000005
(byte) main::i#2 i zp ZP_BYTE:2 22.0
reg byte x [ main::i#2 main::i#1 ]
zp ZP_BYTE:2 [ main::i#2 main::i#1 ]
reg byte a [ main::$0 ]
reg byte a [ main::$1 ]
zp ZP_WORD:2 [ main::f#0 ]
zp ZP_WORD:3 [ main::f#0 ]

@ -291,10 +291,11 @@ fn1: {
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [6] call *((const void()*) main::cls#0) [ main::cols#2 ] ( main:2 [ main::cols#2 ] ) always clobbers reg byte a reg byte x reg byte y
Statement [7] *((byte*) main::cols#2) ← ++ *((byte*) main::cols#2) [ main::cols#2 ] ( main:2 [ main::cols#2 ] ) always clobbers reg byte a reg byte y
Statement [9] if((byte*) main::cols#1<(word/dword/signed dword) $d800+(word/signed word/dword/signed dword) $3e8) goto main::@1 [ main::cols#1 ] ( main:2 [ main::cols#1 ] ) always clobbers reg byte a
Statement [13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2) [ fn1::screen#2 ] ( ) always clobbers reg byte a reg byte y
Statement [15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1 [ fn1::screen#1 ] ( ) always clobbers reg byte a
Statement [13] *((byte*) fn1::screen#2) ← ++ *((byte*) fn1::screen#2) [ fn1::screen#2 ] ( [ fn1::screen#2 ] ) always clobbers reg byte a reg byte y
Statement [15] if((byte*) fn1::screen#1<(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3e8) goto fn1::@1 [ fn1::screen#1 ] ( [ fn1::screen#1 ] ) always clobbers reg byte a
Potential registers zp ZP_WORD:2 [ main::cols#2 main::cols#1 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_WORD:4 [ fn1::screen#2 fn1::screen#1 ] : zp ZP_WORD:4 ,

@ -0,0 +1,42 @@
// Tests calling into a function pointer with local variables
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
.label SCREEN = $400
.label idx = 3
bbegin:
lda #0
sta idx
jsr main
rts
main: {
.label f = hello
jsr do10
rts
}
do10: {
.label i = 2
lda #0
sta i
b1:
jsr main.f
inc i
lda #$a
cmp i
bne b1
rts
}
hello: {
ldx #0
b1:
lda msg,x
ldy idx
sta SCREEN,y
inc idx
inx
lda msg,x
cmp #'@'
bne b1
rts
}
msg: .text "hello @"

@ -0,0 +1,45 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@2
@2: scope:[] from @1
[2] phi()
[3] call main
to:@end
@end: scope:[] from @2
[4] phi()
main: scope:[main] from @2
[5] phi()
[6] call do10
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return
do10: scope:[do10] from main
[8] phi()
to:do10::@1
do10::@1: scope:[do10] from do10 do10::@1
[9] (byte) do10::i#2 ← phi( do10/(byte/signed byte/word/signed word/dword/signed dword) 0 do10::@1/(byte) do10::i#1 )
[10] call *((const void()*) main::f#0)
[11] (byte) do10::i#1 ← ++ (byte) do10::i#2
[12] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1
to:do10::@return
do10::@return: scope:[do10] from do10::@1
[13] return
to:@return
hello: scope:[hello] from
[14] phi()
to:hello::@1
hello::@1: scope:[hello] from hello hello::@1
[15] (byte) idx#3 ← phi( hello/(byte) idx#0 hello::@1/(byte) idx#1 )
[15] (byte) hello::i#2 ← phi( hello/(byte/signed byte/word/signed word/dword/signed dword) 0 hello::@1/(byte) hello::i#1 )
[16] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((const byte[]) msg#0 + (byte) hello::i#2)
[17] (byte) idx#1 ← ++ (byte) idx#3
[18] (byte) hello::i#1 ← ++ (byte) hello::i#2
[19] if(*((const byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1
to:hello::@return
hello::@return: scope:[hello] from hello::@1
[20] return
to:@return

@ -0,0 +1,664 @@
Resolved forward reference hello to (void()) hello()
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@2
main: scope:[main] from @3
(void()*~) main::$0 ← & (void()) hello()
(void()*) main::f#0 ← (void()*~) main::$0
(void()*) do10::fn#0 ← (void()*) main::f#0
call do10
to:main::@1
main::@1: scope:[main] from main
to:main::@return
main::@return: scope:[main] from main::@1
return
to:@return
do10: scope:[do10] from main
(void()*) do10::fn#2 ← phi( main/(void()*) do10::fn#0 )
(byte) do10::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:do10::@1
do10::@1: scope:[do10] from do10 do10::@1
(byte) do10::i#2 ← phi( do10/(byte) do10::i#0 do10::@1/(byte) do10::i#1 )
(void()*) do10::fn#1 ← phi( do10/(void()*) do10::fn#2 do10::@1/(void()*) do10::fn#1 )
call *((void()*) do10::fn#1)
(byte) do10::i#1 ← (byte) do10::i#2 + rangenext(0,9)
(bool~) do10::$1 ← (byte) do10::i#1 != rangelast(0,9)
if((bool~) do10::$1) goto do10::@1
to:do10::@return
do10::@return: scope:[do10] from do10::@1
return
to:@return
@2: scope:[] from @begin
(byte*) SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte[]) msg#0 ← (const string) $0
(byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@3
hello: scope:[hello] from
(byte) idx#5 ← phi( @3/(byte) idx#6 )
(byte) hello::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:hello::@1
hello::@1: scope:[hello] from hello hello::@1
(byte) idx#3 ← phi( hello/(byte) idx#5 hello::@1/(byte) idx#1 )
(byte) hello::i#2 ← phi( hello/(byte) hello::i#0 hello::@1/(byte) hello::i#1 )
*((byte*) SCREEN#0 + (byte) idx#3) ← *((byte[]) msg#0 + (byte) hello::i#2)
(byte) idx#1 ← ++ (byte) idx#3
(byte) hello::i#1 ← ++ (byte) hello::i#2
(bool~) hello::$0 ← *((byte[]) msg#0 + (byte) hello::i#1) != (byte) '@'
if((bool~) hello::$0) goto hello::@1
to:hello::@return
hello::@return: scope:[hello] from hello::@1
(byte) idx#4 ← phi( hello::@1/(byte) idx#1 )
(byte) idx#2 ← (byte) idx#4
return
to:@return
@3: scope:[] from @2
(byte) idx#6 ← phi( @2/(byte) idx#0 )
call main
to:@4
@4: scope:[] from @3
to:@end
@end: scope:[] from @4
SYMBOL TABLE SSA
(const string) $0 = (string) "hello @"
(label) @2
(label) @3
(label) @4
(label) @begin
(label) @end
(byte*) SCREEN
(byte*) SCREEN#0
(void()) do10((void()*) do10::fn)
(bool~) do10::$1
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(void()*) do10::fn#0
(void()*) do10::fn#1
(void()*) do10::fn#2
(byte) do10::i
(byte) do10::i#0
(byte) do10::i#1
(byte) do10::i#2
(void()) hello()
(bool~) hello::$0
(label) hello::@1
(label) hello::@return
(byte) hello::i
(byte) hello::i#0
(byte) hello::i#1
(byte) hello::i#2
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(void()) main()
(void()*~) main::$0
(label) main::@1
(label) main::@return
(void()*) main::f
(void()*) main::f#0
(byte[]) msg
(byte[]) msg#0
Culled Empty Block (label) main::@1
Culled Empty Block (label) @4
Successful SSA optimization Pass2CullEmptyBlocks
Alias (void()*) main::f#0 = (void()*~) main::$0
Alias (byte) idx#1 = (byte) idx#4 (byte) idx#2
Alias (byte) idx#0 = (byte) idx#6
Successful SSA optimization Pass2AliasElimination
Self Phi Eliminated (void()*) do10::fn#1
Successful SSA optimization Pass2SelfPhiElimination
Redundant Phi (void()*) do10::fn#2 (void()*) do10::fn#0
Redundant Phi (void()*) do10::fn#1 (void()*) do10::fn#2
Redundant Phi (byte) idx#5 (byte) idx#0
Successful SSA optimization Pass2RedundantPhiElimination
Simple Condition (bool~) do10::$1 [11] if((byte) do10::i#1!=rangelast(0,9)) goto do10::@1
Simple Condition (bool~) hello::$0 [23] if(*((byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const void()*) main::f#0 = &hello
Constant (const byte) do10::i#0 = 0
Constant (const byte*) SCREEN#0 = ((byte*))$400
Constant (const byte[]) msg#0 = $0
Constant (const byte) hello::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const void()*) do10::fn#0 = main::f#0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value do10::i#1 ← ++ do10::i#2 to ++
Resolved ranged comparison value if(do10::i#1!=rangelast(0,9)) goto do10::@1 to (byte/signed byte/word/signed word/dword/signed dword) $a
Inlining constant with var siblings (const byte) do10::i#0
Inlining constant with var siblings (const byte) hello::i#0
Constant inlined hello::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined do10::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined do10::fn#0 = (const void()*) main::f#0
Constant inlined $0 = (const byte[]) msg#0
Successful SSA optimization Pass2ConstantInlining
Added new block during phi lifting do10::@3(between do10::@1 and do10::@1)
Added new block during phi lifting hello::@3(between hello::@1 and hello::@1)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of do10
CALL GRAPH
Calls in [] to main:3
Calls in [main] to do10:6
Created 3 initial phi equivalence classes
Coalesced [14] do10::i#3 ← do10::i#1
Coalesced [15] idx#7 ← idx#0
Coalesced [22] hello::i#3 ← hello::i#1
Coalesced [23] idx#8 ← idx#1
Coalesced down to 3 phi equivalence classes
Culled Empty Block (label) do10::@3
Culled Empty Block (label) hello::@3
Renumbering block @2 to @1
Renumbering block @3 to @2
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
Adding NOP phi() at start of do10
Adding NOP phi() at start of hello
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@2
@2: scope:[] from @1
[2] phi()
[3] call main
to:@end
@end: scope:[] from @2
[4] phi()
main: scope:[main] from @2
[5] phi()
[6] call do10
to:main::@return
main::@return: scope:[main] from main
[7] return
to:@return
do10: scope:[do10] from main
[8] phi()
to:do10::@1
do10::@1: scope:[do10] from do10 do10::@1
[9] (byte) do10::i#2 ← phi( do10/(byte/signed byte/word/signed word/dword/signed dword) 0 do10::@1/(byte) do10::i#1 )
[10] call *((const void()*) main::f#0)
[11] (byte) do10::i#1 ← ++ (byte) do10::i#2
[12] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1
to:do10::@return
do10::@return: scope:[do10] from do10::@1
[13] return
to:@return
hello: scope:[hello] from
[14] phi()
to:hello::@1
hello::@1: scope:[hello] from hello hello::@1
[15] (byte) idx#3 ← phi( hello/(byte) idx#0 hello::@1/(byte) idx#1 )
[15] (byte) hello::i#2 ← phi( hello/(byte/signed byte/word/signed word/dword/signed dword) 0 hello::@1/(byte) hello::i#1 )
[16] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((const byte[]) msg#0 + (byte) hello::i#2)
[17] (byte) idx#1 ← ++ (byte) idx#3
[18] (byte) hello::i#1 ← ++ (byte) hello::i#2
[19] if(*((const byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1
to:hello::@return
hello::@return: scope:[hello] from hello::@1
[20] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(void()) do10((void()*) do10::fn)
(void()*) do10::fn
(byte) do10::i
(byte) do10::i#1 16.5
(byte) do10::i#2 11.0
(void()) hello()
(byte) hello::i
(byte) hello::i#1 16.5
(byte) hello::i#2 11.0
(byte) idx
(byte) idx#0 4.0
(byte) idx#1 7.333333333333333
(byte) idx#3 17.5
(void()) main()
(void()*) main::f
(byte[]) msg
Initial phi equivalence classes
[ do10::i#2 do10::i#1 ]
[ hello::i#2 hello::i#1 ]
[ idx#3 idx#0 idx#1 ]
Complete equivalence classes
[ do10::i#2 do10::i#1 ]
[ hello::i#2 hello::i#1 ]
[ idx#3 idx#0 idx#1 ]
Allocated zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Allocated zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Allocated zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
INITIAL ASM
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label idx = 4
//SEG3 @begin
bbegin:
jmp b1
//SEG4 @1
b1:
//SEG5 [1] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- vbuz1=vbuc1
lda #0
sta idx
//SEG6 [2] phi from @1 to @2 [phi:@1->@2]
b2_from_b1:
jmp b2
//SEG7 @2
b2:
//SEG8 [3] call main
//SEG9 [5] phi from @2 to main [phi:@2->main]
main_from_b2:
jsr main
//SEG10 [4] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend
//SEG11 @end
bend:
//SEG12 main
main: {
.label f = hello
//SEG13 [6] call do10
//SEG14 [8] phi from main to do10 [phi:main->do10]
do10_from_main:
jsr do10
jmp breturn
//SEG15 main::@return
breturn:
//SEG16 [7] return
rts
}
//SEG17 do10
do10: {
.label i = 2
//SEG18 [9] phi from do10 to do10::@1 [phi:do10->do10::@1]
b1_from_do10:
//SEG19 [9] phi (byte) do10::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG20 [9] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
b1_from_b1:
//SEG21 [9] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy
jmp b1
//SEG22 do10::@1
b1:
//SEG23 [10] call *((const void()*) main::f#0)
jsr main.f
//SEG24 [11] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG25 [12] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$a
cmp i
bne b1_from_b1
jmp breturn
//SEG26 do10::@return
breturn:
//SEG27 [13] return
rts
}
//SEG28 hello
hello: {
.label i = 3
//SEG29 [15] phi from hello to hello::@1 [phi:hello->hello::@1]
b1_from_hello:
//SEG30 [15] phi (byte) idx#3 = (byte) idx#0 [phi:hello->hello::@1#0] -- register_copy
//SEG31 [15] phi (byte) hello::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:hello->hello::@1#1] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG32 [15] phi from hello::@1 to hello::@1 [phi:hello::@1->hello::@1]
b1_from_b1:
//SEG33 [15] phi (byte) idx#3 = (byte) idx#1 [phi:hello::@1->hello::@1#0] -- register_copy
//SEG34 [15] phi (byte) hello::i#2 = (byte) hello::i#1 [phi:hello::@1->hello::@1#1] -- register_copy
jmp b1
//SEG35 hello::@1
b1:
//SEG36 [16] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((const byte[]) msg#0 + (byte) hello::i#2) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuz2
ldy i
lda msg,y
ldy idx
sta SCREEN,y
//SEG37 [17] (byte) idx#1 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz1
inc idx
//SEG38 [18] (byte) hello::i#1 ← ++ (byte) hello::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG39 [19] if(*((const byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 -- pbuc1_derefidx_vbuz1_neq_vbuc2_then_la1
lda #'@'
ldy i
cmp msg,y
bne b1_from_b1
jmp breturn
//SEG40 hello::@return
breturn:
//SEG41 [20] return
rts
}
msg: .text "hello @"
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [1] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( ) always clobbers reg byte a
Statement [10] call *((const void()*) main::f#0) [ do10::i#2 ] ( main:3::do10:6 [ do10::i#2 ] ) always clobbers reg byte a reg byte x reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Removing always clobbered register reg byte x as potential for zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Statement [12] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 [ do10::i#1 ] ( main:3::do10:6 [ do10::i#1 ] ) always clobbers reg byte a
Statement [16] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((const byte[]) msg#0 + (byte) hello::i#2) [ hello::i#2 idx#3 ] ( [ hello::i#2 idx#3 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Statement [19] if(*((const byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 [ hello::i#1 idx#1 ] ( [ hello::i#1 idx#1 ] ) always clobbers reg byte a
Statement [1] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( ) always clobbers reg byte a
Statement [10] call *((const void()*) main::f#0) [ do10::i#2 ] ( main:3::do10:6 [ do10::i#2 ] ) always clobbers reg byte a reg byte x reg byte y
Statement [12] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 [ do10::i#1 ] ( main:3::do10:6 [ do10::i#1 ] ) always clobbers reg byte a
Statement [16] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((const byte[]) msg#0 + (byte) hello::i#2) [ hello::i#2 idx#3 ] ( [ hello::i#2 idx#3 ] ) always clobbers reg byte a reg byte y
Statement [19] if(*((const byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 [ hello::i#1 idx#1 ] ( [ hello::i#1 idx#1 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ] : zp ZP_BYTE:3 , reg byte x ,
Potential registers zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ] : zp ZP_BYTE:4 ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 28.83: zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
Uplift Scope [do10] 27.5: zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Uplift Scope [hello] 27.5: zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Uplift Scope [main]
Uplifting [] best 914 combination zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
Uplifting [do10] best 914 combination zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Uplifting [hello] best 794 combination reg byte x [ hello::i#2 hello::i#1 ]
Uplifting [main] best 794 combination
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
Uplifting [] best 794 combination zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Uplifting [do10] best 794 combination zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Allocated (was zp ZP_BYTE:4) zp ZP_BYTE:3 [ idx#3 idx#0 idx#1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label idx = 3
//SEG3 @begin
bbegin:
jmp b1
//SEG4 @1
b1:
//SEG5 [1] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- vbuz1=vbuc1
lda #0
sta idx
//SEG6 [2] phi from @1 to @2 [phi:@1->@2]
b2_from_b1:
jmp b2
//SEG7 @2
b2:
//SEG8 [3] call main
//SEG9 [5] phi from @2 to main [phi:@2->main]
main_from_b2:
jsr main
//SEG10 [4] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend
//SEG11 @end
bend:
//SEG12 main
main: {
.label f = hello
//SEG13 [6] call do10
//SEG14 [8] phi from main to do10 [phi:main->do10]
do10_from_main:
jsr do10
jmp breturn
//SEG15 main::@return
breturn:
//SEG16 [7] return
rts
}
//SEG17 do10
do10: {
.label i = 2
//SEG18 [9] phi from do10 to do10::@1 [phi:do10->do10::@1]
b1_from_do10:
//SEG19 [9] phi (byte) do10::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG20 [9] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
b1_from_b1:
//SEG21 [9] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy
jmp b1
//SEG22 do10::@1
b1:
//SEG23 [10] call *((const void()*) main::f#0)
jsr main.f
//SEG24 [11] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG25 [12] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$a
cmp i
bne b1_from_b1
jmp breturn
//SEG26 do10::@return
breturn:
//SEG27 [13] return
rts
}
//SEG28 hello
hello: {
//SEG29 [15] phi from hello to hello::@1 [phi:hello->hello::@1]
b1_from_hello:
//SEG30 [15] phi (byte) idx#3 = (byte) idx#0 [phi:hello->hello::@1#0] -- register_copy
//SEG31 [15] phi (byte) hello::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:hello->hello::@1#1] -- vbuxx=vbuc1
ldx #0
jmp b1
//SEG32 [15] phi from hello::@1 to hello::@1 [phi:hello::@1->hello::@1]
b1_from_b1:
//SEG33 [15] phi (byte) idx#3 = (byte) idx#1 [phi:hello::@1->hello::@1#0] -- register_copy
//SEG34 [15] phi (byte) hello::i#2 = (byte) hello::i#1 [phi:hello::@1->hello::@1#1] -- register_copy
jmp b1
//SEG35 hello::@1
b1:
//SEG36 [16] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((const byte[]) msg#0 + (byte) hello::i#2) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuxx
lda msg,x
ldy idx
sta SCREEN,y
//SEG37 [17] (byte) idx#1 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz1
inc idx
//SEG38 [18] (byte) hello::i#1 ← ++ (byte) hello::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG39 [19] if(*((const byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
lda msg,x
cmp #'@'
bne b1_from_b1
jmp breturn
//SEG40 hello::@return
breturn:
//SEG41 [20] return
rts
}
msg: .text "hello @"
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp bend
Removing instruction jmp breturn
Removing instruction jmp b1
Removing instruction jmp breturn
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Replacing label b1_from_b1 with b1
Replacing label b1_from_b1 with b1
Removing instruction b1:
Removing instruction b2_from_b1:
Removing instruction main_from_b2:
Removing instruction bend_from_b2:
Removing instruction b1_from_b1:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction b2:
Removing instruction bend:
Removing instruction do10_from_main:
Removing instruction breturn:
Removing instruction b1_from_do10:
Removing instruction breturn:
Removing instruction b1_from_hello:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b1
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
FINAL SYMBOL TABLE
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(void()) do10((void()*) do10::fn)
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(byte) do10::i
(byte) do10::i#1 i zp ZP_BYTE:2 16.5
(byte) do10::i#2 i zp ZP_BYTE:2 11.0
(void()) hello()
(label) hello::@1
(label) hello::@return
(byte) hello::i
(byte) hello::i#1 reg byte x 16.5
(byte) hello::i#2 reg byte x 11.0
(byte) idx
(byte) idx#0 idx zp ZP_BYTE:3 4.0
(byte) idx#1 idx zp ZP_BYTE:3 7.333333333333333
(byte) idx#3 idx zp ZP_BYTE:3 17.5
(void()) main()
(label) main::@return
(void()*) main::f
(const void()*) main::f#0 f = &(void()) hello()
(byte[]) msg
(const byte[]) msg#0 msg = (string) "hello @"
zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
reg byte x [ hello::i#2 hello::i#1 ]
zp ZP_BYTE:3 [ idx#3 idx#0 idx#1 ]
FINAL ASSEMBLER
Score: 581
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label idx = 3
//SEG3 @begin
bbegin:
//SEG4 @1
//SEG5 [1] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- vbuz1=vbuc1
lda #0
sta idx
//SEG6 [2] phi from @1 to @2 [phi:@1->@2]
//SEG7 @2
//SEG8 [3] call main
//SEG9 [5] phi from @2 to main [phi:@2->main]
jsr main
rts
//SEG10 [4] phi from @2 to @end [phi:@2->@end]
//SEG11 @end
//SEG12 main
main: {
.label f = hello
//SEG13 [6] call do10
//SEG14 [8] phi from main to do10 [phi:main->do10]
jsr do10
//SEG15 main::@return
//SEG16 [7] return
rts
}
//SEG17 do10
do10: {
.label i = 2
//SEG18 [9] phi from do10 to do10::@1 [phi:do10->do10::@1]
//SEG19 [9] phi (byte) do10::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG20 [9] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
//SEG21 [9] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy
//SEG22 do10::@1
b1:
//SEG23 [10] call *((const void()*) main::f#0)
jsr main.f
//SEG24 [11] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG25 [12] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$a
cmp i
bne b1
//SEG26 do10::@return
//SEG27 [13] return
rts
}
//SEG28 hello
hello: {
//SEG29 [15] phi from hello to hello::@1 [phi:hello->hello::@1]
//SEG30 [15] phi (byte) idx#3 = (byte) idx#0 [phi:hello->hello::@1#0] -- register_copy
//SEG31 [15] phi (byte) hello::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:hello->hello::@1#1] -- vbuxx=vbuc1
ldx #0
//SEG32 [15] phi from hello::@1 to hello::@1 [phi:hello::@1->hello::@1]
//SEG33 [15] phi (byte) idx#3 = (byte) idx#1 [phi:hello::@1->hello::@1#0] -- register_copy
//SEG34 [15] phi (byte) hello::i#2 = (byte) hello::i#1 [phi:hello::@1->hello::@1#1] -- register_copy
//SEG35 hello::@1
b1:
//SEG36 [16] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((const byte[]) msg#0 + (byte) hello::i#2) -- pbuc1_derefidx_vbuz1=pbuc2_derefidx_vbuxx
lda msg,x
ldy idx
sta SCREEN,y
//SEG37 [17] (byte) idx#1 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz1
inc idx
//SEG38 [18] (byte) hello::i#1 ← ++ (byte) hello::i#2 -- vbuxx=_inc_vbuxx
inx
//SEG39 [19] if(*((const byte[]) msg#0 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 -- pbuc1_derefidx_vbuxx_neq_vbuc2_then_la1
lda msg,x
cmp #'@'
bne b1
//SEG40 hello::@return
//SEG41 [20] return
rts
}
msg: .text "hello @"

@ -0,0 +1,33 @@
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(void()) do10((void()*) do10::fn)
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(byte) do10::i
(byte) do10::i#1 i zp ZP_BYTE:2 16.5
(byte) do10::i#2 i zp ZP_BYTE:2 11.0
(void()) hello()
(label) hello::@1
(label) hello::@return
(byte) hello::i
(byte) hello::i#1 reg byte x 16.5
(byte) hello::i#2 reg byte x 11.0
(byte) idx
(byte) idx#0 idx zp ZP_BYTE:3 4.0
(byte) idx#1 idx zp ZP_BYTE:3 7.333333333333333
(byte) idx#3 idx zp ZP_BYTE:3 17.5
(void()) main()
(label) main::@return
(void()*) main::f
(const void()*) main::f#0 f = &(void()) hello()
(byte[]) msg
(const byte[]) msg#0 msg = (string) "hello @"
zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
reg byte x [ hello::i#2 hello::i#1 ]
zp ZP_BYTE:3 [ idx#3 idx#0 idx#1 ]

@ -0,0 +1,55 @@
// Tests calling into a function pointer with local variables
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
.label SCREEN = $400
.label msg = 4
.label idx = 3
bbegin:
lda #<0
sta msg
sta msg+1
sta idx
jsr main
rts
main: {
.label f = hello
lda #<msg1
sta msg
lda #>msg1
sta msg+1
jsr do10
lda #<msg2
sta msg
lda #>msg2
sta msg+1
jsr do10
rts
}
do10: {
.label i = 2
lda #0
sta i
b1:
jsr main.f
inc i
lda #$a
cmp i
bne b1
rts
}
hello: {
ldy #0
b1:
lda (msg),y
ldx idx
sta SCREEN,x
inc idx
iny
lda (msg),y
cmp #'@'
bne b1
rts
}
msg1: .text "hello @"
msg2: .text "world @"

@ -0,0 +1,50 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] (byte*) msg#10 ← (byte*) 0
[2] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@2
@2: scope:[] from @1
[3] phi()
[4] call main
to:@end
@end: scope:[] from @2
[5] phi()
main: scope:[main] from @2
[6] (byte*) msg#0 ← (const byte[]) msg1#0
[7] call do10
to:main::@1
main::@1: scope:[main] from main
[8] (byte*) msg#1 ← (const byte[]) msg2#0
[9] call do10
to:main::@return
main::@return: scope:[main] from main::@1
[10] return
to:@return
do10: scope:[do10] from main main::@1
[11] phi()
to:do10::@1
do10::@1: scope:[do10] from do10 do10::@1
[12] (byte) do10::i#2 ← phi( do10/(byte/signed byte/word/signed word/dword/signed dword) 0 do10::@1/(byte) do10::i#1 )
[13] call *((const void()*) main::f#0)
[14] (byte) do10::i#1 ← ++ (byte) do10::i#2
[15] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1
to:do10::@return
do10::@return: scope:[do10] from do10::@1
[16] return
to:@return
hello: scope:[hello] from
[17] phi()
to:hello::@1
hello::@1: scope:[hello] from hello hello::@1
[18] (byte) idx#3 ← phi( hello/(byte) idx#0 hello::@1/(byte) idx#1 )
[18] (byte) hello::i#2 ← phi( hello/(byte/signed byte/word/signed word/dword/signed dword) 0 hello::@1/(byte) hello::i#1 )
[19] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#10 + (byte) hello::i#2)
[20] (byte) idx#1 ← ++ (byte) idx#3
[21] (byte) hello::i#1 ← ++ (byte) hello::i#2
[22] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1
to:hello::@return
hello::@return: scope:[hello] from hello::@1
[23] return
to:@return

@ -0,0 +1,823 @@
Resolved forward reference hello to (void()) hello()
Resolved forward reference msg1 to (byte[]) msg1
Resolved forward reference msg to (byte*) msg
Resolved forward reference msg2 to (byte[]) msg2
Resolved forward reference msg to (byte*) msg
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@2
main: scope:[main] from @3
(void()*~) main::$0 ← & (void()) hello()
(void()*) main::f#0 ← (void()*~) main::$0
(byte*) msg#0 ← (byte[]) msg1#0
(void()*) do10::fn#0 ← (void()*) main::f#0
call do10
to:main::@1
main::@1: scope:[main] from main
(void()*) main::f#1 ← phi( main/(void()*) main::f#0 )
(byte*) msg#1 ← (byte[]) msg2#0
(void()*) do10::fn#1 ← (void()*) main::f#1
call do10
to:main::@2
main::@2: scope:[main] from main::@1
(byte*) msg#8 ← phi( main::@1/(byte*) msg#1 )
to:main::@return
main::@return: scope:[main] from main::@2
(byte*) msg#5 ← phi( main::@2/(byte*) msg#8 )
(byte*) msg#2 ← (byte*) msg#5
return
to:@return
do10: scope:[do10] from main main::@1
(void()*) do10::fn#3 ← phi( main/(void()*) do10::fn#0 main::@1/(void()*) do10::fn#1 )
(byte) do10::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:do10::@1
do10::@1: scope:[do10] from do10 do10::@1
(byte) do10::i#2 ← phi( do10/(byte) do10::i#0 do10::@1/(byte) do10::i#1 )
(void()*) do10::fn#2 ← phi( do10/(void()*) do10::fn#3 do10::@1/(void()*) do10::fn#2 )
call *((void()*) do10::fn#2)
(byte) do10::i#1 ← (byte) do10::i#2 + rangenext(0,9)
(bool~) do10::$1 ← (byte) do10::i#1 != rangelast(0,9)
if((bool~) do10::$1) goto do10::@1
to:do10::@return
do10::@return: scope:[do10] from do10::@1
return
to:@return
@2: scope:[] from @begin
(byte*) SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
(byte[]) msg1#0 ← (const string) $0
(byte[]) msg2#0 ← (const string) $1
(byte*) msg#3 ← (byte*) 0
(byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@3
hello: scope:[hello] from
(byte) idx#5 ← phi( @3/(byte) idx#6 )
(byte*) msg#9 ← phi( @3/(byte*) msg#10 )
(byte) hello::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:hello::@1
hello::@1: scope:[hello] from hello hello::@1
(byte) idx#3 ← phi( hello/(byte) idx#5 hello::@1/(byte) idx#1 )
(byte) hello::i#2 ← phi( hello/(byte) hello::i#0 hello::@1/(byte) hello::i#1 )
(byte*) msg#6 ← phi( hello/(byte*) msg#9 hello::@1/(byte*) msg#6 )
*((byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#6 + (byte) hello::i#2)
(byte) idx#1 ← ++ (byte) idx#3
(byte) hello::i#1 ← ++ (byte) hello::i#2
(bool~) hello::$0 ← *((byte*) msg#6 + (byte) hello::i#1) != (byte) '@'
if((bool~) hello::$0) goto hello::@1
to:hello::@return
hello::@return: scope:[hello] from hello::@1
(byte) idx#4 ← phi( hello::@1/(byte) idx#1 )
(byte) idx#2 ← (byte) idx#4
return
to:@return
@3: scope:[] from @2
(byte) idx#6 ← phi( @2/(byte) idx#0 )
(byte*) msg#10 ← phi( @2/(byte*) msg#3 )
call main
to:@4
@4: scope:[] from @3
(byte*) msg#7 ← phi( @3/(byte*) msg#2 )
(byte*) msg#4 ← (byte*) msg#7
to:@end
@end: scope:[] from @4
SYMBOL TABLE SSA
(const string) $0 = (string) "hello @"
(const string) $1 = (string) "world @"
(label) @2
(label) @3
(label) @4
(label) @begin
(label) @end
(byte*) SCREEN
(byte*) SCREEN#0
(void()) do10((void()*) do10::fn)
(bool~) do10::$1
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(void()*) do10::fn#0
(void()*) do10::fn#1
(void()*) do10::fn#2
(void()*) do10::fn#3
(byte) do10::i
(byte) do10::i#0
(byte) do10::i#1
(byte) do10::i#2
(void()) hello()
(bool~) hello::$0
(label) hello::@1
(label) hello::@return
(byte) hello::i
(byte) hello::i#0
(byte) hello::i#1
(byte) hello::i#2
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(void()) main()
(void()*~) main::$0
(label) main::@1
(label) main::@2
(label) main::@return
(void()*) main::f
(void()*) main::f#0
(void()*) main::f#1
(byte*) msg
(byte*) msg#0
(byte*) msg#1
(byte*) msg#10
(byte*) msg#2
(byte*) msg#3
(byte*) msg#4
(byte*) msg#5
(byte*) msg#6
(byte*) msg#7
(byte*) msg#8
(byte*) msg#9
(byte[]) msg1
(byte[]) msg1#0
(byte[]) msg2
(byte[]) msg2#0
Alias (void()*) main::f#0 = (void()*~) main::$0 (void()*) main::f#1
Alias (byte*) msg#1 = (byte*) msg#8 (byte*) msg#5 (byte*) msg#2
Alias (byte) idx#1 = (byte) idx#4 (byte) idx#2
Alias (byte*) msg#10 = (byte*) msg#3
Alias (byte) idx#0 = (byte) idx#6
Alias (byte*) msg#4 = (byte*) msg#7
Successful SSA optimization Pass2AliasElimination
Self Phi Eliminated (void()*) do10::fn#2
Self Phi Eliminated (byte*) msg#6
Successful SSA optimization Pass2SelfPhiElimination
Redundant Phi (void()*) do10::fn#2 (void()*) do10::fn#3
Redundant Phi (byte*) msg#9 (byte*) msg#10
Redundant Phi (byte) idx#5 (byte) idx#0
Redundant Phi (byte*) msg#6 (byte*) msg#9
Redundant Phi (byte*) msg#4 (byte*) msg#1
Successful SSA optimization Pass2RedundantPhiElimination
Simple Condition (bool~) do10::$1 [19] if((byte) do10::i#1!=rangelast(0,9)) goto do10::@1
Simple Condition (bool~) hello::$0 [33] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const void()*) main::f#0 = &hello
Constant (const byte) do10::i#0 = 0
Constant (const byte*) SCREEN#0 = ((byte*))$400
Constant (const byte[]) msg1#0 = $0
Constant (const byte[]) msg2#0 = $1
Constant (const byte) hello::i#0 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const void()*) do10::fn#0 = main::f#0
Constant (const void()*) do10::fn#1 = main::f#0
Successful SSA optimization Pass2ConstantIdentification
Resolved ranged next value do10::i#1 ← ++ do10::i#2 to ++
Resolved ranged comparison value if(do10::i#1!=rangelast(0,9)) goto do10::@1 to (byte/signed byte/word/signed word/dword/signed dword) $a
Culled Empty Block (label) main::@2
Culled Empty Block (label) @4
Successful SSA optimization Pass2CullEmptyBlocks
Inlining constant with var siblings (const byte) do10::i#0
Inlining constant with var siblings (const void()*) do10::fn#0
Inlining constant with var siblings (const void()*) do10::fn#1
Inlining constant with var siblings (const byte) hello::i#0
Constant inlined hello::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined do10::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
Constant inlined do10::fn#1 = (const void()*) main::f#0
Constant inlined do10::fn#0 = (const void()*) main::f#0
Constant inlined $0 = (const byte[]) msg1#0
Constant inlined $1 = (const byte[]) msg2#0
Successful SSA optimization Pass2ConstantInlining
Identical Phi Values (void()*) do10::fn#3 (const void()*) main::f#0
Successful SSA optimization Pass2IdenticalPhiElimination
Added new block during phi lifting do10::@3(between do10::@1 and do10::@1)
Added new block during phi lifting hello::@3(between hello::@1 and hello::@1)
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of do10
CALL GRAPH
Calls in [] to main:4
Calls in [main] to do10:7 do10:9
Created 3 initial phi equivalence classes
Coalesced [17] do10::i#3 ← do10::i#1
Coalesced [18] idx#7 ← idx#0
Coalesced [25] hello::i#3 ← hello::i#1
Coalesced [26] idx#8 ← idx#1
Coalesced down to 3 phi equivalence classes
Culled Empty Block (label) do10::@3
Culled Empty Block (label) hello::@3
Renumbering block @2 to @1
Renumbering block @3 to @2
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 do10
Adding NOP phi() at start of hello
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] (byte*) msg#10 ← (byte*) 0
[2] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@2
@2: scope:[] from @1
[3] phi()
[4] call main
to:@end
@end: scope:[] from @2
[5] phi()
main: scope:[main] from @2
[6] (byte*) msg#0 ← (const byte[]) msg1#0
[7] call do10
to:main::@1
main::@1: scope:[main] from main
[8] (byte*) msg#1 ← (const byte[]) msg2#0
[9] call do10
to:main::@return
main::@return: scope:[main] from main::@1
[10] return
to:@return
do10: scope:[do10] from main main::@1
[11] phi()
to:do10::@1
do10::@1: scope:[do10] from do10 do10::@1
[12] (byte) do10::i#2 ← phi( do10/(byte/signed byte/word/signed word/dword/signed dword) 0 do10::@1/(byte) do10::i#1 )
[13] call *((const void()*) main::f#0)
[14] (byte) do10::i#1 ← ++ (byte) do10::i#2
[15] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1
to:do10::@return
do10::@return: scope:[do10] from do10::@1
[16] return
to:@return
hello: scope:[hello] from
[17] phi()
to:hello::@1
hello::@1: scope:[hello] from hello hello::@1
[18] (byte) idx#3 ← phi( hello/(byte) idx#0 hello::@1/(byte) idx#1 )
[18] (byte) hello::i#2 ← phi( hello/(byte/signed byte/word/signed word/dword/signed dword) 0 hello::@1/(byte) hello::i#1 )
[19] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#10 + (byte) hello::i#2)
[20] (byte) idx#1 ← ++ (byte) idx#3
[21] (byte) hello::i#1 ← ++ (byte) hello::i#2
[22] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1
to:hello::@return
hello::@return: scope:[hello] from hello::@1
[23] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(void()) do10((void()*) do10::fn)
(void()*) do10::fn
(byte) do10::i
(byte) do10::i#1 16.5
(byte) do10::i#2 11.0
(void()) hello()
(byte) hello::i
(byte) hello::i#1 16.5
(byte) hello::i#2 11.0
(byte) idx
(byte) idx#0 4.0
(byte) idx#1 7.333333333333333
(byte) idx#3 17.5
(void()) main()
(void()*) main::f
(byte*) msg
(byte*) msg#0 20.0
(byte*) msg#1 20.0
(byte*) msg#10 4.0
(byte[]) msg1
(byte[]) msg2
Initial phi equivalence classes
[ do10::i#2 do10::i#1 ]
[ hello::i#2 hello::i#1 ]
[ idx#3 idx#0 idx#1 ]
Added variable msg#10 to zero page equivalence class [ msg#10 ]
Added variable msg#0 to zero page equivalence class [ msg#0 ]
Added variable msg#1 to zero page equivalence class [ msg#1 ]
Complete equivalence classes
[ do10::i#2 do10::i#1 ]
[ hello::i#2 hello::i#1 ]
[ idx#3 idx#0 idx#1 ]
[ msg#10 ]
[ msg#0 ]
[ msg#1 ]
Allocated zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Allocated zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Allocated zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
Allocated zp ZP_WORD:5 [ msg#10 ]
Allocated zp ZP_WORD:7 [ msg#0 ]
Allocated zp ZP_WORD:9 [ msg#1 ]
INITIAL ASM
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label msg = 7
.label msg_1 = 9
.label idx = 4
.label msg_10 = 5
//SEG3 @begin
bbegin:
jmp b1
//SEG4 @1
b1:
//SEG5 [1] (byte*) msg#10 ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta msg_10
lda #>0
sta msg_10+1
//SEG6 [2] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- vbuz1=vbuc1
lda #0
sta idx
//SEG7 [3] phi from @1 to @2 [phi:@1->@2]
b2_from_b1:
jmp b2
//SEG8 @2
b2:
//SEG9 [4] call main
jsr main
//SEG10 [5] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend
//SEG11 @end
bend:
//SEG12 main
main: {
.label f = hello
//SEG13 [6] (byte*) msg#0 ← (const byte[]) msg1#0 -- pbuz1=pbuc1
lda #<msg1
sta msg
lda #>msg1
sta msg+1
//SEG14 [7] call do10
//SEG15 [11] phi from main to do10 [phi:main->do10]
do10_from_main:
jsr do10
jmp b1
//SEG16 main::@1
b1:
//SEG17 [8] (byte*) msg#1 ← (const byte[]) msg2#0 -- pbuz1=pbuc1
lda #<msg2
sta msg_1
lda #>msg2
sta msg_1+1
//SEG18 [9] call do10
//SEG19 [11] phi from main::@1 to do10 [phi:main::@1->do10]
do10_from_b1:
jsr do10
jmp breturn
//SEG20 main::@return
breturn:
//SEG21 [10] return
rts
}
//SEG22 do10
do10: {
.label i = 2
//SEG23 [12] phi from do10 to do10::@1 [phi:do10->do10::@1]
b1_from_do10:
//SEG24 [12] phi (byte) do10::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG25 [12] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
b1_from_b1:
//SEG26 [12] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy
jmp b1
//SEG27 do10::@1
b1:
//SEG28 [13] call *((const void()*) main::f#0)
jsr main.f
//SEG29 [14] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG30 [15] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$a
cmp i
bne b1_from_b1
jmp breturn
//SEG31 do10::@return
breturn:
//SEG32 [16] return
rts
}
//SEG33 hello
hello: {
.label i = 3
//SEG34 [18] phi from hello to hello::@1 [phi:hello->hello::@1]
b1_from_hello:
//SEG35 [18] phi (byte) idx#3 = (byte) idx#0 [phi:hello->hello::@1#0] -- register_copy
//SEG36 [18] phi (byte) hello::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:hello->hello::@1#1] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG37 [18] phi from hello::@1 to hello::@1 [phi:hello::@1->hello::@1]
b1_from_b1:
//SEG38 [18] phi (byte) idx#3 = (byte) idx#1 [phi:hello::@1->hello::@1#0] -- register_copy
//SEG39 [18] phi (byte) hello::i#2 = (byte) hello::i#1 [phi:hello::@1->hello::@1#1] -- register_copy
jmp b1
//SEG40 hello::@1
b1:
//SEG41 [19] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#10 + (byte) hello::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz3
ldx idx
ldy i
lda (msg_10),y
sta SCREEN,x
//SEG42 [20] (byte) idx#1 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz1
inc idx
//SEG43 [21] (byte) hello::i#1 ← ++ (byte) hello::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG44 [22] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 -- pbuz1_derefidx_vbuz2_neq_vbuc1_then_la1
ldy i
lda (msg_10),y
cmp #'@'
bne b1_from_b1
jmp breturn
//SEG45 hello::@return
breturn:
//SEG46 [23] return
rts
}
msg1: .text "hello @"
msg2: .text "world @"
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [1] (byte*) msg#10 ← (byte*) 0 [ ] ( ) always clobbers reg byte a
Statement [2] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( ) always clobbers reg byte a
Statement [6] (byte*) msg#0 ← (const byte[]) msg1#0 [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [8] (byte*) msg#1 ← (const byte[]) msg2#0 [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [13] call *((const void()*) main::f#0) [ do10::i#2 ] ( main:4::do10:7 [ do10::i#2 ] main:4::do10:9 [ do10::i#2 ] ) always clobbers reg byte a reg byte x reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Removing always clobbered register reg byte x as potential for zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Statement [15] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 [ do10::i#1 ] ( main:4::do10:7 [ do10::i#1 ] main:4::do10:9 [ do10::i#1 ] ) always clobbers reg byte a
Statement [19] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#10 + (byte) hello::i#2) [ msg#10 hello::i#2 idx#3 ] ( [ msg#10 hello::i#2 idx#3 ] ) always clobbers reg byte a reg byte x
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Removing always clobbered register reg byte x as potential for zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Statement [22] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 [ msg#10 hello::i#1 idx#1 ] ( [ msg#10 hello::i#1 idx#1 ] ) always clobbers reg byte a
Statement [1] (byte*) msg#10 ← (byte*) 0 [ ] ( ) always clobbers reg byte a
Statement [2] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( ) always clobbers reg byte a
Statement [6] (byte*) msg#0 ← (const byte[]) msg1#0 [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [8] (byte*) msg#1 ← (const byte[]) msg2#0 [ ] ( main:4 [ ] ) always clobbers reg byte a
Statement [13] call *((const void()*) main::f#0) [ do10::i#2 ] ( main:4::do10:7 [ do10::i#2 ] main:4::do10:9 [ do10::i#2 ] ) always clobbers reg byte a reg byte x reg byte y
Statement [15] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 [ do10::i#1 ] ( main:4::do10:7 [ do10::i#1 ] main:4::do10:9 [ do10::i#1 ] ) always clobbers reg byte a
Statement [19] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#10 + (byte) hello::i#2) [ msg#10 hello::i#2 idx#3 ] ( [ msg#10 hello::i#2 idx#3 ] ) always clobbers reg byte a reg byte x
Statement [22] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 [ msg#10 hello::i#1 idx#1 ] ( [ msg#10 hello::i#1 idx#1 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ] : zp ZP_BYTE:2 ,
Potential registers zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ] : zp ZP_BYTE:3 , reg byte y ,
Potential registers zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ] : zp ZP_BYTE:4 ,
Potential registers zp ZP_WORD:5 [ msg#10 ] : zp ZP_WORD:5 ,
Potential registers zp ZP_WORD:7 [ msg#0 ] : zp ZP_WORD:7 ,
Potential registers zp ZP_WORD:9 [ msg#1 ] : zp ZP_WORD:9 ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 28.83: zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ] 20: zp ZP_WORD:7 [ msg#0 ] 20: zp ZP_WORD:9 [ msg#1 ] 4: zp ZP_WORD:5 [ msg#10 ]
Uplift Scope [do10] 27.5: zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Uplift Scope [hello] 27.5: zp ZP_BYTE:3 [ hello::i#2 hello::i#1 ]
Uplift Scope [main]
Uplifting [] best 973 combination zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ] zp ZP_WORD:7 [ msg#0 ] zp ZP_WORD:9 [ msg#1 ] zp ZP_WORD:5 [ msg#10 ]
Uplifting [do10] best 973 combination zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Uplifting [hello] best 853 combination reg byte y [ hello::i#2 hello::i#1 ]
Uplifting [main] best 853 combination
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
Uplifting [] best 853 combination zp ZP_BYTE:4 [ idx#3 idx#0 idx#1 ]
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Uplifting [do10] best 853 combination zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
Coalescing zero page register [ zp ZP_WORD:5 [ msg#10 ] ] with [ zp ZP_WORD:7 [ msg#0 ] ]
Coalescing zero page register [ zp ZP_WORD:5 [ msg#10 msg#0 ] ] with [ zp ZP_WORD:9 [ msg#1 ] ]
Allocated (was zp ZP_BYTE:4) zp ZP_BYTE:3 [ idx#3 idx#0 idx#1 ]
Allocated (was zp ZP_WORD:5) zp ZP_WORD:4 [ msg#10 msg#0 msg#1 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label msg = 4
.label idx = 3
//SEG3 @begin
bbegin:
jmp b1
//SEG4 @1
b1:
//SEG5 [1] (byte*) msg#10 ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta msg
lda #>0
sta msg+1
//SEG6 [2] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- vbuz1=vbuc1
lda #0
sta idx
//SEG7 [3] phi from @1 to @2 [phi:@1->@2]
b2_from_b1:
jmp b2
//SEG8 @2
b2:
//SEG9 [4] call main
jsr main
//SEG10 [5] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend
//SEG11 @end
bend:
//SEG12 main
main: {
.label f = hello
//SEG13 [6] (byte*) msg#0 ← (const byte[]) msg1#0 -- pbuz1=pbuc1
lda #<msg1
sta msg
lda #>msg1
sta msg+1
//SEG14 [7] call do10
//SEG15 [11] phi from main to do10 [phi:main->do10]
do10_from_main:
jsr do10
jmp b1
//SEG16 main::@1
b1:
//SEG17 [8] (byte*) msg#1 ← (const byte[]) msg2#0 -- pbuz1=pbuc1
lda #<msg2
sta msg
lda #>msg2
sta msg+1
//SEG18 [9] call do10
//SEG19 [11] phi from main::@1 to do10 [phi:main::@1->do10]
do10_from_b1:
jsr do10
jmp breturn
//SEG20 main::@return
breturn:
//SEG21 [10] return
rts
}
//SEG22 do10
do10: {
.label i = 2
//SEG23 [12] phi from do10 to do10::@1 [phi:do10->do10::@1]
b1_from_do10:
//SEG24 [12] phi (byte) do10::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1
lda #0
sta i
jmp b1
//SEG25 [12] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
b1_from_b1:
//SEG26 [12] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy
jmp b1
//SEG27 do10::@1
b1:
//SEG28 [13] call *((const void()*) main::f#0)
jsr main.f
//SEG29 [14] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG30 [15] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$a
cmp i
bne b1_from_b1
jmp breturn
//SEG31 do10::@return
breturn:
//SEG32 [16] return
rts
}
//SEG33 hello
hello: {
//SEG34 [18] phi from hello to hello::@1 [phi:hello->hello::@1]
b1_from_hello:
//SEG35 [18] phi (byte) idx#3 = (byte) idx#0 [phi:hello->hello::@1#0] -- register_copy
//SEG36 [18] phi (byte) hello::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:hello->hello::@1#1] -- vbuyy=vbuc1
ldy #0
jmp b1
//SEG37 [18] phi from hello::@1 to hello::@1 [phi:hello::@1->hello::@1]
b1_from_b1:
//SEG38 [18] phi (byte) idx#3 = (byte) idx#1 [phi:hello::@1->hello::@1#0] -- register_copy
//SEG39 [18] phi (byte) hello::i#2 = (byte) hello::i#1 [phi:hello::@1->hello::@1#1] -- register_copy
jmp b1
//SEG40 hello::@1
b1:
//SEG41 [19] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#10 + (byte) hello::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuyy
lda (msg),y
ldx idx
sta SCREEN,x
//SEG42 [20] (byte) idx#1 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz1
inc idx
//SEG43 [21] (byte) hello::i#1 ← ++ (byte) hello::i#2 -- vbuyy=_inc_vbuyy
iny
//SEG44 [22] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 -- pbuz1_derefidx_vbuyy_neq_vbuc1_then_la1
lda (msg),y
cmp #'@'
bne b1_from_b1
jmp breturn
//SEG45 hello::@return
breturn:
//SEG46 [23] return
rts
}
msg1: .text "hello @"
msg2: .text "world @"
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp breturn
Removing instruction jmp b1
Removing instruction jmp breturn
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda #>0
Removing instruction lda #0
Succesful ASM optimization Pass5UnnecesaryLoadElimination
Replacing label b1_from_b1 with b1
Replacing label b1_from_b1 with b1
Removing instruction b1:
Removing instruction b2_from_b1:
Removing instruction bend_from_b2:
Removing instruction b1_from_b1:
Removing instruction b1_from_b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction b2:
Removing instruction bend:
Removing instruction do10_from_main:
Removing instruction b1:
Removing instruction do10_from_b1:
Removing instruction breturn:
Removing instruction b1_from_do10:
Removing instruction breturn:
Removing instruction b1_from_hello:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b1
Removing instruction jmp b1
Succesful ASM optimization Pass5NextJumpElimination
FINAL SYMBOL TABLE
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(void()) do10((void()*) do10::fn)
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(byte) do10::i
(byte) do10::i#1 i zp ZP_BYTE:2 16.5
(byte) do10::i#2 i zp ZP_BYTE:2 11.0
(void()) hello()
(label) hello::@1
(label) hello::@return
(byte) hello::i
(byte) hello::i#1 reg byte y 16.5
(byte) hello::i#2 reg byte y 11.0
(byte) idx
(byte) idx#0 idx zp ZP_BYTE:3 4.0
(byte) idx#1 idx zp ZP_BYTE:3 7.333333333333333
(byte) idx#3 idx zp ZP_BYTE:3 17.5
(void()) main()
(label) main::@1
(label) main::@return
(void()*) main::f
(const void()*) main::f#0 f = &(void()) hello()
(byte*) msg
(byte*) msg#0 msg zp ZP_WORD:4 20.0
(byte*) msg#1 msg zp ZP_WORD:4 20.0
(byte*) msg#10 msg zp ZP_WORD:4 4.0
(byte[]) msg1
(const byte[]) msg1#0 msg1 = (string) "hello @"
(byte[]) msg2
(const byte[]) msg2#0 msg2 = (string) "world @"
zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
reg byte y [ hello::i#2 hello::i#1 ]
zp ZP_BYTE:3 [ idx#3 idx#0 idx#1 ]
zp ZP_WORD:4 [ msg#10 msg#0 msg#1 ]
FINAL ASSEMBLER
Score: 633
//SEG0 File Comments
// Tests calling into a function pointer with local variables
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label msg = 4
.label idx = 3
//SEG3 @begin
bbegin:
//SEG4 @1
//SEG5 [1] (byte*) msg#10 ← (byte*) 0 -- pbuz1=pbuc1
lda #<0
sta msg
sta msg+1
//SEG6 [2] (byte) idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 -- vbuz1=vbuc1
sta idx
//SEG7 [3] phi from @1 to @2 [phi:@1->@2]
//SEG8 @2
//SEG9 [4] call main
jsr main
rts
//SEG10 [5] phi from @2 to @end [phi:@2->@end]
//SEG11 @end
//SEG12 main
main: {
.label f = hello
//SEG13 [6] (byte*) msg#0 ← (const byte[]) msg1#0 -- pbuz1=pbuc1
lda #<msg1
sta msg
lda #>msg1
sta msg+1
//SEG14 [7] call do10
//SEG15 [11] phi from main to do10 [phi:main->do10]
jsr do10
//SEG16 main::@1
//SEG17 [8] (byte*) msg#1 ← (const byte[]) msg2#0 -- pbuz1=pbuc1
lda #<msg2
sta msg
lda #>msg2
sta msg+1
//SEG18 [9] call do10
//SEG19 [11] phi from main::@1 to do10 [phi:main::@1->do10]
jsr do10
//SEG20 main::@return
//SEG21 [10] return
rts
}
//SEG22 do10
do10: {
.label i = 2
//SEG23 [12] phi from do10 to do10::@1 [phi:do10->do10::@1]
//SEG24 [12] phi (byte) do10::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:do10->do10::@1#0] -- vbuz1=vbuc1
lda #0
sta i
//SEG25 [12] phi from do10::@1 to do10::@1 [phi:do10::@1->do10::@1]
//SEG26 [12] phi (byte) do10::i#2 = (byte) do10::i#1 [phi:do10::@1->do10::@1#0] -- register_copy
//SEG27 do10::@1
b1:
//SEG28 [13] call *((const void()*) main::f#0)
jsr main.f
//SEG29 [14] (byte) do10::i#1 ← ++ (byte) do10::i#2 -- vbuz1=_inc_vbuz1
inc i
//SEG30 [15] if((byte) do10::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $a) goto do10::@1 -- vbuz1_neq_vbuc1_then_la1
lda #$a
cmp i
bne b1
//SEG31 do10::@return
//SEG32 [16] return
rts
}
//SEG33 hello
hello: {
//SEG34 [18] phi from hello to hello::@1 [phi:hello->hello::@1]
//SEG35 [18] phi (byte) idx#3 = (byte) idx#0 [phi:hello->hello::@1#0] -- register_copy
//SEG36 [18] phi (byte) hello::i#2 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:hello->hello::@1#1] -- vbuyy=vbuc1
ldy #0
//SEG37 [18] phi from hello::@1 to hello::@1 [phi:hello::@1->hello::@1]
//SEG38 [18] phi (byte) idx#3 = (byte) idx#1 [phi:hello::@1->hello::@1#0] -- register_copy
//SEG39 [18] phi (byte) hello::i#2 = (byte) hello::i#1 [phi:hello::@1->hello::@1#1] -- register_copy
//SEG40 hello::@1
b1:
//SEG41 [19] *((const byte*) SCREEN#0 + (byte) idx#3) ← *((byte*) msg#10 + (byte) hello::i#2) -- pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuyy
lda (msg),y
ldx idx
sta SCREEN,x
//SEG42 [20] (byte) idx#1 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz1
inc idx
//SEG43 [21] (byte) hello::i#1 ← ++ (byte) hello::i#2 -- vbuyy=_inc_vbuyy
iny
//SEG44 [22] if(*((byte*) msg#10 + (byte) hello::i#1)!=(byte) '@') goto hello::@1 -- pbuz1_derefidx_vbuyy_neq_vbuc1_then_la1
lda (msg),y
cmp #'@'
bne b1
//SEG45 hello::@return
//SEG46 [23] return
rts
}
msg1: .text "hello @"
msg2: .text "world @"

@ -0,0 +1,41 @@
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
(void()) do10((void()*) do10::fn)
(label) do10::@1
(label) do10::@return
(void()*) do10::fn
(byte) do10::i
(byte) do10::i#1 i zp ZP_BYTE:2 16.5
(byte) do10::i#2 i zp ZP_BYTE:2 11.0
(void()) hello()
(label) hello::@1
(label) hello::@return
(byte) hello::i
(byte) hello::i#1 reg byte y 16.5
(byte) hello::i#2 reg byte y 11.0
(byte) idx
(byte) idx#0 idx zp ZP_BYTE:3 4.0
(byte) idx#1 idx zp ZP_BYTE:3 7.333333333333333
(byte) idx#3 idx zp ZP_BYTE:3 17.5
(void()) main()
(label) main::@1
(label) main::@return
(void()*) main::f
(const void()*) main::f#0 f = &(void()) hello()
(byte*) msg
(byte*) msg#0 msg zp ZP_WORD:4 20.0
(byte*) msg#1 msg zp ZP_WORD:4 20.0
(byte*) msg#10 msg zp ZP_WORD:4 4.0
(byte[]) msg1
(const byte[]) msg1#0 msg1 = (string) "hello @"
(byte[]) msg2
(const byte[]) msg2#0 msg2 = (string) "world @"
zp ZP_BYTE:2 [ do10::i#2 do10::i#1 ]
reg byte y [ hello::i#2 hello::i#1 ]
zp ZP_BYTE:3 [ idx#3 idx#0 idx#1 ]
zp ZP_WORD:4 [ msg#10 msg#0 msg#1 ]

@ -139,6 +139,7 @@ fn1: {
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] call *((const void()*) main::f#0) [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte x reg byte y
REGISTER UPLIFT SCOPES
Uplift Scope [main]

@ -7,6 +7,7 @@ bbegin:
lda #$c
sta x
jsr main
rts
main: {
b1:
inc x

@ -280,6 +280,8 @@ Removing instruction bend:
Removing instruction b2:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
@ -299,7 +301,7 @@ zp ZP_BYTE:2 [ x#5 x#0 x#1 x#2 ]
FINAL ASSEMBLER
Score: 147
Score: 153
//SEG0 File Comments
// Illustrates a problem where volatiles with initializers are initialized outside the main()-routine
@ -319,6 +321,7 @@ bbegin:
//SEG7 [2] call main
//SEG8 [4] phi from @1 to main [phi:@1->main]
jsr main
rts
//SEG9 [3] phi from @1 to @end [phi:@1->@end]
//SEG10 @end
//SEG11 main

@ -12,6 +12,7 @@ bbegin:
lda #8
sta col2
jsr main
rts
main: {
lda #<irq
sta KERNEL_IRQ

@ -334,6 +334,8 @@ Removing instruction bend:
Removing instruction breturn:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
@ -359,7 +361,7 @@ zp ZP_BYTE:3 [ col2#0 col2#1 ]
FINAL ASSEMBLER
Score: 61
Score: 67
//SEG0 File Comments
// Illustrates problem where volatiles reuse the same ZP addresses for multiple overlapping volatiles
@ -384,6 +386,7 @@ bbegin:
//SEG7 @1
//SEG8 [3] call main
jsr main
rts
//SEG9 [4] phi from @1 to @end [phi:@1->@end]
//SEG10 @end
//SEG11 main

@ -10,6 +10,7 @@ bbegin:
lda #0
sta col1
jsr main
rts
main: {
.label y = 2
lda #<irq

@ -647,6 +647,8 @@ Skipping double jump to b1 in bne b6
Succesful ASM optimization Pass5DoubleJumpElimination
Relabelling long label b1_from_b5 to b4
Succesful ASM optimization Pass5RelabelLongLabels
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b2
Removing instruction jmp b3
Succesful ASM optimization Pass5NextJumpElimination
@ -697,7 +699,7 @@ reg byte a [ main::$1 ]
FINAL ASSEMBLER
Score: 223698
Score: 223704
//SEG0 File Comments
// Illustrates problem where volatiles reuse ZP addresses of other variables
@ -719,6 +721,7 @@ bbegin:
//SEG6 @1
//SEG7 [2] call main
jsr main
rts
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main

@ -25,6 +25,7 @@ bbegin:
lda #0
sta irq_idx
jsr main
rts
main: {
sei
// Disable CIA 1 Timer IRQ

@ -1115,9 +1115,11 @@ Removing instruction b6:
Succesful ASM optimization Pass5UnusedLabelElimination
Skipping double jump to $ea81 in bcs breturn
Succesful ASM optimization Pass5DoubleJumpElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Fixing long branch [67] bcs $ea81 to bcc
Fixing long branch [68] bcs $ea81 to bcc
FINAL SYMBOL TABLE
(label) @1
@ -1249,7 +1251,7 @@ reg byte x [ table_driven_irq::val#0 ]
FINAL ASSEMBLER
Score: 598
Score: 604
//SEG0 File Comments
// Test interrupt routine using a variable between calls (irq_idx)
@ -1287,6 +1289,7 @@ bbegin:
//SEG7 @2
//SEG8 [3] call main
jsr main
rts
//SEG9 [4] phi from @2 to @end [phi:@2->@end]
//SEG10 @end
//SEG11 main

@ -17,6 +17,7 @@ bbegin:
lda #0
sta framedone
jsr main
rts
main: {
sei
// Disable CIA 1 Timer IRQ

@ -537,6 +537,8 @@ Removing instruction b2:
Removing instruction b2:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
FINAL SYMBOL TABLE
(label) @1
@ -577,7 +579,7 @@ zp ZP_BOOL:2 [ framedone#11 framedone#0 framedone#3 ]
FINAL ASSEMBLER
Score: 1022
Score: 1028
//SEG0 File Comments
// Illustrates a problem where a volatile bool modified at the end of an IRQ is not stored properly
@ -607,6 +609,7 @@ bbegin:
//SEG7 @2
//SEG8 [3] call main
jsr main
rts
//SEG9 [4] phi from @2 to @end [phi:@2->@end]
//SEG10 @end
//SEG11 main

@ -9,6 +9,7 @@ bbegin:
lda #0
sta col
jsr main
rts
main: {
lda #<irq
sta KERNEL_IRQ

@ -432,13 +432,15 @@ Skipping double jump to $ea81 in beq breturn
Succesful ASM optimization Pass5DoubleJumpElimination
Relabelling long label b1_from_b3 to b1
Succesful ASM optimization Pass5RelabelLongLabels
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b2
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Fixing long branch [30] beq $ea81 to bne
Fixing long branch [31] beq $ea81 to bne
FINAL SYMBOL TABLE
(label) @1
@ -465,7 +467,7 @@ zp ZP_BYTE:2 [ col#12 col#0 col#1 col#3 ]
FINAL ASSEMBLER
Score: 882
Score: 888
//SEG0 File Comments
// Tests that long branch fixing works with interrupt exits (to $ea81)
@ -486,6 +488,7 @@ bbegin:
//SEG6 @1
//SEG7 [2] call main
jsr main
rts
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main

@ -57,6 +57,7 @@ bbegin:
lda #1
sta framedone
jsr main
rts
main: {
sei
jsr init

@ -4274,6 +4274,8 @@ Removing instruction b5:
Removing instruction b3:
Removing instruction b4:
Succesful ASM optimization Pass5UnusedLabelElimination
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b4
Removing instruction jmp b1
Removing instruction jmp plexFreePrepare1_b1
@ -4585,7 +4587,7 @@ reg byte x [ plexShowSprite::$6 ]
FINAL ASSEMBLER
Score: 47272
Score: 47278
//SEG0 File Comments
// A simple usage of the flexible sprite multiplexer routine
@ -4664,6 +4666,7 @@ bbegin:
//SEG16 @5
//SEG17 [9] call main
jsr main
rts
//SEG18 [10] phi from @5 to @end [phi:@5->@end]
//SEG19 @end
//SEG20 main

@ -10,6 +10,7 @@ bbegin:
lda #0
sta col
jsr main
rts
main: {
lda #<irq
sta KERNEL_IRQ

@ -461,6 +461,8 @@ Skipping double jump to $ea81 in jmp breturn
Succesful ASM optimization Pass5DoubleJumpElimination
Relabelling long label b1_from_b3 to b1
Succesful ASM optimization Pass5RelabelLongLabels
Adding RTS to root block
Succesful ASM optimization Pass5AddMainRts
Removing instruction jmp b2
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction lda col
@ -497,7 +499,7 @@ zp ZP_BYTE:2 [ col#14 col#0 col#1 col#4 col#3 ]
FINAL ASSEMBLER
Score: 889
Score: 895
//SEG0 File Comments
// Tests that volatile variables can be both read & written inside & outside interrupts
@ -519,6 +521,7 @@ bbegin:
//SEG6 @1
//SEG7 [2] call main
jsr main
rts
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main

@ -8,6 +8,7 @@ bbegin:
lda #0
sta col
jsr main
rts
main: {
lda #<irq
sta KERNEL_IRQ

@ -310,6 +310,8 @@ 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
@ -333,7 +335,7 @@ zp ZP_BYTE:2 [ col#2 col#0 col#1 ]
FINAL ASSEMBLER
Score: 117
Score: 123
//SEG0 File Comments
//SEG1 Basic Upstart
@ -353,6 +355,7 @@ bbegin:
//SEG6 @1
//SEG7 [2] call main
jsr main
rts
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
//SEG9 @end
//SEG10 main