mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-15 16:30:02 +00:00
Fixed problem where zeropage allocations inside IRQ and outside could overlap. Closes #154
This commit is contained in:
parent
c81147f60f
commit
7fcb6e525a
@ -7,6 +7,7 @@ import dk.camelot64.kickc.model.StatementSequence;
|
||||
import dk.camelot64.kickc.model.statements.StatementCall;
|
||||
import dk.camelot64.kickc.model.statements.StatementSource;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.parser.KickCLexer;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
import dk.camelot64.kickc.passes.*;
|
||||
@ -126,7 +127,7 @@ public class Compiler {
|
||||
loadAndParseFile(fileName, program, currentPath.toPath());
|
||||
|
||||
StatementSequence sequence = program.getStatementSequence();
|
||||
sequence.addStatement(new StatementCall(null, "main", new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
|
||||
sequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
|
||||
program.setStatementSequence(sequence);
|
||||
|
||||
pass1GenerateSSA();
|
||||
|
@ -107,8 +107,6 @@ public class CallGraph {
|
||||
* This includes the recursive closure of calls (ie. sub-calls and their sub-calls).
|
||||
* @param scopeRef The scope (procedure/root) to examine
|
||||
* @param found The scopes already found
|
||||
*
|
||||
* @return All scopes called in the closure of calls
|
||||
*/
|
||||
private void addRecursiveCalls(ScopeRef scopeRef, Collection<ScopeRef> found) {
|
||||
if(found.contains(scopeRef)) {
|
||||
@ -124,8 +122,6 @@ public class CallGraph {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
@ -153,6 +149,55 @@ public class CallGraph {
|
||||
return callers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all procedures containing calls of a specific procedure
|
||||
*
|
||||
* @param label The label of the procedure
|
||||
* @return All calls
|
||||
*/
|
||||
public Collection<ScopeRef> getCallerProcs(ScopeRef label) {
|
||||
Collection<ScopeRef> callers = new ArrayList<>();
|
||||
for(CallBlock callBlock : callBlocks) {
|
||||
for(CallBlock.Call call : callBlock.getCalls()) {
|
||||
if(call.getProcedure().equals(label)) {
|
||||
callers.add(callBlock.getScopeLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
return callers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the closure of all procedures calling a specific scope.
|
||||
* This includes the recursive closure of callers (ie. callers and their callers).
|
||||
* @param scopeRef The scope (procedure/root) to examine
|
||||
* @return All scopes calling the passed scope (potentially through other callers)
|
||||
*/
|
||||
public Collection<ScopeRef> getRecursiveCallers(ScopeRef scopeRef) {
|
||||
ArrayList<ScopeRef> closure = new ArrayList<>();
|
||||
addRecursiveCallers(scopeRef, closure);
|
||||
return closure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the closure of all procedures calling a specific scope.
|
||||
* This includes the recursive closure of callers (ie. callers and their callers).
|
||||
* @param scopeRef The scope (procedure/root) to examine
|
||||
* @param found The scopes already found
|
||||
* */
|
||||
private void addRecursiveCallers(ScopeRef scopeRef, Collection<ScopeRef> found) {
|
||||
if(found.contains(scopeRef)) {
|
||||
// Recursion detected - stop here
|
||||
return;
|
||||
}
|
||||
found.add(scopeRef);
|
||||
Collection<ScopeRef> callerProcs = getCallerProcs(scopeRef);
|
||||
for(ScopeRef callerProc : callerProcs) {
|
||||
addRecursiveCallers(callerProc, found);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A block in the call graph, matching a scope in the program.
|
||||
*/
|
||||
|
@ -8,6 +8,7 @@ import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.passes.Pass2ConstantIdentification;
|
||||
|
||||
@ -172,14 +173,13 @@ public class ControlFlowGraph {
|
||||
public ControlFlowBlock getMainBlock() {
|
||||
for(ControlFlowBlock block : getAllBlocks()) {
|
||||
LabelRef label = block.getLabel();
|
||||
if(label.getFullName().equals("main")) {
|
||||
if(label.getFullName().equals(SymbolRef.MAIN_PROC_NAME)) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all blocks that are program entry points. This is the main-block and any blocks referenced by the address-off operator (&)
|
||||
* @param program The program
|
||||
|
@ -251,7 +251,7 @@ public class Pass1GenerateSingleStaticAssignmentForm extends Pass1Base {
|
||||
if(symbol instanceof Procedure) {
|
||||
if(((Procedure) symbol).getInterruptType()!=null) {
|
||||
// Find all root-level predecessors to the main block
|
||||
ControlFlowBlock mainBlock = getGraph().getBlock(new LabelRef("main"));
|
||||
ControlFlowBlock mainBlock = getGraph().getBlock(new LabelRef(SymbolRef.MAIN_PROC_NAME));
|
||||
List<ControlFlowBlock> mainPredecessors = getGraph().getPredecessors(mainBlock);
|
||||
for(ControlFlowBlock mainPredecessor : mainPredecessors) {
|
||||
if(mainPredecessor.getScope().equals(ScopeRef.ROOT)) {
|
||||
|
@ -1,10 +1,15 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.symbols.ProgramScope;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
import dk.camelot64.kickc.model.symbols.VariableUnversioned;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@ -21,9 +26,10 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
||||
public void coalesce() {
|
||||
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
|
||||
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
|
||||
Collection<ScopeRef> threads = getThreadHeads(getSymbols());
|
||||
boolean change;
|
||||
do {
|
||||
change = coalesce(liveRangeEquivalenceClassSet, unknownFragments);
|
||||
change = coalesce(liveRangeEquivalenceClassSet, threads, unknownFragments);
|
||||
} while(change);
|
||||
|
||||
if(unknownFragments.size() > 0) {
|
||||
@ -35,6 +41,26 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all functions that represents a separate thread in the program.
|
||||
* Each interrupt function and the main() function are threads.
|
||||
*
|
||||
* @return The threads.
|
||||
*/
|
||||
public static Collection<ScopeRef> getThreadHeads(ProgramScope programScope) {
|
||||
ArrayList<ScopeRef> threadHeads = new ArrayList<>();
|
||||
Collection<Procedure> procedures = programScope.getAllProcedures(true);
|
||||
for(Procedure procedure : procedures) {
|
||||
if(procedure.getInterruptType() != null) {
|
||||
threadHeads.add(procedure.getRef());
|
||||
}
|
||||
if(procedure.getFullName().equals(SymbolRef.MAIN_PROC_NAME)) {
|
||||
threadHeads.add(procedure.getRef());
|
||||
}
|
||||
}
|
||||
return threadHeads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find two equivalence classes that can be coalesced into one - and perform the coalescence.
|
||||
*
|
||||
@ -42,11 +68,11 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
||||
* @param unknownFragments Receives information about any unknown fragments encountered during ASM generation
|
||||
* @return true if any classes were coalesced. False otherwise.
|
||||
*/
|
||||
private boolean coalesce(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet, Set<String> unknownFragments) {
|
||||
private boolean coalesce(LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet, Collection<ScopeRef> threadHeads, Set<String> unknownFragments) {
|
||||
for(LiveRangeEquivalenceClass thisEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
|
||||
for(LiveRangeEquivalenceClass otherEquivalenceClass : liveRangeEquivalenceClassSet.getEquivalenceClasses()) {
|
||||
if(!thisEquivalenceClass.equals(otherEquivalenceClass)) {
|
||||
if(canCoalesce(thisEquivalenceClass, otherEquivalenceClass, unknownFragments, getProgram())) {
|
||||
if(canCoalesce(thisEquivalenceClass, otherEquivalenceClass, threadHeads, unknownFragments, getProgram())) {
|
||||
getLog().append("Coalescing zero page register [ " + thisEquivalenceClass + " ] with [ " + otherEquivalenceClass + " ]");
|
||||
liveRangeEquivalenceClassSet.consolidate(thisEquivalenceClass, otherEquivalenceClass);
|
||||
// Reset the program register allocation
|
||||
@ -68,8 +94,56 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
||||
* @param program The program
|
||||
* @return True if the two equivalence classes can be coalesced into one without problems.
|
||||
*/
|
||||
public static boolean canCoalesce(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Set<String> unknownFragments, Program program) {
|
||||
return canCoalesceVolatile(ec1, ec2, program) && canCoalesceClobber(ec1, ec2, unknownFragments, program);
|
||||
static boolean canCoalesce(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Collection<ScopeRef> threadHeads, Set<String> unknownFragments, Program program) {
|
||||
return canCoalesceVolatile(ec1, ec2, program) && canCoalesceThreads(ec1, ec2, threadHeads, program) && canCoalesceClobber(ec1, ec2, unknownFragments, program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two live range equivalence classes can be coalesced without cross-thread clobber.
|
||||
* This is possible if they are both only called from the same thread head.
|
||||
*
|
||||
* @param ec1 One equivalence class
|
||||
* @param ec2 Another equivalence class
|
||||
* @param threadHeads The heads (in the call graph) from each thread in the program
|
||||
* @param program The program
|
||||
* @return True if the two equivalence classes can be coalesced into one without problems.
|
||||
*/
|
||||
private static boolean canCoalesceThreads(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Collection<ScopeRef> threadHeads, Program program) {
|
||||
CallGraph callGraph = program.getCallGraph();
|
||||
|
||||
Collection<ScopeRef> threads1 = getEquivalenceClassThreads(ec1, program, threadHeads, callGraph);
|
||||
Collection<ScopeRef> threads2 = getEquivalenceClassThreads(ec2, program, threadHeads, callGraph);
|
||||
|
||||
if(threads1.isEmpty() || threads2.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return threads1.equals(threads2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the threads for the variables in an equivalence class.
|
||||
*
|
||||
* @param equivalenceClass The equivalence class
|
||||
* @param program The program
|
||||
* @param threadHeads The threads (heads)
|
||||
* @param callGraph The call graph
|
||||
* @return All threads containing variables in the equivalence class.
|
||||
*/
|
||||
private static Collection<ScopeRef> getEquivalenceClassThreads(LiveRangeEquivalenceClass equivalenceClass, Program program, Collection<ScopeRef> threadHeads, CallGraph callGraph) {
|
||||
Collection<ScopeRef> threads = new ArrayList<>();
|
||||
for(VariableRef varRef : equivalenceClass.getVariables()) {
|
||||
Variable variable = program.getScope().getVariable(varRef);
|
||||
ScopeRef scopeRef = variable.getScope().getRef();
|
||||
Collection<ScopeRef> recursiveCallers = callGraph.getRecursiveCallers(scopeRef);
|
||||
for(ScopeRef threadHead : threadHeads) {
|
||||
if(recursiveCallers.contains(threadHead)) {
|
||||
if(!threads.contains(threadHead)) {
|
||||
threads.add(threadHead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return threads;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +170,8 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if any volatile varialbes prevents coalescing two equivalence classes
|
||||
* Determines if any volatile variables prevents coalescing two equivalence classes
|
||||
*
|
||||
* @param ec1 One equivalence class
|
||||
* @param ec2 Another equivalence class
|
||||
* @param program The program
|
||||
@ -107,7 +182,7 @@ public class Pass4ZeroPageCoalesce extends Pass2Base {
|
||||
if(ec1.hasVolatile(program) || ec2.hasVolatile(program)) {
|
||||
Variable baseVar1 = ec1.getSingleVariableBase(program);
|
||||
Variable baseVar2 = ec2.getSingleVariableBase(program);
|
||||
if(baseVar1==null || baseVar2==null) {
|
||||
if(baseVar1 == null || baseVar2 == null) {
|
||||
// One of the equivalence classes have different base variables inside
|
||||
return false;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.values.ScopeRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
|
||||
@ -19,6 +20,7 @@ public class Pass4ZeroPageCoalesceAssignment extends Pass2Base {
|
||||
public void coalesce() {
|
||||
CoalesceVarScores coalesceVarScores = new CoalesceVarScores(getProgram());
|
||||
LinkedHashSet<String> unknownFragments = new LinkedHashSet<>();
|
||||
Collection<ScopeRef> threadHeads = Pass4ZeroPageCoalesce.getThreadHeads(getSymbols());
|
||||
|
||||
boolean change;
|
||||
do {
|
||||
@ -28,7 +30,7 @@ public class Pass4ZeroPageCoalesceAssignment extends Pass2Base {
|
||||
List<LiveRangeEquivalenceClassCoalesceCandidate> coalesceCandidates =
|
||||
equivalenceClassScores.getCoalesceCandidates();
|
||||
for(LiveRangeEquivalenceClassCoalesceCandidate candidate : coalesceCandidates) {
|
||||
change |= attemptCoalesce(candidate, unknownFragments);
|
||||
change |= attemptCoalesce(candidate, threadHeads, unknownFragments);
|
||||
}
|
||||
} while(change);
|
||||
|
||||
@ -40,12 +42,12 @@ public class Pass4ZeroPageCoalesceAssignment extends Pass2Base {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean attemptCoalesce(LiveRangeEquivalenceClassCoalesceCandidate candidate, LinkedHashSet<String> unknownFragments) {
|
||||
private boolean attemptCoalesce(LiveRangeEquivalenceClassCoalesceCandidate candidate, Collection<ScopeRef> threadHeads, LinkedHashSet<String> unknownFragments) {
|
||||
LiveRangeEquivalenceClassSet liveRangeEquivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
|
||||
List<LiveRangeEquivalenceClass> equivalenceClasses = liveRangeEquivalenceClassSet.getEquivalenceClasses();
|
||||
if(equivalenceClasses.contains(candidate.getEc1()) && equivalenceClasses.contains(candidate.getEc2())) {
|
||||
// Both equivalence classes still exist
|
||||
if(Pass4ZeroPageCoalesce.canCoalesce(candidate.getEc1(), candidate.getEc2(), unknownFragments, getProgram())) {
|
||||
if(Pass4ZeroPageCoalesce.canCoalesce(candidate.getEc1(), candidate.getEc2(), threadHeads, unknownFragments, getProgram())) {
|
||||
getLog().append("Coalescing zero page register with common assignment [ " + candidate.getEc1() + " ] with [ " + candidate.getEc2()+ " ] - score: "+candidate.getScore());
|
||||
liveRangeEquivalenceClassSet.consolidate(candidate.getEc1(), candidate.getEc2());
|
||||
// Reset the program register allocation
|
||||
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.values.LabelRef;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -31,7 +32,7 @@ public class PassNDominatorsAnalysis extends Pass2SsaOptimization {
|
||||
for(ControlFlowBlock entryPointBlock : entryPointBlocks) {
|
||||
LabelRef firstBlock = entryPointBlock.getLabel();
|
||||
// Skip main-block, as it will be called by @begin anyways
|
||||
if(firstBlock.getFullName().equals("main")) continue;
|
||||
if(firstBlock.getFullName().equals(SymbolRef.MAIN_PROC_NAME)) continue;
|
||||
DominatorsBlock firstDominators = dominatorsGraph.addDominators(firstBlock);
|
||||
firstDominators.add(firstBlock);
|
||||
firstBlocks.add(firstBlock);
|
||||
|
@ -32,6 +32,11 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIrqLocalVarOverlap() throws IOException, URISyntaxException {
|
||||
compileAndCompare("irq-local-var-overlap-problem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplexerIrq() throws IOException, URISyntaxException {
|
||||
compileAndCompare("multiplexer-irq/simple-multiplexer-irq", 10);
|
||||
|
62
src/test/kc/irq-local-var-overlap-problem.kc
Normal file
62
src/test/kc/irq-local-var-overlap-problem.kc
Normal file
@ -0,0 +1,62 @@
|
||||
// Illustrates a problem where local variables inside an IRQ are assigned the same zeropage as a variable outside the IRQ
|
||||
|
||||
const void()** KERNEL_IRQ = $0314;
|
||||
const byte* RASTER = $d012;
|
||||
const byte* VIC_CONTROL = $d011;
|
||||
const byte* IRQ_STATUS = $d019;
|
||||
const byte* IRQ_ENABLE = $d01a;
|
||||
const byte IRQ_RASTER = %00000001;
|
||||
const byte* BGCOL = $d020;
|
||||
const byte* FGCOL = $d021;
|
||||
|
||||
const byte* CIA1_INTERRUPT = $dc0d;
|
||||
const byte CIA_INTERRUPT_CLEAR = $7f;
|
||||
|
||||
|
||||
void main() {
|
||||
asm { sei }
|
||||
// Disable CIA 1 Timer IRQ
|
||||
*CIA1_INTERRUPT = CIA_INTERRUPT_CLEAR;
|
||||
// Set raster line to $0fd
|
||||
*VIC_CONTROL &=$7f;
|
||||
*RASTER = $fd;
|
||||
// Enable Raster Interrupt
|
||||
*IRQ_ENABLE = IRQ_RASTER;
|
||||
// Set the IRQ routine
|
||||
*KERNEL_IRQ = &irq;
|
||||
asm { cli }
|
||||
while(true) {
|
||||
for( byte i: 0..10 )
|
||||
for( byte j: 0..10 )
|
||||
for( byte k: 0..10 ) {
|
||||
*FGCOL = i+j+k;
|
||||
sub_main();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interrupt(kernel_min) void irq() {
|
||||
(*BGCOL)++;
|
||||
for( byte i: 0..10 )
|
||||
for( byte j: 0..10 )
|
||||
for( byte k: 0..10 ) {
|
||||
*FGCOL = i+j+k;
|
||||
sub_irq();
|
||||
}
|
||||
*IRQ_STATUS = IRQ_RASTER;
|
||||
(*BGCOL)--;
|
||||
}
|
||||
|
||||
void sub_main() {
|
||||
for( byte i: 0..10 )
|
||||
for( byte j: 0..10 )
|
||||
for( byte k: 0..10 )
|
||||
*BGCOL = i+j+k;
|
||||
}
|
||||
|
||||
void sub_irq() {
|
||||
for( byte i: 0..10 )
|
||||
for( byte j: 0..10 )
|
||||
for( byte k: 0..10 )
|
||||
*BGCOL = i+j+k;
|
||||
}
|
158
src/test/ref/irq-local-var-overlap-problem.asm
Normal file
158
src/test/ref/irq-local-var-overlap-problem.asm
Normal file
@ -0,0 +1,158 @@
|
||||
// Illustrates a problem where local variables inside an IRQ are assigned the same zeropage as a variable outside the IRQ
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label KERNEL_IRQ = $314
|
||||
.label RASTER = $d012
|
||||
.label VIC_CONTROL = $d011
|
||||
.label IRQ_STATUS = $d019
|
||||
.label IRQ_ENABLE = $d01a
|
||||
.const IRQ_RASTER = 1
|
||||
.label BGCOL = $d020
|
||||
.label FGCOL = $d021
|
||||
.label CIA1_INTERRUPT = $dc0d
|
||||
.const CIA_INTERRUPT_CLEAR = $7f
|
||||
main: {
|
||||
.label k = 4
|
||||
.label j = 3
|
||||
.label i = 2
|
||||
sei
|
||||
// Disable CIA 1 Timer IRQ
|
||||
lda #CIA_INTERRUPT_CLEAR
|
||||
sta CIA1_INTERRUPT
|
||||
// Set raster line to $0fd
|
||||
lda #$7f
|
||||
and VIC_CONTROL
|
||||
sta VIC_CONTROL
|
||||
lda #$fd
|
||||
sta RASTER
|
||||
// Enable Raster Interrupt
|
||||
lda #IRQ_RASTER
|
||||
sta IRQ_ENABLE
|
||||
// Set the IRQ routine
|
||||
lda #<irq
|
||||
sta KERNEL_IRQ
|
||||
lda #>irq
|
||||
sta KERNEL_IRQ+1
|
||||
cli
|
||||
b1:
|
||||
lda #0
|
||||
sta i
|
||||
b4:
|
||||
lda #0
|
||||
sta j
|
||||
b5:
|
||||
lda #0
|
||||
sta k
|
||||
b6:
|
||||
lda i
|
||||
clc
|
||||
adc j
|
||||
clc
|
||||
adc k
|
||||
sta FGCOL
|
||||
jsr sub_main
|
||||
inc k
|
||||
lda #$b
|
||||
cmp k
|
||||
bne b6
|
||||
inc j
|
||||
cmp j
|
||||
bne b5
|
||||
inc i
|
||||
cmp i
|
||||
bne b4
|
||||
jmp b1
|
||||
}
|
||||
sub_main: {
|
||||
.label i = 5
|
||||
lda #0
|
||||
sta i
|
||||
b1:
|
||||
ldx #0
|
||||
b2:
|
||||
ldy #0
|
||||
b3:
|
||||
txa
|
||||
clc
|
||||
adc i
|
||||
sty $ff
|
||||
clc
|
||||
adc $ff
|
||||
sta BGCOL
|
||||
iny
|
||||
cpy #$b
|
||||
bne b3
|
||||
inx
|
||||
cpx #$b
|
||||
bne b2
|
||||
inc i
|
||||
lda #$b
|
||||
cmp i
|
||||
bne b1
|
||||
rts
|
||||
}
|
||||
irq: {
|
||||
.label k = 8
|
||||
.label j = 7
|
||||
.label i = 6
|
||||
inc BGCOL
|
||||
lda #0
|
||||
sta i
|
||||
b1:
|
||||
lda #0
|
||||
sta j
|
||||
b2:
|
||||
lda #0
|
||||
sta k
|
||||
b3:
|
||||
lda i
|
||||
clc
|
||||
adc j
|
||||
clc
|
||||
adc k
|
||||
sta FGCOL
|
||||
jsr sub_irq
|
||||
inc k
|
||||
lda #$b
|
||||
cmp k
|
||||
bne b3
|
||||
inc j
|
||||
cmp j
|
||||
bne b2
|
||||
inc i
|
||||
cmp i
|
||||
bne b1
|
||||
lda #IRQ_RASTER
|
||||
sta IRQ_STATUS
|
||||
dec BGCOL
|
||||
jmp $ea81
|
||||
}
|
||||
sub_irq: {
|
||||
.label i = 9
|
||||
lda #0
|
||||
sta i
|
||||
b1:
|
||||
ldx #0
|
||||
b2:
|
||||
ldy #0
|
||||
b3:
|
||||
txa
|
||||
clc
|
||||
adc i
|
||||
sty $ff
|
||||
clc
|
||||
adc $ff
|
||||
sta BGCOL
|
||||
iny
|
||||
cpy #$b
|
||||
bne b3
|
||||
inx
|
||||
cpx #$b
|
||||
bne b2
|
||||
inc i
|
||||
lda #$b
|
||||
cmp i
|
||||
bne b1
|
||||
rts
|
||||
}
|
137
src/test/ref/irq-local-var-overlap-problem.cfg
Normal file
137
src/test/ref/irq-local-var-overlap-problem.cfg
Normal file
@ -0,0 +1,137 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@4
|
||||
@4: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @4
|
||||
[3] phi()
|
||||
main: scope:[main] from @4
|
||||
asm { sei }
|
||||
[5] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0
|
||||
[6] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f
|
||||
[7] *((const byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd
|
||||
[8] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0
|
||||
[9] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) irq()
|
||||
asm { cli }
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main main::@10 main::@14
|
||||
[11] (byte) main::i#7 ← phi( main::@14/(byte) main::i#1 main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@10/(byte/signed byte/word/signed word/dword/signed dword) 0 )
|
||||
to:main::@5
|
||||
main::@5: scope:[main] from main::@4 main::@9
|
||||
[12] (byte) main::j#5 ← phi( main::@4/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@9/(byte) main::j#1 )
|
||||
to:main::@6
|
||||
main::@6: scope:[main] from main::@13 main::@5
|
||||
[13] (byte) main::k#2 ← phi( main::@13/(byte) main::k#1 main::@5/(byte/signed byte/word/signed word/dword/signed dword) 0 )
|
||||
[14] (byte~) main::$1 ← (byte) main::i#7 + (byte) main::j#5
|
||||
[15] (byte~) main::$2 ← (byte~) main::$1 + (byte) main::k#2
|
||||
[16] *((const byte*) FGCOL#0) ← (byte~) main::$2
|
||||
[17] call sub_main
|
||||
to:main::@13
|
||||
main::@13: scope:[main] from main::@6
|
||||
[18] (byte) main::k#1 ← ++ (byte) main::k#2
|
||||
[19] if((byte) main::k#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto main::@6
|
||||
to:main::@9
|
||||
main::@9: scope:[main] from main::@13
|
||||
[20] (byte) main::j#1 ← ++ (byte) main::j#5
|
||||
[21] if((byte) main::j#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto main::@5
|
||||
to:main::@10
|
||||
main::@10: scope:[main] from main::@9
|
||||
[22] (byte) main::i#1 ← ++ (byte) main::i#7
|
||||
[23] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto main::@14
|
||||
to:main::@4
|
||||
main::@14: scope:[main] from main::@10
|
||||
[24] phi()
|
||||
to:main::@4
|
||||
sub_main: scope:[sub_main] from main::@6
|
||||
[25] phi()
|
||||
to:sub_main::@1
|
||||
sub_main::@1: scope:[sub_main] from sub_main sub_main::@5
|
||||
[26] (byte) sub_main::i#6 ← phi( sub_main/(byte/signed byte/word/signed word/dword/signed dword) 0 sub_main::@5/(byte) sub_main::i#1 )
|
||||
to:sub_main::@2
|
||||
sub_main::@2: scope:[sub_main] from sub_main::@1 sub_main::@4
|
||||
[27] (byte) sub_main::j#4 ← phi( sub_main::@1/(byte/signed byte/word/signed word/dword/signed dword) 0 sub_main::@4/(byte) sub_main::j#1 )
|
||||
to:sub_main::@3
|
||||
sub_main::@3: scope:[sub_main] from sub_main::@2 sub_main::@3
|
||||
[28] (byte) sub_main::k#2 ← phi( sub_main::@2/(byte/signed byte/word/signed word/dword/signed dword) 0 sub_main::@3/(byte) sub_main::k#1 )
|
||||
[29] (byte~) sub_main::$0 ← (byte) sub_main::i#6 + (byte) sub_main::j#4
|
||||
[30] (byte~) sub_main::$1 ← (byte~) sub_main::$0 + (byte) sub_main::k#2
|
||||
[31] *((const byte*) BGCOL#0) ← (byte~) sub_main::$1
|
||||
[32] (byte) sub_main::k#1 ← ++ (byte) sub_main::k#2
|
||||
[33] if((byte) sub_main::k#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto sub_main::@3
|
||||
to:sub_main::@4
|
||||
sub_main::@4: scope:[sub_main] from sub_main::@3
|
||||
[34] (byte) sub_main::j#1 ← ++ (byte) sub_main::j#4
|
||||
[35] if((byte) sub_main::j#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto sub_main::@2
|
||||
to:sub_main::@5
|
||||
sub_main::@5: scope:[sub_main] from sub_main::@4
|
||||
[36] (byte) sub_main::i#1 ← ++ (byte) sub_main::i#6
|
||||
[37] if((byte) sub_main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto sub_main::@1
|
||||
to:sub_main::@return
|
||||
sub_main::@return: scope:[sub_main] from sub_main::@5
|
||||
[38] return
|
||||
to:@return
|
||||
irq: scope:[irq] from
|
||||
[39] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0)
|
||||
to:irq::@1
|
||||
irq::@1: scope:[irq] from irq irq::@5
|
||||
[40] (byte) irq::i#7 ← phi( irq/(byte/signed byte/word/signed word/dword/signed dword) 0 irq::@5/(byte) irq::i#1 )
|
||||
to:irq::@2
|
||||
irq::@2: scope:[irq] from irq::@1 irq::@4
|
||||
[41] (byte) irq::j#4 ← phi( irq::@1/(byte/signed byte/word/signed word/dword/signed dword) 0 irq::@4/(byte) irq::j#1 )
|
||||
to:irq::@3
|
||||
irq::@3: scope:[irq] from irq::@2 irq::@7
|
||||
[42] (byte) irq::k#2 ← phi( irq::@2/(byte/signed byte/word/signed word/dword/signed dword) 0 irq::@7/(byte) irq::k#1 )
|
||||
[43] (byte~) irq::$0 ← (byte) irq::i#7 + (byte) irq::j#4
|
||||
[44] (byte~) irq::$1 ← (byte~) irq::$0 + (byte) irq::k#2
|
||||
[45] *((const byte*) FGCOL#0) ← (byte~) irq::$1
|
||||
[46] call sub_irq
|
||||
to:irq::@7
|
||||
irq::@7: scope:[irq] from irq::@3
|
||||
[47] (byte) irq::k#1 ← ++ (byte) irq::k#2
|
||||
[48] if((byte) irq::k#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto irq::@3
|
||||
to:irq::@4
|
||||
irq::@4: scope:[irq] from irq::@7
|
||||
[49] (byte) irq::j#1 ← ++ (byte) irq::j#4
|
||||
[50] if((byte) irq::j#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto irq::@2
|
||||
to:irq::@5
|
||||
irq::@5: scope:[irq] from irq::@4
|
||||
[51] (byte) irq::i#1 ← ++ (byte) irq::i#7
|
||||
[52] if((byte) irq::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto irq::@1
|
||||
to:irq::@6
|
||||
irq::@6: scope:[irq] from irq::@5
|
||||
[53] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0
|
||||
[54] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0)
|
||||
to:irq::@return
|
||||
irq::@return: scope:[irq] from irq::@6
|
||||
[55] return
|
||||
to:@return
|
||||
sub_irq: scope:[sub_irq] from irq::@3
|
||||
[56] phi()
|
||||
to:sub_irq::@1
|
||||
sub_irq::@1: scope:[sub_irq] from sub_irq sub_irq::@5
|
||||
[57] (byte) sub_irq::i#6 ← phi( sub_irq/(byte/signed byte/word/signed word/dword/signed dword) 0 sub_irq::@5/(byte) sub_irq::i#1 )
|
||||
to:sub_irq::@2
|
||||
sub_irq::@2: scope:[sub_irq] from sub_irq::@1 sub_irq::@4
|
||||
[58] (byte) sub_irq::j#4 ← phi( sub_irq::@1/(byte/signed byte/word/signed word/dword/signed dword) 0 sub_irq::@4/(byte) sub_irq::j#1 )
|
||||
to:sub_irq::@3
|
||||
sub_irq::@3: scope:[sub_irq] from sub_irq::@2 sub_irq::@3
|
||||
[59] (byte) sub_irq::k#2 ← phi( sub_irq::@2/(byte/signed byte/word/signed word/dword/signed dword) 0 sub_irq::@3/(byte) sub_irq::k#1 )
|
||||
[60] (byte~) sub_irq::$0 ← (byte) sub_irq::i#6 + (byte) sub_irq::j#4
|
||||
[61] (byte~) sub_irq::$1 ← (byte~) sub_irq::$0 + (byte) sub_irq::k#2
|
||||
[62] *((const byte*) BGCOL#0) ← (byte~) sub_irq::$1
|
||||
[63] (byte) sub_irq::k#1 ← ++ (byte) sub_irq::k#2
|
||||
[64] if((byte) sub_irq::k#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto sub_irq::@3
|
||||
to:sub_irq::@4
|
||||
sub_irq::@4: scope:[sub_irq] from sub_irq::@3
|
||||
[65] (byte) sub_irq::j#1 ← ++ (byte) sub_irq::j#4
|
||||
[66] if((byte) sub_irq::j#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto sub_irq::@2
|
||||
to:sub_irq::@5
|
||||
sub_irq::@5: scope:[sub_irq] from sub_irq::@4
|
||||
[67] (byte) sub_irq::i#1 ← ++ (byte) sub_irq::i#6
|
||||
[68] if((byte) sub_irq::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $b) goto sub_irq::@1
|
||||
to:sub_irq::@return
|
||||
sub_irq::@return: scope:[sub_irq] from sub_irq::@5
|
||||
[69] return
|
||||
to:@return
|
2291
src/test/ref/irq-local-var-overlap-problem.log
Normal file
2291
src/test/ref/irq-local-var-overlap-problem.log
Normal file
File diff suppressed because it is too large
Load Diff
119
src/test/ref/irq-local-var-overlap-problem.sym
Normal file
119
src/test/ref/irq-local-var-overlap-problem.sym
Normal file
@ -0,0 +1,119 @@
|
||||
(label) @4
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(byte*) BGCOL
|
||||
(const byte*) BGCOL#0 BGCOL = ((byte*))(word/dword/signed dword) $d020
|
||||
(byte*) CIA1_INTERRUPT
|
||||
(const byte*) CIA1_INTERRUPT#0 CIA1_INTERRUPT = ((byte*))(word/dword/signed dword) $dc0d
|
||||
(byte) CIA_INTERRUPT_CLEAR
|
||||
(const byte) CIA_INTERRUPT_CLEAR#0 CIA_INTERRUPT_CLEAR = (byte/signed byte/word/signed word/dword/signed dword) $7f
|
||||
(byte*) FGCOL
|
||||
(const byte*) FGCOL#0 FGCOL = ((byte*))(word/dword/signed dword) $d021
|
||||
(byte*) IRQ_ENABLE
|
||||
(const byte*) IRQ_ENABLE#0 IRQ_ENABLE = ((byte*))(word/dword/signed dword) $d01a
|
||||
(byte) IRQ_RASTER
|
||||
(const byte) IRQ_RASTER#0 IRQ_RASTER = (byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
(byte*) IRQ_STATUS
|
||||
(const byte*) IRQ_STATUS#0 IRQ_STATUS = ((byte*))(word/dword/signed dword) $d019
|
||||
(void()**) KERNEL_IRQ
|
||||
(const void()**) KERNEL_IRQ#0 KERNEL_IRQ = ((void()**))(word/signed word/dword/signed dword) $314
|
||||
(byte*) RASTER
|
||||
(const byte*) RASTER#0 RASTER = ((byte*))(word/dword/signed dword) $d012
|
||||
(byte*) VIC_CONTROL
|
||||
(const byte*) VIC_CONTROL#0 VIC_CONTROL = ((byte*))(word/dword/signed dword) $d011
|
||||
interrupt(KERNEL_MIN)(void()) irq()
|
||||
(byte~) irq::$0 reg byte a 2002.0
|
||||
(byte~) irq::$1 reg byte a 2002.0
|
||||
(label) irq::@1
|
||||
(label) irq::@2
|
||||
(label) irq::@3
|
||||
(label) irq::@4
|
||||
(label) irq::@5
|
||||
(label) irq::@6
|
||||
(label) irq::@7
|
||||
(label) irq::@return
|
||||
(byte) irq::i
|
||||
(byte) irq::i#1 i zp ZP_BYTE:6 16.5
|
||||
(byte) irq::i#7 i zp ZP_BYTE:6 93.0
|
||||
(byte) irq::j
|
||||
(byte) irq::j#1 j zp ZP_BYTE:7 151.5
|
||||
(byte) irq::j#4 j zp ZP_BYTE:7 150.375
|
||||
(byte) irq::k
|
||||
(byte) irq::k#1 k zp ZP_BYTE:8 1501.5
|
||||
(byte) irq::k#2 k zp ZP_BYTE:8 600.5999999999999
|
||||
(void()) main()
|
||||
(byte~) main::$1 reg byte a 20002.0
|
||||
(byte~) main::$2 reg byte a 20002.0
|
||||
(label) main::@10
|
||||
(label) main::@13
|
||||
(label) main::@14
|
||||
(label) main::@4
|
||||
(label) main::@5
|
||||
(label) main::@6
|
||||
(label) main::@9
|
||||
(byte) main::i
|
||||
(byte) main::i#1 i zp ZP_BYTE:2 71.0
|
||||
(byte) main::i#7 i zp ZP_BYTE:2 919.3636363636363
|
||||
(byte) main::j
|
||||
(byte) main::j#1 j zp ZP_BYTE:3 1501.5
|
||||
(byte) main::j#5 j zp ZP_BYTE:3 1500.375
|
||||
(byte) main::k
|
||||
(byte) main::k#1 k zp ZP_BYTE:4 15001.5
|
||||
(byte) main::k#2 k zp ZP_BYTE:4 6000.6
|
||||
(void()) sub_irq()
|
||||
(byte~) sub_irq::$0 reg byte a 2000002.0
|
||||
(byte~) sub_irq::$1 reg byte a 2000002.0
|
||||
(label) sub_irq::@1
|
||||
(label) sub_irq::@2
|
||||
(label) sub_irq::@3
|
||||
(label) sub_irq::@4
|
||||
(label) sub_irq::@5
|
||||
(label) sub_irq::@return
|
||||
(byte) sub_irq::i
|
||||
(byte) sub_irq::i#1 i zp ZP_BYTE:9 15001.5
|
||||
(byte) sub_irq::i#6 i zp ZP_BYTE:9 102000.30000000002
|
||||
(byte) sub_irq::j
|
||||
(byte) sub_irq::j#1 reg byte x 150001.5
|
||||
(byte) sub_irq::j#4 reg byte x 171428.99999999997
|
||||
(byte) sub_irq::k
|
||||
(byte) sub_irq::k#1 reg byte y 1500001.5
|
||||
(byte) sub_irq::k#2 reg byte y 750000.75
|
||||
(void()) sub_main()
|
||||
(byte~) sub_main::$0 reg byte a 2.0000002E7
|
||||
(byte~) sub_main::$1 reg byte a 2.0000002E7
|
||||
(label) sub_main::@1
|
||||
(label) sub_main::@2
|
||||
(label) sub_main::@3
|
||||
(label) sub_main::@4
|
||||
(label) sub_main::@5
|
||||
(label) sub_main::@return
|
||||
(byte) sub_main::i
|
||||
(byte) sub_main::i#1 i zp ZP_BYTE:5 150001.5
|
||||
(byte) sub_main::i#6 i zp ZP_BYTE:5 1020000.2999999999
|
||||
(byte) sub_main::j
|
||||
(byte) sub_main::j#1 reg byte x 1500001.5
|
||||
(byte) sub_main::j#4 reg byte x 1714286.1428571427
|
||||
(byte) sub_main::k
|
||||
(byte) sub_main::k#1 reg byte y 1.50000015E7
|
||||
(byte) sub_main::k#2 reg byte y 7500000.75
|
||||
|
||||
zp ZP_BYTE:2 [ main::i#7 main::i#1 ]
|
||||
zp ZP_BYTE:3 [ main::j#5 main::j#1 ]
|
||||
zp ZP_BYTE:4 [ main::k#2 main::k#1 ]
|
||||
zp ZP_BYTE:5 [ sub_main::i#6 sub_main::i#1 ]
|
||||
reg byte x [ sub_main::j#4 sub_main::j#1 ]
|
||||
reg byte y [ sub_main::k#2 sub_main::k#1 ]
|
||||
zp ZP_BYTE:6 [ irq::i#7 irq::i#1 ]
|
||||
zp ZP_BYTE:7 [ irq::j#4 irq::j#1 ]
|
||||
zp ZP_BYTE:8 [ irq::k#2 irq::k#1 ]
|
||||
zp ZP_BYTE:9 [ sub_irq::i#6 sub_irq::i#1 ]
|
||||
reg byte x [ sub_irq::j#4 sub_irq::j#1 ]
|
||||
reg byte y [ sub_irq::k#2 sub_irq::k#1 ]
|
||||
reg byte a [ main::$1 ]
|
||||
reg byte a [ main::$2 ]
|
||||
reg byte a [ sub_main::$0 ]
|
||||
reg byte a [ sub_main::$1 ]
|
||||
reg byte a [ irq::$0 ]
|
||||
reg byte a [ irq::$1 ]
|
||||
reg byte a [ sub_irq::$0 ]
|
||||
reg byte a [ sub_irq::$1 ]
|
@ -239,7 +239,7 @@ plexInit: {
|
||||
rts
|
||||
}
|
||||
plex_irq: {
|
||||
.label _3 = 5
|
||||
.label _3 = $10
|
||||
lda #WHITE
|
||||
sta BORDERCOL
|
||||
b1:
|
||||
@ -277,7 +277,7 @@ plex_irq: {
|
||||
// plexSort() prepares showing the sprites
|
||||
plexShowSprite: {
|
||||
.label _8 = 8
|
||||
.label plex_sprite_idx2 = 5
|
||||
.label plex_sprite_idx2 = $10
|
||||
.label plexFreeAdd1__2 = $a
|
||||
lda plex_sprite_idx
|
||||
asl
|
||||
|
@ -3451,11 +3451,10 @@ Uplifting [plexShowSprite] best 58508 combination reg byte x [ plexShowSprite::x
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:29 [ plexShowSprite::plex_sprite_idx2#0 ]
|
||||
Uplifting [plexShowSprite] best 58508 combination zp ZP_BYTE:29 [ plexShowSprite::plex_sprite_idx2#0 ]
|
||||
Coalescing zero page register [ zp ZP_BOOL:2 [ framedone#12 framedone#19 framedone#5 ] ] with [ zp ZP_BOOL:28 [ framedone#3 ] ]
|
||||
Coalescing zero page register [ zp ZP_BYTE:6 [ plexSort::m#2 plexSort::m#1 ] ] with [ zp ZP_BYTE:27 [ plex_irq::$3 ] ]
|
||||
Coalescing zero page register [ zp ZP_BYTE:6 [ plexSort::m#2 plexSort::m#1 plex_irq::$3 ] ] with [ zp ZP_BYTE:29 [ plexShowSprite::plex_sprite_idx2#0 ] ]
|
||||
Coalescing zero page register [ zp ZP_BYTE:15 [ plex_show_idx#27 plex_show_idx#0 plex_show_idx#16 ] ] with [ zp ZP_BYTE:21 [ plex_show_idx#1 ] ]
|
||||
Coalescing zero page register [ zp ZP_BYTE:17 [ plex_sprite_msb#29 plex_sprite_msb#0 plex_sprite_msb#17 plex_sprite_msb#27 plex_sprite_msb#4 ] ] with [ zp ZP_BYTE:23 [ plex_sprite_msb#1 ] ]
|
||||
Allocated (was zp ZP_BYTE:6) zp ZP_BYTE:5 [ plexSort::m#2 plexSort::m#1 plex_irq::$3 plexShowSprite::plex_sprite_idx2#0 ]
|
||||
Coalescing zero page register [ zp ZP_BYTE:27 [ plex_irq::$3 ] ] with [ zp ZP_BYTE:29 [ plexShowSprite::plex_sprite_idx2#0 ] ]
|
||||
Allocated (was zp ZP_BYTE:6) zp ZP_BYTE:5 [ plexSort::m#2 plexSort::m#1 ]
|
||||
Allocated (was zp ZP_WORD:10) zp ZP_WORD:6 [ init::xp#2 init::xp#1 ]
|
||||
Allocated (was zp ZP_BYTE:14) zp ZP_BYTE:8 [ plex_sprite_idx#25 plex_sprite_idx#0 plexShowSprite::$8 ]
|
||||
Allocated (was zp ZP_BYTE:15) zp ZP_BYTE:9 [ plex_show_idx#27 plex_show_idx#0 plex_show_idx#16 plex_show_idx#1 ]
|
||||
@ -3465,6 +3464,7 @@ Allocated (was zp ZP_BYTE:18) zp ZP_BYTE:12 [ plexSort::nxt_idx#0 ]
|
||||
Allocated (was zp ZP_BYTE:19) zp ZP_BYTE:13 [ plexSort::nxt_y#0 ]
|
||||
Allocated (was zp ZP_BYTE:22) zp ZP_BYTE:14 [ plex_sprite_idx#1 ]
|
||||
Allocated (was zp ZP_BYTE:24) zp ZP_BYTE:15 [ plex_free_next#0 ]
|
||||
Allocated (was zp ZP_BYTE:27) zp ZP_BYTE:16 [ plex_irq::$3 plexShowSprite::plex_sprite_idx2#0 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
@ -3947,7 +3947,7 @@ plexInit: {
|
||||
}
|
||||
//SEG152 plex_irq
|
||||
plex_irq: {
|
||||
.label _3 = 5
|
||||
.label _3 = $10
|
||||
//SEG153 entry interrupt(KERNEL_MIN)
|
||||
//SEG154 [86] *((const byte*) BORDERCOL#0) ← (const byte) WHITE#0 -- _deref_pbuc1=vbuc2
|
||||
lda #WHITE
|
||||
@ -4026,7 +4026,7 @@ plex_irq: {
|
||||
// plexSort() prepares showing the sprites
|
||||
plexShowSprite: {
|
||||
.label _8 = 8
|
||||
.label plex_sprite_idx2 = 5
|
||||
.label plex_sprite_idx2 = $10
|
||||
.label plexFreeAdd1__2 = $a
|
||||
//SEG181 [99] (byte) plexShowSprite::plex_sprite_idx2#0 ← (byte) plex_sprite_idx#25 << (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda plex_sprite_idx
|
||||
@ -4483,7 +4483,7 @@ FINAL SYMBOL TABLE
|
||||
(byte) plexShowSprite::plexFreeAdd1_ypos
|
||||
(byte) plexShowSprite::plexFreeAdd1_ypos#0 reg byte a 3.0
|
||||
(byte) plexShowSprite::plex_sprite_idx2
|
||||
(byte) plexShowSprite::plex_sprite_idx2#0 plex_sprite_idx2 zp ZP_BYTE:5 0.6000000000000001
|
||||
(byte) plexShowSprite::plex_sprite_idx2#0 plex_sprite_idx2 zp ZP_BYTE:16 0.6000000000000001
|
||||
(byte) plexShowSprite::xpos_idx
|
||||
(byte) plexShowSprite::xpos_idx#0 reg byte x 2.0
|
||||
(byte) plexShowSprite::ypos
|
||||
@ -4520,7 +4520,7 @@ FINAL SYMBOL TABLE
|
||||
(byte) plex_free_next#27 plex_free_next#27 zp ZP_BYTE:10 2.8333333333333335
|
||||
(byte) plex_free_next#31 plex_free_next#31 zp ZP_BYTE:10 4.0
|
||||
interrupt(KERNEL_MIN)(void()) plex_irq()
|
||||
(byte/signed word/word/dword/signed dword~) plex_irq::$3 $3 zp ZP_BYTE:5 11.0
|
||||
(byte/signed word/word/dword/signed dword~) plex_irq::$3 $3 zp ZP_BYTE:16 11.0
|
||||
(label) plex_irq::@1
|
||||
(label) plex_irq::@2
|
||||
(label) plex_irq::@3
|
||||
@ -4554,7 +4554,7 @@ zp ZP_BOOL:2 [ framedone#12 framedone#19 framedone#5 framedone#3 ]
|
||||
zp ZP_BYTE:3 [ loop::sin_idx#6 loop::sin_idx#0 loop::sin_idx#1 ]
|
||||
zp ZP_BYTE:4 [ loop::y_idx#2 loop::y_idx#0 loop::y_idx#1 ]
|
||||
reg byte y [ loop::sy#2 loop::sy#1 ]
|
||||
zp ZP_BYTE:5 [ plexSort::m#2 plexSort::m#1 plex_irq::$3 plexShowSprite::plex_sprite_idx2#0 ]
|
||||
zp ZP_BYTE:5 [ plexSort::m#2 plexSort::m#1 ]
|
||||
reg byte x [ plexSort::s#3 plexSort::s#1 plexSort::s#6 ]
|
||||
reg byte x [ plexSort::plexFreePrepare1_s#2 plexSort::plexFreePrepare1_s#1 ]
|
||||
reg byte x [ init::sx#2 init::sx#1 ]
|
||||
@ -4572,6 +4572,7 @@ zp ZP_BYTE:14 [ plex_sprite_idx#1 ]
|
||||
zp ZP_BYTE:15 [ plex_free_next#0 ]
|
||||
reg byte a [ init::$6 ]
|
||||
reg byte x [ plex_irq::plexFreeNextYpos1_return#0 ]
|
||||
zp ZP_BYTE:16 [ plex_irq::$3 plexShowSprite::plex_sprite_idx2#0 ]
|
||||
reg byte a [ plexShowSprite::plexFreeAdd1_ypos#0 ]
|
||||
reg byte a [ plexShowSprite::plexFreeAdd1_$0#0 ]
|
||||
reg byte x [ plexShowSprite::plexFreeAdd1_$1#0 ]
|
||||
@ -4979,7 +4980,7 @@ plexInit: {
|
||||
}
|
||||
//SEG152 plex_irq
|
||||
plex_irq: {
|
||||
.label _3 = 5
|
||||
.label _3 = $10
|
||||
//SEG153 entry interrupt(KERNEL_MIN)
|
||||
//SEG154 [86] *((const byte*) BORDERCOL#0) ← (const byte) WHITE#0 -- _deref_pbuc1=vbuc2
|
||||
lda #WHITE
|
||||
@ -5045,7 +5046,7 @@ plex_irq: {
|
||||
// plexSort() prepares showing the sprites
|
||||
plexShowSprite: {
|
||||
.label _8 = 8
|
||||
.label plex_sprite_idx2 = 5
|
||||
.label plex_sprite_idx2 = $10
|
||||
.label plexFreeAdd1__2 = $a
|
||||
//SEG181 [99] (byte) plexShowSprite::plex_sprite_idx2#0 ← (byte) plex_sprite_idx#25 << (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuz1=vbuz2_rol_1
|
||||
lda plex_sprite_idx
|
||||
|
@ -197,7 +197,7 @@
|
||||
(byte) plexShowSprite::plexFreeAdd1_ypos
|
||||
(byte) plexShowSprite::plexFreeAdd1_ypos#0 reg byte a 3.0
|
||||
(byte) plexShowSprite::plex_sprite_idx2
|
||||
(byte) plexShowSprite::plex_sprite_idx2#0 plex_sprite_idx2 zp ZP_BYTE:5 0.6000000000000001
|
||||
(byte) plexShowSprite::plex_sprite_idx2#0 plex_sprite_idx2 zp ZP_BYTE:16 0.6000000000000001
|
||||
(byte) plexShowSprite::xpos_idx
|
||||
(byte) plexShowSprite::xpos_idx#0 reg byte x 2.0
|
||||
(byte) plexShowSprite::ypos
|
||||
@ -234,7 +234,7 @@
|
||||
(byte) plex_free_next#27 plex_free_next#27 zp ZP_BYTE:10 2.8333333333333335
|
||||
(byte) plex_free_next#31 plex_free_next#31 zp ZP_BYTE:10 4.0
|
||||
interrupt(KERNEL_MIN)(void()) plex_irq()
|
||||
(byte/signed word/word/dword/signed dword~) plex_irq::$3 $3 zp ZP_BYTE:5 11.0
|
||||
(byte/signed word/word/dword/signed dword~) plex_irq::$3 $3 zp ZP_BYTE:16 11.0
|
||||
(label) plex_irq::@1
|
||||
(label) plex_irq::@2
|
||||
(label) plex_irq::@3
|
||||
@ -268,7 +268,7 @@ zp ZP_BOOL:2 [ framedone#12 framedone#19 framedone#5 framedone#3 ]
|
||||
zp ZP_BYTE:3 [ loop::sin_idx#6 loop::sin_idx#0 loop::sin_idx#1 ]
|
||||
zp ZP_BYTE:4 [ loop::y_idx#2 loop::y_idx#0 loop::y_idx#1 ]
|
||||
reg byte y [ loop::sy#2 loop::sy#1 ]
|
||||
zp ZP_BYTE:5 [ plexSort::m#2 plexSort::m#1 plex_irq::$3 plexShowSprite::plex_sprite_idx2#0 ]
|
||||
zp ZP_BYTE:5 [ plexSort::m#2 plexSort::m#1 ]
|
||||
reg byte x [ plexSort::s#3 plexSort::s#1 plexSort::s#6 ]
|
||||
reg byte x [ plexSort::plexFreePrepare1_s#2 plexSort::plexFreePrepare1_s#1 ]
|
||||
reg byte x [ init::sx#2 init::sx#1 ]
|
||||
@ -286,6 +286,7 @@ zp ZP_BYTE:14 [ plex_sprite_idx#1 ]
|
||||
zp ZP_BYTE:15 [ plex_free_next#0 ]
|
||||
reg byte a [ init::$6 ]
|
||||
reg byte x [ plex_irq::plexFreeNextYpos1_return#0 ]
|
||||
zp ZP_BYTE:16 [ plex_irq::$3 plexShowSprite::plex_sprite_idx2#0 ]
|
||||
reg byte a [ plexShowSprite::plexFreeAdd1_ypos#0 ]
|
||||
reg byte a [ plexShowSprite::plexFreeAdd1_$0#0 ]
|
||||
reg byte x [ plexShowSprite::plexFreeAdd1_$1#0 ]
|
||||
|
Loading…
x
Reference in New Issue
Block a user