mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-23 23:32:55 +00:00
Improved pointer-to-pointer functionality significantly.
This commit is contained in:
parent
44b6ed1fb8
commit
9ccc5d828f
4
src/main/fragment/_deref_pptc1=pbuc2.asm
Normal file
4
src/main/fragment/_deref_pptc1=pbuc2.asm
Normal file
@ -0,0 +1,4 @@
|
||||
lda #<{c2}
|
||||
sta {c1}
|
||||
lda #>{c2}
|
||||
sta {c1}+1
|
6
src/main/fragment/_deref_pptz1=pbuc1.asm
Normal file
6
src/main/fragment/_deref_pptz1=pbuc1.asm
Normal file
@ -0,0 +1,6 @@
|
||||
ldy #0
|
||||
lda #<{c1}
|
||||
sta ({z1}),y
|
||||
iny
|
||||
lda #>{c1}
|
||||
sta ({z1}),y
|
4
src/main/fragment/pptz1=pptc1.asm
Normal file
4
src/main/fragment/pptz1=pptc1.asm
Normal file
@ -0,0 +1,4 @@
|
||||
lda #<{c1}
|
||||
sta {z1}
|
||||
lda #>{c1}
|
||||
sta {z1}+1
|
2
src/main/fragment/vbuaa=_deref__deref_pptc1.asm
Normal file
2
src/main/fragment/vbuaa=_deref__deref_pptc1.asm
Normal file
@ -0,0 +1,2 @@
|
||||
ldy #0
|
||||
lda ({c1}),y
|
@ -123,10 +123,20 @@ public class CompileLog {
|
||||
this.verboseSequencePlan = verboseSequencePlan;
|
||||
}
|
||||
|
||||
public CompileLog verboseParse() {
|
||||
setVerboseParse(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setVerboseParse(boolean verboseParse) {
|
||||
this.verboseParse = verboseParse;
|
||||
}
|
||||
|
||||
public CompileLog verboseCreateSsa() {
|
||||
setVerboseCreateSsa(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setVerboseCreateSsa(boolean verboseCreateSsa) {
|
||||
this.verboseCreateSsa = verboseCreateSsa;
|
||||
}
|
||||
@ -135,6 +145,11 @@ public class CompileLog {
|
||||
return verboseUplift;
|
||||
}
|
||||
|
||||
public CompileLog verboseUplift() {
|
||||
setVerboseUplift(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setVerboseUplift(boolean verboseUplift) {
|
||||
this.verboseUplift = verboseUplift;
|
||||
}
|
||||
@ -167,6 +182,12 @@ public class CompileLog {
|
||||
return verboseSSAOptimize;
|
||||
}
|
||||
|
||||
public CompileLog setVerboseSSAOptimize() {
|
||||
setVerboseSSAOptimize(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public void setVerboseSSAOptimize(boolean verboseSSAOptimize) {
|
||||
this.verboseSSAOptimize = verboseSSAOptimize;
|
||||
}
|
||||
|
@ -45,13 +45,26 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
for(VariableRef constRef : constVars) {
|
||||
Variable variable = getProgram().getScope().getVariable(constRef);
|
||||
|
||||
ConstantVariableValue constVarVal = constants.get(constRef);
|
||||
|
||||
// Weed out all variables that are affected by the address-of operator
|
||||
if(isAddressOfUsed(constRef, getProgram())) {
|
||||
|
||||
// If the assignment has an operator then replace it with the single constant value
|
||||
if(constVarVal.getAssignment() instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) constVarVal.getAssignment();
|
||||
if(assignment.getOperator()!=null) {
|
||||
getLog().append("Constant right-side identified " + assignment.toString(getProgram(), false));
|
||||
assignment.setOperator(null);
|
||||
assignment.setrValue1(null);
|
||||
assignment.setrValue2(constVarVal.getConstantValue());
|
||||
}
|
||||
}
|
||||
|
||||
// But do not remove the variable
|
||||
constants.remove(constRef);
|
||||
continue;
|
||||
}
|
||||
|
||||
ConstantVariableValue constVarVal = constants.get(constRef);
|
||||
Scope constScope = variable.getScope();
|
||||
|
||||
ConstantValue constVal = constVarVal.getConstantValue();
|
||||
@ -80,7 +93,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
constVal);
|
||||
constantVar.setDeclaredAlignment(variable.getDeclaredAlignment());
|
||||
constantVar.setDeclaredRegister(variable.getDeclaredRegister());
|
||||
if(variable.getComments().size()>0) {
|
||||
if(variable.getComments().size() > 0) {
|
||||
constantVar.setComments(variable.getComments());
|
||||
} else {
|
||||
constantVar.setComments(constVarVal.getAssignment().getComments());
|
||||
@ -111,7 +124,7 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
/**
|
||||
* The statement that assigns the variable its value (the assignment will be removed at the end).
|
||||
* Either a {@link StatementAssignment} or a {@link StatementPhiBlock}.
|
||||
* */
|
||||
*/
|
||||
private Statement assignment;
|
||||
|
||||
public ConstantVariableValue(VariableRef variableRef, ConstantValue constantValue, Statement assignment) {
|
||||
@ -182,83 +195,85 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
// Volatile variables cannot be constant
|
||||
return;
|
||||
}
|
||||
if(assignment.getrValue1() == null && getConstant(assignment.getrValue2()) != null) {
|
||||
if(assignment.getOperator() == null) {
|
||||
// Constant assignment
|
||||
ConstantValue constant = getConstant(assignment.getrValue2());
|
||||
if(constant != null) {
|
||||
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
|
||||
}
|
||||
} else {
|
||||
// Constant unary expression
|
||||
ConstantValue constant = createUnary(
|
||||
(OperatorUnary) assignment.getOperator(),
|
||||
getConstant(assignment.getrValue2())
|
||||
);
|
||||
if(constant != null) {
|
||||
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
|
||||
}
|
||||
}
|
||||
} else if(getConstant(assignment.getrValue1()) != null && getConstant(assignment.getrValue2()) != null) {
|
||||
// Constant binary expression
|
||||
ConstantValue constant = createBinary(
|
||||
getConstant(assignment.getrValue1()),
|
||||
(OperatorBinary) assignment.getOperator(),
|
||||
getConstant(assignment.getrValue2()),
|
||||
getScope());
|
||||
if(constant != null) {
|
||||
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
|
||||
}
|
||||
} else if(assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
|
||||
// A candidate for a constant list - examine to confirm
|
||||
Variable lVariable = getScope().getVariable((VariableRef) lValue);
|
||||
if(lVariable.getType() instanceof SymbolTypeArray) {
|
||||
ValueList valueList = (ValueList) assignment.getrValue2();
|
||||
List<RValue> values = valueList.getList();
|
||||
boolean allConstant = true;
|
||||
// Type of the elements of the list (deducted from the type of all elements)
|
||||
SymbolType listType = null;
|
||||
List<ConstantValue> elements = new ArrayList<>();
|
||||
for(RValue elmValue : values) {
|
||||
if(elmValue instanceof ConstantValue) {
|
||||
ConstantValue constantValue = (ConstantValue) elmValue;
|
||||
SymbolType elmType = constantValue.getType(getScope());
|
||||
if(listType == null) {
|
||||
listType = elmType;
|
||||
} else {
|
||||
if(!SymbolTypeInference.typeMatch(listType, elmType)) {
|
||||
SymbolType intersectType = SymbolTypeInference.intersectTypes(listType, elmType);
|
||||
if(intersectType == null) {
|
||||
// No overlap between list type and element type
|
||||
throw new RuntimeException("Array type " + listType + " does not match element type" + elmType + ". Array: " + valueList.toString(getProgram()));
|
||||
} else {
|
||||
listType = intersectType;
|
||||
}
|
||||
}
|
||||
}
|
||||
elements.add(constantValue);
|
||||
} else {
|
||||
allConstant = false;
|
||||
listType = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(allConstant && listType != null) {
|
||||
// Constant list confirmed!
|
||||
ConstantValue constant = new ConstantArrayList(elements, listType);
|
||||
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
|
||||
}
|
||||
}
|
||||
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
|
||||
// Constant address-of variable
|
||||
if(assignment.getrValue2() instanceof SymbolRef) {
|
||||
ConstantSymbolPointer constantSymbolPointer = new ConstantSymbolPointer((SymbolRef) assignment.getrValue2());
|
||||
constants.put(variable, new ConstantVariableValue(variable, constantSymbolPointer, assignment));
|
||||
}
|
||||
ConstantValue constant = getConstantAssignmentValue(assignment, var.getType());
|
||||
if(constant != null) {
|
||||
constants.put(variable, new ConstantVariableValue(variable, constant, assignment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine the right side of an assignment and if it is constant then return the constant value.
|
||||
* @param assignment The assignment to examine
|
||||
* @param lValueType The type of the lvalue
|
||||
* @return The constant value if the right side is constant
|
||||
*/
|
||||
private ConstantValue getConstantAssignmentValue(StatementAssignment assignment, SymbolType lValueType) {
|
||||
if(assignment.getrValue1() == null && getConstant(assignment.getrValue2()) != null) {
|
||||
if(assignment.getOperator() == null) {
|
||||
// Constant assignment
|
||||
return getConstant(assignment.getrValue2());
|
||||
} else {
|
||||
// Constant unary expression
|
||||
return createUnary(
|
||||
(OperatorUnary) assignment.getOperator(),
|
||||
getConstant(assignment.getrValue2())
|
||||
);
|
||||
}
|
||||
} else if(getConstant(assignment.getrValue1()) != null && getConstant(assignment.getrValue2()) != null) {
|
||||
// Constant binary expression
|
||||
return createBinary(
|
||||
getConstant(assignment.getrValue1()),
|
||||
(OperatorBinary) assignment.getOperator(),
|
||||
getConstant(assignment.getrValue2()),
|
||||
getScope());
|
||||
} else if(assignment.getrValue2() instanceof ValueList && assignment.getOperator() == null && assignment.getrValue1() == null) {
|
||||
// A candidate for a constant list - examine to confirm
|
||||
if(lValueType instanceof SymbolTypeArray) {
|
||||
ValueList valueList = (ValueList) assignment.getrValue2();
|
||||
List<RValue> values = valueList.getList();
|
||||
boolean allConstant = true;
|
||||
// Type of the elements of the list (deducted from the type of all elements)
|
||||
SymbolType listType = null;
|
||||
List<ConstantValue> elements = new ArrayList<>();
|
||||
for(RValue elmValue : values) {
|
||||
if(elmValue instanceof ConstantValue) {
|
||||
ConstantValue constantValue = (ConstantValue) elmValue;
|
||||
SymbolType elmType = constantValue.getType(getScope());
|
||||
if(listType == null) {
|
||||
listType = elmType;
|
||||
} else {
|
||||
if(!SymbolTypeInference.typeMatch(listType, elmType)) {
|
||||
SymbolType intersectType = SymbolTypeInference.intersectTypes(listType, elmType);
|
||||
if(intersectType == null) {
|
||||
// No overlap between list type and element type
|
||||
throw new RuntimeException("Array type " + listType + " does not match element type" + elmType + ". Array: " + valueList.toString(getProgram()));
|
||||
} else {
|
||||
listType = intersectType;
|
||||
}
|
||||
}
|
||||
}
|
||||
elements.add(constantValue);
|
||||
} else {
|
||||
allConstant = false;
|
||||
listType = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(allConstant && listType != null) {
|
||||
// Constant list confirmed!
|
||||
return new ConstantArrayList(elements, listType);
|
||||
}
|
||||
}
|
||||
} else if(Operators.ADDRESS_OF.equals(assignment.getOperator()) && assignment.getrValue1() == null) {
|
||||
// Constant address-of variable
|
||||
if(assignment.getrValue2() instanceof SymbolRef) {
|
||||
return new ConstantSymbolPointer((SymbolRef) assignment.getrValue2());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the rValue is a known constant return the constant value.
|
||||
*
|
||||
|
@ -154,6 +154,7 @@ public class Pass4CodeGeneration {
|
||||
*/
|
||||
private void generateScopeEnding(AsmProgram asm, ScopeRef currentScope) {
|
||||
if(!ScopeRef.ROOT.equals(currentScope)) {
|
||||
// Generate any indirect calls pending
|
||||
for(String indirectCallAsmName : indirectCallAsmNames) {
|
||||
asm.addLabel("bi_"+indirectCallAsmName);
|
||||
asm.addInstruction("jmp", AsmAddressingMode.IND, indirectCallAsmName, false);
|
||||
@ -164,6 +165,20 @@ public class Pass4CodeGeneration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an indirect call to the assembler program. Also queues ASM for the indirect jump to be added at the end of the block.
|
||||
* @param asm The ASM program being built
|
||||
* @param procedureVariable The variable containing the function pointer
|
||||
* @param codeScopeRef The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope).
|
||||
*/
|
||||
private void generateIndirectCall(AsmProgram asm, Variable procedureVariable, ScopeRef codeScopeRef) {
|
||||
String varAsmName = AsmFormat.getAsmParamName(procedureVariable, codeScopeRef);
|
||||
indirectCallAsmNames.add(varAsmName);
|
||||
asm.addInstruction("jsr", AsmAddressingMode.ABS, "bi_" + varAsmName, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate a comment that describes the procedure signature and parameter transfer
|
||||
* @param asm The assembler program being generated
|
||||
@ -601,9 +616,7 @@ public class Pass4CodeGeneration {
|
||||
supported = true;
|
||||
} else if(pointer instanceof VariableRef) {
|
||||
Variable variable = getScope().getVariable((VariableRef) pointer);
|
||||
String varAsmName = AsmFormat.getAsmParamName(variable, block.getScope());
|
||||
indirectCallAsmNames.add(varAsmName);
|
||||
asm.addInstruction("jsr", AsmAddressingMode.ABS, "bi_"+varAsmName,false);
|
||||
generateIndirectCall(asm, variable, block.getScope());
|
||||
supported = true;
|
||||
}
|
||||
} else if(procedure instanceof VariableRef) {
|
||||
@ -611,9 +624,7 @@ public class Pass4CodeGeneration {
|
||||
SymbolType procedureVariableType = procedureVariable.getType();
|
||||
if(procedureVariableType instanceof SymbolTypePointer) {
|
||||
if(((SymbolTypePointer) procedureVariableType).getElementType() instanceof SymbolTypeProcedure) {
|
||||
String varAsmName = AsmFormat.getAsmParamName(procedureVariable, block.getScope());
|
||||
indirectCallAsmNames.add(varAsmName);
|
||||
asm.addInstruction("jsr", AsmAddressingMode.ABS, "bi_"+varAsmName,false);
|
||||
generateIndirectCall(asm, procedureVariable, block.getScope());
|
||||
supported = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.values.ConstantSymbolPointer;
|
||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.model.symbols.ConstantVar;
|
||||
import dk.camelot64.kickc.model.symbols.Variable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -49,12 +46,12 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
|
||||
Registers.RegisterType registerType = defaultRegister.getType();
|
||||
List<Registers.Register> potentials = new ArrayList<>();
|
||||
potentials.add(defaultRegister);
|
||||
if(registerType.equals(Registers.RegisterType.ZP_BYTE) && !varRefExtracted(equivalenceClass) &&!varVolatile(equivalenceClass)) {
|
||||
if(registerType.equals(Registers.RegisterType.ZP_BYTE) && !isAddressOfUsed(equivalenceClass) &&!varVolatile(equivalenceClass)) {
|
||||
potentials.add(Registers.getRegisterA());
|
||||
potentials.add(Registers.getRegisterX());
|
||||
potentials.add(Registers.getRegisterY());
|
||||
}
|
||||
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !varRefExtracted(equivalenceClass) &&!varVolatile(equivalenceClass)) {
|
||||
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !isAddressOfUsed(equivalenceClass) &&!varVolatile(equivalenceClass)) {
|
||||
potentials.add(Registers.getRegisterA());
|
||||
}
|
||||
registerPotentials.setPotentialRegisters(equivalenceClass, potentials);
|
||||
@ -83,14 +80,10 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
|
||||
* @param equivalenceClass The equivalence class
|
||||
* @return true if a variable reference is extracted
|
||||
*/
|
||||
private boolean varRefExtracted(LiveRangeEquivalenceClass equivalenceClass) {
|
||||
Collection<ConstantVar> allConstants = getProgram().getScope().getAllConstants(true);
|
||||
for(ConstantVar allConstant : allConstants) {
|
||||
if(allConstant.getValue() instanceof ConstantSymbolPointer) {
|
||||
SymbolRef toSym = ((ConstantSymbolPointer) allConstant.getValue()).getToSymbol();
|
||||
if(equivalenceClass.getVariables().contains(toSym)) {
|
||||
return true;
|
||||
}
|
||||
private boolean isAddressOfUsed(LiveRangeEquivalenceClass equivalenceClass) {
|
||||
for(VariableRef variableRef : equivalenceClass.getVariables()) {
|
||||
if(Pass2ConstantIdentification.isAddressOfUsed(variableRef, getProgram())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -32,6 +32,16 @@ public class TestPrograms {
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerPointer2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("pointer-pointer-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerPointer1() throws IOException, URISyntaxException {
|
||||
compileAndCompare("pointer-pointer-1" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionPointerNoargCall6() throws IOException, URISyntaxException {
|
||||
compileAndCompare("function-pointer-noarg-call-6");
|
||||
@ -109,7 +119,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testLocalScopeLoops() throws IOException, URISyntaxException {
|
||||
compileAndCompare("localscope-loops", getLogSysout());
|
||||
compileAndCompare("localscope-loops");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1470,11 +1480,11 @@ public class TestPrograms {
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
CompileLog log = getLogSysout();
|
||||
CompileLog log = log();
|
||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
private static CompileLog getLogSysout() {
|
||||
private static CompileLog log() {
|
||||
CompileLog log = new CompileLog();
|
||||
log.setSysOut(true);
|
||||
return log;
|
||||
|
11
src/test/kc/pointer-pointer-1.kc
Normal file
11
src/test/kc/pointer-pointer-1.kc
Normal file
@ -0,0 +1,11 @@
|
||||
// Tests a simple pointer to a pointer
|
||||
|
||||
void main() {
|
||||
const byte* SCREEN = $400;
|
||||
|
||||
byte b = 'a';
|
||||
byte* pb = &b;
|
||||
byte** ppb = &pb;
|
||||
*SCREEN = **ppb;
|
||||
|
||||
}
|
30
src/test/kc/pointer-pointer-2.kc
Normal file
30
src/test/kc/pointer-pointer-2.kc
Normal file
@ -0,0 +1,30 @@
|
||||
// Tests pointer to pointer in a more complex setup
|
||||
|
||||
void main() {
|
||||
|
||||
byte* screen = $400;
|
||||
|
||||
byte* text;
|
||||
for(byte i: 0..20) {
|
||||
nexttext(&text);
|
||||
while(*text!='@') {
|
||||
*screen++ = *text++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
byte[] text1 = "camelot @";
|
||||
byte[] text2 = "rex @";
|
||||
|
||||
byte textid = 0;
|
||||
|
||||
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
|
||||
void nexttext(byte** textp) {
|
||||
if((textid++&1)==0) {
|
||||
*textp = text1;
|
||||
} else {
|
||||
*textp = text2;
|
||||
}
|
||||
}
|
||||
|
20
src/test/ref/pointer-pointer-1.asm
Normal file
20
src/test/ref/pointer-pointer-1.asm
Normal file
@ -0,0 +1,20 @@
|
||||
// Tests a simple pointer to a pointer
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label ppb = pb
|
||||
.label b = 2
|
||||
.label pb = 3
|
||||
lda #'a'
|
||||
sta b
|
||||
lda #<b
|
||||
sta pb
|
||||
lda #>b
|
||||
sta pb+1
|
||||
ldy #0
|
||||
lda (ppb),y
|
||||
sta SCREEN
|
||||
rts
|
||||
}
|
17
src/test/ref/pointer-pointer-1.cfg
Normal file
17
src/test/ref/pointer-pointer-1.cfg
Normal file
@ -0,0 +1,17 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] (byte) main::b#0 ← (byte) 'a'
|
||||
[5] (byte*) main::pb#0 ← &(byte) main::b#0
|
||||
[6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0))
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[7] return
|
||||
to:@return
|
286
src/test/ref/pointer-pointer-1.log
Normal file
286
src/test/ref/pointer-pointer-1.log
Normal file
@ -0,0 +1,286 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
to:@1
|
||||
main: scope:[main] from @1
|
||||
(byte*) main::SCREEN#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
|
||||
(byte) main::b#0 ← (byte) 'a'
|
||||
(byte*~) main::$0 ← & (byte) main::b#0
|
||||
(byte*) main::pb#0 ← (byte*~) main::$0
|
||||
(byte**~) main::$1 ← & (byte*) main::pb#0
|
||||
(byte**) main::ppb#0 ← (byte**~) main::$1
|
||||
*((byte*) main::SCREEN#0) ← *(*((byte**) main::ppb#0))
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
call main
|
||||
to:@2
|
||||
@2: scope:[] from @1
|
||||
to:@end
|
||||
@end: scope:[] from @2
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(byte*~) main::$0
|
||||
(byte**~) main::$1
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(byte*) main::SCREEN#0
|
||||
(byte) main::b
|
||||
(byte) main::b#0
|
||||
(byte*) main::pb
|
||||
(byte*) main::pb#0
|
||||
(byte**) main::ppb
|
||||
(byte**) main::ppb#0
|
||||
|
||||
Culled Empty Block (label) @2
|
||||
Successful SSA optimization Pass2CullEmptyBlocks
|
||||
Alias (byte*) main::pb#0 = (byte*~) main::$0
|
||||
Alias (byte**) main::ppb#0 = (byte**~) main::$1
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Constant (const byte*) main::SCREEN#0 = ((byte*))$400
|
||||
Constant right-side identified [2] (byte*) main::pb#0 ← & (byte) main::b#0
|
||||
Constant (const byte**) main::ppb#0 = &main::pb#0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
CALL GRAPH
|
||||
Calls in [] to main:2
|
||||
|
||||
Created 0 initial phi equivalence classes
|
||||
Coalesced down to 0 phi equivalence classes
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] (byte) main::b#0 ← (byte) 'a'
|
||||
[5] (byte*) main::pb#0 ← &(byte) main::b#0
|
||||
[6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0))
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main
|
||||
[7] return
|
||||
to:@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
(byte*) main::SCREEN
|
||||
(byte) main::b
|
||||
(byte) main::b#0 2.0
|
||||
(byte*) main::pb
|
||||
(byte*) main::pb#0 20.0
|
||||
(byte**) main::ppb
|
||||
|
||||
Initial phi equivalence classes
|
||||
Added variable main::b#0 to zero page equivalence class [ main::b#0 ]
|
||||
Added variable main::pb#0 to zero page equivalence class [ main::pb#0 ]
|
||||
Complete equivalence classes
|
||||
[ main::b#0 ]
|
||||
[ main::pb#0 ]
|
||||
Allocated zp ZP_BYTE:2 [ main::b#0 ]
|
||||
Allocated zp ZP_WORD:3 [ main::pb#0 ]
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Tests a simple pointer to a pointer
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label ppb = pb
|
||||
.label b = 2
|
||||
.label pb = 3
|
||||
//SEG10 [4] (byte) main::b#0 ← (byte) 'a' -- vbuz1=vbuc1
|
||||
lda #'a'
|
||||
sta b
|
||||
//SEG11 [5] (byte*) main::pb#0 ← &(byte) main::b#0 -- pbuz1=pbuc1
|
||||
lda #<b
|
||||
sta pb
|
||||
lda #>b
|
||||
sta pb+1
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref__deref_pptc2
|
||||
ldy #0
|
||||
lda (ppb),y
|
||||
sta SCREEN
|
||||
jmp breturn
|
||||
//SEG13 main::@return
|
||||
breturn:
|
||||
//SEG14 [7] return
|
||||
rts
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] (byte) main::b#0 ← (byte) 'a' [ main::b#0 ] ( main:2 [ main::b#0 ] ) always clobbers reg byte a
|
||||
Statement [5] (byte*) main::pb#0 ← &(byte) main::b#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) [ ] ( main:2 [ ] ) always clobbers reg byte a reg byte y
|
||||
Potential registers zp ZP_BYTE:2 [ main::b#0 ] : zp ZP_BYTE:2 ,
|
||||
Potential registers zp ZP_WORD:3 [ main::pb#0 ] : zp ZP_WORD:3 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 20: zp ZP_WORD:3 [ main::pb#0 ] 2: zp ZP_BYTE:2 [ main::b#0 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 47 combination zp ZP_WORD:3 [ main::pb#0 ] zp ZP_BYTE:2 [ main::b#0 ]
|
||||
Uplifting [] best 47 combination
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:2 [ main::b#0 ]
|
||||
Uplifting [main] best 47 combination zp ZP_BYTE:2 [ main::b#0 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Tests a simple pointer to a pointer
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
jsr main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG8 @end
|
||||
bend:
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label ppb = pb
|
||||
.label b = 2
|
||||
.label pb = 3
|
||||
//SEG10 [4] (byte) main::b#0 ← (byte) 'a' -- vbuz1=vbuc1
|
||||
lda #'a'
|
||||
sta b
|
||||
//SEG11 [5] (byte*) main::pb#0 ← &(byte) main::b#0 -- pbuz1=pbuc1
|
||||
lda #<b
|
||||
sta pb
|
||||
lda #>b
|
||||
sta pb+1
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref__deref_pptc2
|
||||
ldy #0
|
||||
lda (ppb),y
|
||||
sta SCREEN
|
||||
jmp breturn
|
||||
//SEG13 main::@return
|
||||
breturn:
|
||||
//SEG14 [7] return
|
||||
rts
|
||||
}
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction bend:
|
||||
Removing instruction breturn:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction bbegin:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(byte) main::b
|
||||
(byte) main::b#0 b zp ZP_BYTE:2 2.0
|
||||
(byte*) main::pb
|
||||
(byte*) main::pb#0 pb zp ZP_WORD:3 20.0
|
||||
(byte**) main::ppb
|
||||
(const byte**) main::ppb#0 ppb = &(byte*) main::pb#0
|
||||
|
||||
zp ZP_BYTE:2 [ main::b#0 ]
|
||||
zp ZP_WORD:3 [ main::pb#0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 32
|
||||
|
||||
//SEG0 File Comments
|
||||
// Tests a simple pointer to a pointer
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
//SEG3 @begin
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG5 @1
|
||||
//SEG6 [2] call main
|
||||
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG8 @end
|
||||
//SEG9 main
|
||||
main: {
|
||||
.label SCREEN = $400
|
||||
.label ppb = pb
|
||||
.label b = 2
|
||||
.label pb = 3
|
||||
//SEG10 [4] (byte) main::b#0 ← (byte) 'a' -- vbuz1=vbuc1
|
||||
lda #'a'
|
||||
sta b
|
||||
//SEG11 [5] (byte*) main::pb#0 ← &(byte) main::b#0 -- pbuz1=pbuc1
|
||||
lda #<b
|
||||
sta pb
|
||||
lda #>b
|
||||
sta pb+1
|
||||
//SEG12 [6] *((const byte*) main::SCREEN#0) ← *(*((const byte**) main::ppb#0)) -- _deref_pbuc1=_deref__deref_pptc2
|
||||
ldy #0
|
||||
lda (ppb),y
|
||||
sta SCREEN
|
||||
//SEG13 main::@return
|
||||
//SEG14 [7] return
|
||||
rts
|
||||
}
|
||||
|
16
src/test/ref/pointer-pointer-1.sym
Normal file
16
src/test/ref/pointer-pointer-1.sym
Normal file
@ -0,0 +1,16 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@return
|
||||
(byte*) main::SCREEN
|
||||
(const byte*) main::SCREEN#0 SCREEN = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
(byte) main::b
|
||||
(byte) main::b#0 b zp ZP_BYTE:2 2.0
|
||||
(byte*) main::pb
|
||||
(byte*) main::pb#0 pb zp ZP_WORD:3 20.0
|
||||
(byte**) main::ppb
|
||||
(const byte**) main::ppb#0 ppb = &(byte*) main::pb#0
|
||||
|
||||
zp ZP_BYTE:2 [ main::b#0 ]
|
||||
zp ZP_WORD:3 [ main::pb#0 ]
|
65
src/test/ref/pointer-pointer-2.asm
Normal file
65
src/test/ref/pointer-pointer-2.asm
Normal file
@ -0,0 +1,65 @@
|
||||
// Tests pointer to pointer in a more complex setup
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label textid = 4
|
||||
main: {
|
||||
.label screen = 5
|
||||
.label text = 2
|
||||
ldx #0
|
||||
lda #<$400
|
||||
sta screen
|
||||
lda #>$400
|
||||
sta screen+1
|
||||
txa
|
||||
sta textid
|
||||
sta text
|
||||
sta text+1
|
||||
b1:
|
||||
jsr nexttext
|
||||
b2:
|
||||
ldy #0
|
||||
lda (text),y
|
||||
cmp #'@'
|
||||
bne b3
|
||||
inx
|
||||
cpx #$15
|
||||
bne b1
|
||||
rts
|
||||
b3:
|
||||
ldy #0
|
||||
lda (text),y
|
||||
sta (screen),y
|
||||
inc screen
|
||||
bne !+
|
||||
inc screen+1
|
||||
!:
|
||||
inc text
|
||||
bne !+
|
||||
inc text+1
|
||||
!:
|
||||
jmp b2
|
||||
}
|
||||
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
|
||||
nexttext: {
|
||||
.label textp = main.text
|
||||
lda #1
|
||||
and textid
|
||||
inc textid
|
||||
cmp #0
|
||||
beq b1
|
||||
lda #<text2
|
||||
sta textp
|
||||
lda #>text2
|
||||
sta textp+1
|
||||
breturn:
|
||||
rts
|
||||
b1:
|
||||
lda #<text1
|
||||
sta textp
|
||||
lda #>text1
|
||||
sta textp+1
|
||||
jmp breturn
|
||||
}
|
||||
text1: .text "camelot @"
|
||||
text2: .text "rex @"
|
50
src/test/ref/pointer-pointer-2.cfg
Normal file
50
src/test/ref/pointer-pointer-2.cfg
Normal file
@ -0,0 +1,50 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@4
|
||||
[5] (byte) main::i#5 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) main::i#1 )
|
||||
[5] (byte*) main::screen#4 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@4/(byte*) main::screen#2 )
|
||||
[5] (byte) textid#11 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) textid#13 )
|
||||
[5] (byte*) main::text#2 ← phi( main/(byte*) 0 main::@4/(byte*) main::text#3 )
|
||||
[6] call nexttext
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1 main::@3
|
||||
[7] (byte*) main::screen#2 ← phi( main::@3/(byte*) main::screen#1 main::@1/(byte*) main::screen#4 )
|
||||
[7] (byte*) main::text#3 ← phi( main::@3/(byte*) main::text#1 main::@1/(byte*) main::text#2 )
|
||||
[8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@2
|
||||
[9] (byte) main::i#1 ← ++ (byte) main::i#5
|
||||
[10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@4
|
||||
[11] return
|
||||
to:@return
|
||||
main::@3: scope:[main] from main::@2
|
||||
[12] *((byte*) main::screen#2) ← *((byte*) main::text#3)
|
||||
[13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
|
||||
[14] (byte*) main::text#1 ← ++ (byte*) main::text#3
|
||||
to:main::@2
|
||||
nexttext: scope:[nexttext] from main::@1
|
||||
[15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
[16] (byte) textid#13 ← ++ (byte) textid#11
|
||||
[17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1
|
||||
to:nexttext::@2
|
||||
nexttext::@2: scope:[nexttext] from nexttext
|
||||
[18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0
|
||||
to:nexttext::@return
|
||||
nexttext::@return: scope:[nexttext] from nexttext::@1 nexttext::@2
|
||||
[19] return
|
||||
to:@return
|
||||
nexttext::@1: scope:[nexttext] from nexttext
|
||||
[20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0
|
||||
to:nexttext::@return
|
866
src/test/ref/pointer-pointer-2.log
Normal file
866
src/test/ref/pointer-pointer-2.log
Normal file
@ -0,0 +1,866 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
@begin: scope:[] from
|
||||
to:@1
|
||||
main: scope:[main] from @2
|
||||
(byte) textid#16 ← phi( @2/(byte) textid#15 )
|
||||
(byte*) main::screen#0 ← ((byte*)) (word/signed word/dword/signed dword) $400
|
||||
(byte*) main::text#0 ← (byte*) 0
|
||||
(byte) main::i#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@4
|
||||
(byte) main::i#6 ← phi( main/(byte) main::i#0 main::@4/(byte) main::i#1 )
|
||||
(byte*) main::screen#5 ← phi( main/(byte*) main::screen#0 main::@4/(byte*) main::screen#6 )
|
||||
(byte) textid#11 ← phi( main/(byte) textid#16 main::@4/(byte) textid#12 )
|
||||
(byte*) main::text#2 ← phi( main/(byte*) main::text#0 main::@4/(byte*) main::text#5 )
|
||||
(byte**~) main::$0 ← & (byte*) main::text#2
|
||||
(byte**) nexttext::textp#0 ← (byte**~) main::$0
|
||||
call nexttext
|
||||
to:main::@9
|
||||
main::@9: scope:[main] from main::@1
|
||||
(byte) main::i#5 ← phi( main::@1/(byte) main::i#6 )
|
||||
(byte*) main::screen#4 ← phi( main::@1/(byte*) main::screen#5 )
|
||||
(byte*) main::text#6 ← phi( main::@1/(byte*) main::text#2 )
|
||||
(byte) textid#6 ← phi( main::@1/(byte) textid#4 )
|
||||
(byte) textid#0 ← (byte) textid#6
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@3 main::@9
|
||||
(byte) textid#17 ← phi( main::@3/(byte) textid#18 main::@9/(byte) textid#0 )
|
||||
(byte) main::i#3 ← phi( main::@3/(byte) main::i#4 main::@9/(byte) main::i#5 )
|
||||
(byte*) main::screen#3 ← phi( main::@3/(byte*) main::screen#1 main::@9/(byte*) main::screen#4 )
|
||||
(byte*) main::text#3 ← phi( main::@3/(byte*) main::text#1 main::@9/(byte*) main::text#6 )
|
||||
(bool~) main::$2 ← *((byte*) main::text#3) != (byte) '@'
|
||||
if((bool~) main::$2) goto main::@3
|
||||
to:main::@4
|
||||
main::@3: scope:[main] from main::@2
|
||||
(byte) textid#18 ← phi( main::@2/(byte) textid#17 )
|
||||
(byte) main::i#4 ← phi( main::@2/(byte) main::i#3 )
|
||||
(byte*) main::screen#2 ← phi( main::@2/(byte*) main::screen#3 )
|
||||
(byte*) main::text#4 ← phi( main::@2/(byte*) main::text#3 )
|
||||
*((byte*) main::screen#2) ← *((byte*) main::text#4)
|
||||
(byte*) main::screen#1 ← ++ (byte*) main::screen#2
|
||||
(byte*) main::text#1 ← ++ (byte*) main::text#4
|
||||
to:main::@2
|
||||
main::@4: scope:[main] from main::@2
|
||||
(byte*) main::screen#6 ← phi( main::@2/(byte*) main::screen#3 )
|
||||
(byte) textid#12 ← phi( main::@2/(byte) textid#17 )
|
||||
(byte*) main::text#5 ← phi( main::@2/(byte*) main::text#3 )
|
||||
(byte) main::i#2 ← phi( main::@2/(byte) main::i#3 )
|
||||
(byte) main::i#1 ← (byte) main::i#2 + rangenext(0,$14)
|
||||
(bool~) main::$3 ← (byte) main::i#1 != rangelast(0,$14)
|
||||
if((bool~) main::$3) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@4
|
||||
(byte) textid#7 ← phi( main::@4/(byte) textid#12 )
|
||||
(byte) textid#1 ← (byte) textid#7
|
||||
return
|
||||
to:@return
|
||||
@1: scope:[] from @begin
|
||||
(byte[]) text1#0 ← (const string) $0
|
||||
(byte[]) text2#0 ← (const string) $1
|
||||
(byte) textid#2 ← (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
to:@2
|
||||
nexttext: scope:[nexttext] from main::@1
|
||||
(byte**) nexttext::textp#3 ← phi( main::@1/(byte**) nexttext::textp#0 )
|
||||
(byte) textid#8 ← phi( main::@1/(byte) textid#11 )
|
||||
(byte~) nexttext::$0 ← (byte) textid#8 & (byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
(bool~) nexttext::$1 ← (byte~) nexttext::$0 == (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
(byte) textid#3 ← ++ (byte) textid#8
|
||||
if((bool~) nexttext::$1) goto nexttext::@1
|
||||
to:nexttext::@3
|
||||
nexttext::@1: scope:[nexttext] from nexttext
|
||||
(byte) textid#13 ← phi( nexttext/(byte) textid#3 )
|
||||
(byte**) nexttext::textp#1 ← phi( nexttext/(byte**) nexttext::textp#3 )
|
||||
*((byte**) nexttext::textp#1) ← (byte[]) text1#0
|
||||
to:nexttext::@return
|
||||
nexttext::@3: scope:[nexttext] from nexttext
|
||||
(byte) textid#14 ← phi( nexttext/(byte) textid#3 )
|
||||
(byte**) nexttext::textp#2 ← phi( nexttext/(byte**) nexttext::textp#3 )
|
||||
*((byte**) nexttext::textp#2) ← (byte[]) text2#0
|
||||
to:nexttext::@return
|
||||
nexttext::@return: scope:[nexttext] from nexttext::@1 nexttext::@3
|
||||
(byte) textid#9 ← phi( nexttext::@1/(byte) textid#13 nexttext::@3/(byte) textid#14 )
|
||||
(byte) textid#4 ← (byte) textid#9
|
||||
return
|
||||
to:@return
|
||||
@2: scope:[] from @1
|
||||
(byte) textid#15 ← phi( @1/(byte) textid#2 )
|
||||
call main
|
||||
to:@3
|
||||
@3: scope:[] from @2
|
||||
(byte) textid#10 ← phi( @2/(byte) textid#1 )
|
||||
(byte) textid#5 ← (byte) textid#10
|
||||
to:@end
|
||||
@end: scope:[] from @3
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(const string) $0 = (string) "camelot @"
|
||||
(const string) $1 = (string) "rex @"
|
||||
(label) @1
|
||||
(label) @2
|
||||
(label) @3
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(byte**~) main::$0
|
||||
(bool~) main::$2
|
||||
(bool~) main::$3
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@9
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#0
|
||||
(byte) main::i#1
|
||||
(byte) main::i#2
|
||||
(byte) main::i#3
|
||||
(byte) main::i#4
|
||||
(byte) main::i#5
|
||||
(byte) main::i#6
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#0
|
||||
(byte*) main::screen#1
|
||||
(byte*) main::screen#2
|
||||
(byte*) main::screen#3
|
||||
(byte*) main::screen#4
|
||||
(byte*) main::screen#5
|
||||
(byte*) main::screen#6
|
||||
(byte*) main::text
|
||||
(byte*) main::text#0
|
||||
(byte*) main::text#1
|
||||
(byte*) main::text#2
|
||||
(byte*) main::text#3
|
||||
(byte*) main::text#4
|
||||
(byte*) main::text#5
|
||||
(byte*) main::text#6
|
||||
(void()) nexttext((byte**) nexttext::textp)
|
||||
(byte~) nexttext::$0
|
||||
(bool~) nexttext::$1
|
||||
(label) nexttext::@1
|
||||
(label) nexttext::@3
|
||||
(label) nexttext::@return
|
||||
(byte**) nexttext::textp
|
||||
(byte**) nexttext::textp#0
|
||||
(byte**) nexttext::textp#1
|
||||
(byte**) nexttext::textp#2
|
||||
(byte**) nexttext::textp#3
|
||||
(byte[]) text1
|
||||
(byte[]) text1#0
|
||||
(byte[]) text2
|
||||
(byte[]) text2#0
|
||||
(byte) textid
|
||||
(byte) textid#0
|
||||
(byte) textid#1
|
||||
(byte) textid#10
|
||||
(byte) textid#11
|
||||
(byte) textid#12
|
||||
(byte) textid#13
|
||||
(byte) textid#14
|
||||
(byte) textid#15
|
||||
(byte) textid#16
|
||||
(byte) textid#17
|
||||
(byte) textid#18
|
||||
(byte) textid#2
|
||||
(byte) textid#3
|
||||
(byte) textid#4
|
||||
(byte) textid#5
|
||||
(byte) textid#6
|
||||
(byte) textid#7
|
||||
(byte) textid#8
|
||||
(byte) textid#9
|
||||
|
||||
Alias (byte**) nexttext::textp#0 = (byte**~) main::$0
|
||||
Alias (byte*) main::text#2 = (byte*) main::text#6
|
||||
Alias (byte*) main::screen#4 = (byte*) main::screen#5
|
||||
Alias (byte) main::i#5 = (byte) main::i#6
|
||||
Alias (byte) textid#0 = (byte) textid#6
|
||||
Alias (byte*) main::text#3 = (byte*) main::text#4 (byte*) main::text#5
|
||||
Alias (byte*) main::screen#2 = (byte*) main::screen#3 (byte*) main::screen#6
|
||||
Alias (byte) main::i#2 = (byte) main::i#4 (byte) main::i#3
|
||||
Alias (byte) textid#1 = (byte) textid#18 (byte) textid#17 (byte) textid#12 (byte) textid#7
|
||||
Alias (byte**) nexttext::textp#1 = (byte**) nexttext::textp#3 (byte**) nexttext::textp#2
|
||||
Alias (byte) textid#13 = (byte) textid#3 (byte) textid#14
|
||||
Alias (byte) textid#4 = (byte) textid#9
|
||||
Alias (byte) textid#15 = (byte) textid#2
|
||||
Alias (byte) textid#10 = (byte) textid#5
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Alias (byte) textid#13 = (byte) textid#4
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Self Phi Eliminated (byte) main::i#2
|
||||
Self Phi Eliminated (byte) textid#1
|
||||
Successful SSA optimization Pass2SelfPhiElimination
|
||||
Redundant Phi (byte) textid#16 (byte) textid#15
|
||||
Redundant Phi (byte) textid#0 (byte) textid#13
|
||||
Redundant Phi (byte) main::i#2 (byte) main::i#5
|
||||
Redundant Phi (byte) textid#1 (byte) textid#0
|
||||
Redundant Phi (byte) textid#8 (byte) textid#11
|
||||
Redundant Phi (byte**) nexttext::textp#1 (byte**) nexttext::textp#0
|
||||
Redundant Phi (byte) textid#10 (byte) textid#1
|
||||
Successful SSA optimization Pass2RedundantPhiElimination
|
||||
Simple Condition (bool~) main::$2 [12] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3
|
||||
Simple Condition (bool~) main::$3 [20] if((byte) main::i#1!=rangelast(0,$14)) goto main::@1
|
||||
Simple Condition (bool~) nexttext::$1 [31] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant (const byte*) main::screen#0 = ((byte*))$400
|
||||
Constant (const byte*) main::text#0 = 0
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Constant (const byte**) nexttext::textp#0 = &main::text#2
|
||||
Constant (const byte[]) text1#0 = $0
|
||||
Constant (const byte[]) text2#0 = $1
|
||||
Constant (const byte) textid#15 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Resolved ranged next value main::i#1 ← ++ main::i#5 to ++
|
||||
Resolved ranged comparison value if(main::i#1!=rangelast(0,$14)) goto main::@1 to (byte/signed byte/word/signed word/dword/signed dword) $15
|
||||
Culled Empty Block (label) main::@9
|
||||
Culled Empty Block (label) @1
|
||||
Culled Empty Block (label) @3
|
||||
Successful SSA optimization Pass2CullEmptyBlocks
|
||||
Inlining constant with var siblings (const byte*) main::screen#0
|
||||
Inlining constant with var siblings (const byte*) main::text#0
|
||||
Inlining constant with var siblings (const byte) main::i#0
|
||||
Inlining constant with var siblings (const byte) textid#15
|
||||
Constant inlined main::screen#0 = ((byte*))(word/signed word/dword/signed dword) $400
|
||||
Constant inlined main::i#0 = (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
Constant inlined main::text#0 = (byte*) 0
|
||||
Constant inlined textid#15 = (byte/signed byte/word/signed word/dword/signed dword) 0
|
||||
Constant inlined $0 = (const byte[]) text1#0
|
||||
Constant inlined $1 = (const byte[]) text2#0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Added new block during phi lifting main::@10(between main::@4 and main::@1)
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @2
|
||||
Adding NOP phi() at start of @end
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
Calls in [] to main:2
|
||||
Calls in [main] to nexttext:6
|
||||
|
||||
Created 6 initial phi equivalence classes
|
||||
Coalesced [7] main::text#9 ← main::text#2
|
||||
Coalesced [8] main::screen#9 ← main::screen#4
|
||||
Coalesced (already) [14] main::text#7 ← main::text#3
|
||||
Coalesced [15] textid#19 ← textid#13
|
||||
Coalesced (already) [16] main::screen#7 ← main::screen#2
|
||||
Coalesced [17] main::i#7 ← main::i#1
|
||||
Coalesced [21] main::text#8 ← main::text#1
|
||||
Coalesced [22] main::screen#8 ← main::screen#1
|
||||
Coalesced down to 4 phi equivalence classes
|
||||
Culled Empty Block (label) main::@10
|
||||
Renumbering block @2 to @1
|
||||
Renumbering block nexttext::@3 to nexttext::@2
|
||||
Adding NOP phi() at start of @begin
|
||||
Adding NOP phi() at start of @1
|
||||
Adding NOP phi() at start of @end
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
@begin: scope:[] from
|
||||
[0] phi()
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
[1] phi()
|
||||
[2] call main
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
[3] phi()
|
||||
main: scope:[main] from @1
|
||||
[4] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@4
|
||||
[5] (byte) main::i#5 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) main::i#1 )
|
||||
[5] (byte*) main::screen#4 ← phi( main/((byte*))(word/signed word/dword/signed dword) $400 main::@4/(byte*) main::screen#2 )
|
||||
[5] (byte) textid#11 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@4/(byte) textid#13 )
|
||||
[5] (byte*) main::text#2 ← phi( main/(byte*) 0 main::@4/(byte*) main::text#3 )
|
||||
[6] call nexttext
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1 main::@3
|
||||
[7] (byte*) main::screen#2 ← phi( main::@3/(byte*) main::screen#1 main::@1/(byte*) main::screen#4 )
|
||||
[7] (byte*) main::text#3 ← phi( main::@3/(byte*) main::text#1 main::@1/(byte*) main::text#2 )
|
||||
[8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@2
|
||||
[9] (byte) main::i#1 ← ++ (byte) main::i#5
|
||||
[10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@4
|
||||
[11] return
|
||||
to:@return
|
||||
main::@3: scope:[main] from main::@2
|
||||
[12] *((byte*) main::screen#2) ← *((byte*) main::text#3)
|
||||
[13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2
|
||||
[14] (byte*) main::text#1 ← ++ (byte*) main::text#3
|
||||
to:main::@2
|
||||
nexttext: scope:[nexttext] from main::@1
|
||||
[15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1
|
||||
[16] (byte) textid#13 ← ++ (byte) textid#11
|
||||
[17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1
|
||||
to:nexttext::@2
|
||||
nexttext::@2: scope:[nexttext] from nexttext
|
||||
[18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0
|
||||
to:nexttext::@return
|
||||
nexttext::@return: scope:[nexttext] from nexttext::@1 nexttext::@2
|
||||
[19] return
|
||||
to:@return
|
||||
nexttext::@1: scope:[nexttext] from nexttext
|
||||
[20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0
|
||||
to:nexttext::@return
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
(byte) main::i
|
||||
(byte) main::i#1 16.5
|
||||
(byte) main::i#5 3.142857142857143
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#1 101.0
|
||||
(byte*) main::screen#2 65.0
|
||||
(byte*) main::screen#4 11.0
|
||||
(byte*) main::text
|
||||
(byte*) main::text#1 202.0
|
||||
(byte*) main::text#2 11.0
|
||||
(byte*) main::text#3 70.99999999999999
|
||||
(void()) nexttext((byte**) nexttext::textp)
|
||||
(byte~) nexttext::$0 2.0
|
||||
(byte**) nexttext::textp
|
||||
(byte[]) text1
|
||||
(byte[]) text2
|
||||
(byte) textid
|
||||
(byte) textid#11 7.5
|
||||
(byte) textid#13 1.0
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::text#2 main::text#3 main::text#1 ]
|
||||
[ textid#11 textid#13 ]
|
||||
[ main::screen#4 main::screen#2 main::screen#1 ]
|
||||
[ main::i#5 main::i#1 ]
|
||||
Added variable nexttext::$0 to zero page equivalence class [ nexttext::$0 ]
|
||||
Complete equivalence classes
|
||||
[ main::text#2 main::text#3 main::text#1 ]
|
||||
[ textid#11 textid#13 ]
|
||||
[ main::screen#4 main::screen#2 main::screen#1 ]
|
||||
[ main::i#5 main::i#1 ]
|
||||
[ nexttext::$0 ]
|
||||
Allocated zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ]
|
||||
Allocated zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
Allocated zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ]
|
||||
Allocated zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
|
||||
Allocated zp ZP_BYTE:8 [ nexttext::$0 ]
|
||||
|
||||
INITIAL ASM
|
||||
//SEG0 File Comments
|
||||
// Tests pointer to pointer in a more complex setup
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label textid = 4
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
//SEG7 [4] phi from @1 to main [phi:@1->main]
|
||||
main_from_b1:
|
||||
jsr main
|
||||
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG9 @end
|
||||
bend:
|
||||
//SEG10 main
|
||||
main: {
|
||||
.label screen = 5
|
||||
.label text = 2
|
||||
.label i = 7
|
||||
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
b1_from_main:
|
||||
//SEG12 [5] phi (byte) main::i#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta i
|
||||
//SEG13 [5] phi (byte*) main::screen#4 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta screen
|
||||
lda #>$400
|
||||
sta screen+1
|
||||
//SEG14 [5] phi (byte) textid#11 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta textid
|
||||
//SEG15 [5] phi (byte*) main::text#2 = (byte*) 0 [phi:main->main::@1#3] -- pbuz1=pbuc1
|
||||
lda #<0
|
||||
sta text
|
||||
lda #>0
|
||||
sta text+1
|
||||
jmp b1
|
||||
//SEG16 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
|
||||
b1_from_b4:
|
||||
//SEG17 [5] phi (byte) main::i#5 = (byte) main::i#1 [phi:main::@4->main::@1#0] -- register_copy
|
||||
//SEG18 [5] phi (byte*) main::screen#4 = (byte*) main::screen#2 [phi:main::@4->main::@1#1] -- register_copy
|
||||
//SEG19 [5] phi (byte) textid#11 = (byte) textid#13 [phi:main::@4->main::@1#2] -- register_copy
|
||||
//SEG20 [5] phi (byte*) main::text#2 = (byte*) main::text#3 [phi:main::@4->main::@1#3] -- register_copy
|
||||
jmp b1
|
||||
//SEG21 main::@1
|
||||
b1:
|
||||
//SEG22 [6] call nexttext
|
||||
jsr nexttext
|
||||
//SEG23 [7] phi from main::@1 main::@3 to main::@2 [phi:main::@1/main::@3->main::@2]
|
||||
b2_from_b1:
|
||||
b2_from_b3:
|
||||
//SEG24 [7] phi (byte*) main::screen#2 = (byte*) main::screen#4 [phi:main::@1/main::@3->main::@2#0] -- register_copy
|
||||
//SEG25 [7] phi (byte*) main::text#3 = (byte*) main::text#2 [phi:main::@1/main::@3->main::@2#1] -- register_copy
|
||||
jmp b2
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 -- _deref_pbuz1_neq_vbuc1_then_la1
|
||||
ldy #0
|
||||
lda (text),y
|
||||
cmp #'@'
|
||||
bne b3
|
||||
jmp b4
|
||||
//SEG28 main::@4
|
||||
b4:
|
||||
//SEG29 [9] (byte) main::i#1 ← ++ (byte) main::i#5 -- vbuz1=_inc_vbuz1
|
||||
inc i
|
||||
//SEG30 [10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1 -- vbuz1_neq_vbuc1_then_la1
|
||||
lda #$15
|
||||
cmp i
|
||||
bne b1_from_b4
|
||||
jmp breturn
|
||||
//SEG31 main::@return
|
||||
breturn:
|
||||
//SEG32 [11] return
|
||||
rts
|
||||
//SEG33 main::@3
|
||||
b3:
|
||||
//SEG34 [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) -- _deref_pbuz1=_deref_pbuz2
|
||||
ldy #0
|
||||
lda (text),y
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
//SEG35 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
|
||||
inc screen
|
||||
bne !+
|
||||
inc screen+1
|
||||
!:
|
||||
//SEG36 [14] (byte*) main::text#1 ← ++ (byte*) main::text#3 -- pbuz1=_inc_pbuz1
|
||||
inc text
|
||||
bne !+
|
||||
inc text+1
|
||||
!:
|
||||
jmp b2_from_b3
|
||||
}
|
||||
//SEG37 nexttext
|
||||
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
|
||||
nexttext: {
|
||||
.label textp = main.text
|
||||
.label _0 = 8
|
||||
//SEG38 [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuz1=vbuz2_band_vbuc1
|
||||
lda #1
|
||||
and textid
|
||||
sta _0
|
||||
//SEG39 [16] (byte) textid#13 ← ++ (byte) textid#11 -- vbuz1=_inc_vbuz1
|
||||
inc textid
|
||||
//SEG40 [17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1 -- vbuz1_eq_0_then_la1
|
||||
lda _0
|
||||
cmp #0
|
||||
beq b1
|
||||
jmp b2
|
||||
//SEG41 nexttext::@2
|
||||
b2:
|
||||
//SEG42 [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 -- _deref_pptc1=pbuc2
|
||||
lda #<text2
|
||||
sta textp
|
||||
lda #>text2
|
||||
sta textp+1
|
||||
jmp breturn
|
||||
//SEG43 nexttext::@return
|
||||
breturn:
|
||||
//SEG44 [19] return
|
||||
rts
|
||||
//SEG45 nexttext::@1
|
||||
b1:
|
||||
//SEG46 [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 -- _deref_pptc1=pbuc2
|
||||
lda #<text1
|
||||
sta textp
|
||||
lda #>text1
|
||||
sta textp+1
|
||||
jmp breturn
|
||||
}
|
||||
text1: .text "camelot @"
|
||||
text2: .text "rex @"
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
|
||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
|
||||
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
Statement [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
|
||||
Statement [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ textid#11 nexttext::$0 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#11 nexttext::$0 ] ) always clobbers reg byte a
|
||||
Statement [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
|
||||
Statement [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
|
||||
Statement [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
|
||||
Statement [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) [ main::i#5 main::text#3 textid#13 main::screen#2 ] ( main:2 [ main::i#5 main::text#3 textid#13 main::screen#2 ] ) always clobbers reg byte a reg byte y
|
||||
Statement [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ textid#11 nexttext::$0 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#11 nexttext::$0 ] ) always clobbers reg byte a
|
||||
Statement [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
|
||||
Statement [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 [ textid#13 ] ( main:2::nexttext:6 [ main::text#2 main::screen#4 main::i#5 textid#13 ] ) always clobbers reg byte a
|
||||
Potential registers zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ] : zp ZP_WORD:2 ,
|
||||
Potential registers zp ZP_BYTE:4 [ textid#11 textid#13 ] : zp ZP_BYTE:4 , reg byte x ,
|
||||
Potential registers zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ] : zp ZP_WORD:5 ,
|
||||
Potential registers zp ZP_BYTE:7 [ main::i#5 main::i#1 ] : zp ZP_BYTE:7 , reg byte x ,
|
||||
Potential registers zp ZP_BYTE:8 [ nexttext::$0 ] : zp ZP_BYTE:8 , reg byte a , reg byte x , reg byte y ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 284: zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ] 177: zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ] 19.64: zp ZP_BYTE:7 [ main::i#5 main::i#1 ]
|
||||
Uplift Scope [] 8.5: zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
Uplift Scope [nexttext] 2: zp ZP_BYTE:8 [ nexttext::$0 ]
|
||||
|
||||
Uplifting [main] best 6712 combination zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ] zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ] reg byte x [ main::i#5 main::i#1 ]
|
||||
Uplifting [] best 6712 combination zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
Uplifting [nexttext] best 6706 combination reg byte a [ nexttext::$0 ]
|
||||
Attempting to uplift remaining variables inzp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
Uplifting [] best 6706 combination zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
//SEG0 File Comments
|
||||
// Tests pointer to pointer in a more complex setup
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(bbegin)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label textid = 4
|
||||
//SEG3 @begin
|
||||
bbegin:
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
b1_from_bbegin:
|
||||
jmp b1
|
||||
//SEG5 @1
|
||||
b1:
|
||||
//SEG6 [2] call main
|
||||
//SEG7 [4] phi from @1 to main [phi:@1->main]
|
||||
main_from_b1:
|
||||
jsr main
|
||||
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
|
||||
bend_from_b1:
|
||||
jmp bend
|
||||
//SEG9 @end
|
||||
bend:
|
||||
//SEG10 main
|
||||
main: {
|
||||
.label screen = 5
|
||||
.label text = 2
|
||||
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
b1_from_main:
|
||||
//SEG12 [5] phi (byte) main::i#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
//SEG13 [5] phi (byte*) main::screen#4 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta screen
|
||||
lda #>$400
|
||||
sta screen+1
|
||||
//SEG14 [5] phi (byte) textid#11 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuz1=vbuc1
|
||||
lda #0
|
||||
sta textid
|
||||
//SEG15 [5] phi (byte*) main::text#2 = (byte*) 0 [phi:main->main::@1#3] -- pbuz1=pbuc1
|
||||
lda #<0
|
||||
sta text
|
||||
lda #>0
|
||||
sta text+1
|
||||
jmp b1
|
||||
//SEG16 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
|
||||
b1_from_b4:
|
||||
//SEG17 [5] phi (byte) main::i#5 = (byte) main::i#1 [phi:main::@4->main::@1#0] -- register_copy
|
||||
//SEG18 [5] phi (byte*) main::screen#4 = (byte*) main::screen#2 [phi:main::@4->main::@1#1] -- register_copy
|
||||
//SEG19 [5] phi (byte) textid#11 = (byte) textid#13 [phi:main::@4->main::@1#2] -- register_copy
|
||||
//SEG20 [5] phi (byte*) main::text#2 = (byte*) main::text#3 [phi:main::@4->main::@1#3] -- register_copy
|
||||
jmp b1
|
||||
//SEG21 main::@1
|
||||
b1:
|
||||
//SEG22 [6] call nexttext
|
||||
jsr nexttext
|
||||
//SEG23 [7] phi from main::@1 main::@3 to main::@2 [phi:main::@1/main::@3->main::@2]
|
||||
b2_from_b1:
|
||||
b2_from_b3:
|
||||
//SEG24 [7] phi (byte*) main::screen#2 = (byte*) main::screen#4 [phi:main::@1/main::@3->main::@2#0] -- register_copy
|
||||
//SEG25 [7] phi (byte*) main::text#3 = (byte*) main::text#2 [phi:main::@1/main::@3->main::@2#1] -- register_copy
|
||||
jmp b2
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 -- _deref_pbuz1_neq_vbuc1_then_la1
|
||||
ldy #0
|
||||
lda (text),y
|
||||
cmp #'@'
|
||||
bne b3
|
||||
jmp b4
|
||||
//SEG28 main::@4
|
||||
b4:
|
||||
//SEG29 [9] (byte) main::i#1 ← ++ (byte) main::i#5 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG30 [10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$15
|
||||
bne b1_from_b4
|
||||
jmp breturn
|
||||
//SEG31 main::@return
|
||||
breturn:
|
||||
//SEG32 [11] return
|
||||
rts
|
||||
//SEG33 main::@3
|
||||
b3:
|
||||
//SEG34 [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) -- _deref_pbuz1=_deref_pbuz2
|
||||
ldy #0
|
||||
lda (text),y
|
||||
ldy #0
|
||||
sta (screen),y
|
||||
//SEG35 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
|
||||
inc screen
|
||||
bne !+
|
||||
inc screen+1
|
||||
!:
|
||||
//SEG36 [14] (byte*) main::text#1 ← ++ (byte*) main::text#3 -- pbuz1=_inc_pbuz1
|
||||
inc text
|
||||
bne !+
|
||||
inc text+1
|
||||
!:
|
||||
jmp b2_from_b3
|
||||
}
|
||||
//SEG37 nexttext
|
||||
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
|
||||
nexttext: {
|
||||
.label textp = main.text
|
||||
//SEG38 [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
|
||||
lda #1
|
||||
and textid
|
||||
//SEG39 [16] (byte) textid#13 ← ++ (byte) textid#11 -- vbuz1=_inc_vbuz1
|
||||
inc textid
|
||||
//SEG40 [17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1 -- vbuaa_eq_0_then_la1
|
||||
cmp #0
|
||||
beq b1
|
||||
jmp b2
|
||||
//SEG41 nexttext::@2
|
||||
b2:
|
||||
//SEG42 [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 -- _deref_pptc1=pbuc2
|
||||
lda #<text2
|
||||
sta textp
|
||||
lda #>text2
|
||||
sta textp+1
|
||||
jmp breturn
|
||||
//SEG43 nexttext::@return
|
||||
breturn:
|
||||
//SEG44 [19] return
|
||||
rts
|
||||
//SEG45 nexttext::@1
|
||||
b1:
|
||||
//SEG46 [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 -- _deref_pptc1=pbuc2
|
||||
lda #<text1
|
||||
sta textp
|
||||
lda #>text1
|
||||
sta textp+1
|
||||
jmp breturn
|
||||
}
|
||||
text1: .text "camelot @"
|
||||
text2: .text "rex @"
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp bend
|
||||
Removing instruction jmp b1
|
||||
Removing instruction jmp b2
|
||||
Removing instruction jmp b4
|
||||
Removing instruction jmp breturn
|
||||
Removing instruction jmp b2
|
||||
Removing instruction jmp breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Replacing instruction lda #0 with TXA
|
||||
Removing instruction lda #<0
|
||||
Removing instruction lda #>0
|
||||
Removing instruction ldy #0
|
||||
Succesful ASM optimization Pass5UnnecesaryLoadElimination
|
||||
Replacing label b1_from_b4 with b1
|
||||
Replacing label b2_from_b3 with b2
|
||||
Removing instruction b1_from_bbegin:
|
||||
Removing instruction b1:
|
||||
Removing instruction main_from_b1:
|
||||
Removing instruction bend_from_b1:
|
||||
Removing instruction b1_from_b4:
|
||||
Removing instruction b2_from_b1:
|
||||
Removing instruction b2_from_b3:
|
||||
Succesful ASM optimization Pass5RedundantLabelElimination
|
||||
Removing instruction bend:
|
||||
Removing instruction b1_from_main:
|
||||
Removing instruction b4:
|
||||
Removing instruction breturn:
|
||||
Removing instruction b2:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
Updating BasicUpstart to call main directly
|
||||
Removing instruction jsr main
|
||||
Succesful ASM optimization Pass5SkipBegin
|
||||
Removing instruction jmp b1
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction bbegin:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 16.5
|
||||
(byte) main::i#5 reg byte x 3.142857142857143
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#1 screen zp ZP_WORD:5 101.0
|
||||
(byte*) main::screen#2 screen zp ZP_WORD:5 65.0
|
||||
(byte*) main::screen#4 screen zp ZP_WORD:5 11.0
|
||||
(byte*) main::text
|
||||
(byte*) main::text#1 text zp ZP_WORD:2 202.0
|
||||
(byte*) main::text#2 text zp ZP_WORD:2 11.0
|
||||
(byte*) main::text#3 text zp ZP_WORD:2 70.99999999999999
|
||||
(void()) nexttext((byte**) nexttext::textp)
|
||||
(byte~) nexttext::$0 reg byte a 2.0
|
||||
(label) nexttext::@1
|
||||
(label) nexttext::@2
|
||||
(label) nexttext::@return
|
||||
(byte**) nexttext::textp
|
||||
(const byte**) nexttext::textp#0 textp = &(byte*) main::text#2
|
||||
(byte[]) text1
|
||||
(const byte[]) text1#0 text1 = (string) "camelot @"
|
||||
(byte[]) text2
|
||||
(const byte[]) text2#0 text2 = (string) "rex @"
|
||||
(byte) textid
|
||||
(byte) textid#11 textid zp ZP_BYTE:4 7.5
|
||||
(byte) textid#13 textid zp ZP_BYTE:4 1.0
|
||||
|
||||
zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ]
|
||||
zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ]
|
||||
reg byte x [ main::i#5 main::i#1 ]
|
||||
reg byte a [ nexttext::$0 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 5758
|
||||
|
||||
//SEG0 File Comments
|
||||
// Tests pointer to pointer in a more complex setup
|
||||
//SEG1 Basic Upstart
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
//SEG2 Global Constants & labels
|
||||
.label textid = 4
|
||||
//SEG3 @begin
|
||||
//SEG4 [1] phi from @begin to @1 [phi:@begin->@1]
|
||||
//SEG5 @1
|
||||
//SEG6 [2] call main
|
||||
//SEG7 [4] phi from @1 to main [phi:@1->main]
|
||||
//SEG8 [3] phi from @1 to @end [phi:@1->@end]
|
||||
//SEG9 @end
|
||||
//SEG10 main
|
||||
main: {
|
||||
.label screen = 5
|
||||
.label text = 2
|
||||
//SEG11 [5] phi from main to main::@1 [phi:main->main::@1]
|
||||
//SEG12 [5] phi (byte) main::i#5 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1
|
||||
ldx #0
|
||||
//SEG13 [5] phi (byte*) main::screen#4 = ((byte*))(word/signed word/dword/signed dword) $400 [phi:main->main::@1#1] -- pbuz1=pbuc1
|
||||
lda #<$400
|
||||
sta screen
|
||||
lda #>$400
|
||||
sta screen+1
|
||||
//SEG14 [5] phi (byte) textid#11 = (byte/signed byte/word/signed word/dword/signed dword) 0 [phi:main->main::@1#2] -- vbuz1=vbuc1
|
||||
txa
|
||||
sta textid
|
||||
//SEG15 [5] phi (byte*) main::text#2 = (byte*) 0 [phi:main->main::@1#3] -- pbuz1=pbuc1
|
||||
sta text
|
||||
sta text+1
|
||||
//SEG16 [5] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
|
||||
//SEG17 [5] phi (byte) main::i#5 = (byte) main::i#1 [phi:main::@4->main::@1#0] -- register_copy
|
||||
//SEG18 [5] phi (byte*) main::screen#4 = (byte*) main::screen#2 [phi:main::@4->main::@1#1] -- register_copy
|
||||
//SEG19 [5] phi (byte) textid#11 = (byte) textid#13 [phi:main::@4->main::@1#2] -- register_copy
|
||||
//SEG20 [5] phi (byte*) main::text#2 = (byte*) main::text#3 [phi:main::@4->main::@1#3] -- register_copy
|
||||
//SEG21 main::@1
|
||||
b1:
|
||||
//SEG22 [6] call nexttext
|
||||
jsr nexttext
|
||||
//SEG23 [7] phi from main::@1 main::@3 to main::@2 [phi:main::@1/main::@3->main::@2]
|
||||
//SEG24 [7] phi (byte*) main::screen#2 = (byte*) main::screen#4 [phi:main::@1/main::@3->main::@2#0] -- register_copy
|
||||
//SEG25 [7] phi (byte*) main::text#3 = (byte*) main::text#2 [phi:main::@1/main::@3->main::@2#1] -- register_copy
|
||||
//SEG26 main::@2
|
||||
b2:
|
||||
//SEG27 [8] if(*((byte*) main::text#3)!=(byte) '@') goto main::@3 -- _deref_pbuz1_neq_vbuc1_then_la1
|
||||
ldy #0
|
||||
lda (text),y
|
||||
cmp #'@'
|
||||
bne b3
|
||||
//SEG28 main::@4
|
||||
//SEG29 [9] (byte) main::i#1 ← ++ (byte) main::i#5 -- vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//SEG30 [10] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) $15) goto main::@1 -- vbuxx_neq_vbuc1_then_la1
|
||||
cpx #$15
|
||||
bne b1
|
||||
//SEG31 main::@return
|
||||
//SEG32 [11] return
|
||||
rts
|
||||
//SEG33 main::@3
|
||||
b3:
|
||||
//SEG34 [12] *((byte*) main::screen#2) ← *((byte*) main::text#3) -- _deref_pbuz1=_deref_pbuz2
|
||||
ldy #0
|
||||
lda (text),y
|
||||
sta (screen),y
|
||||
//SEG35 [13] (byte*) main::screen#1 ← ++ (byte*) main::screen#2 -- pbuz1=_inc_pbuz1
|
||||
inc screen
|
||||
bne !+
|
||||
inc screen+1
|
||||
!:
|
||||
//SEG36 [14] (byte*) main::text#1 ← ++ (byte*) main::text#3 -- pbuz1=_inc_pbuz1
|
||||
inc text
|
||||
bne !+
|
||||
inc text+1
|
||||
!:
|
||||
jmp b2
|
||||
}
|
||||
//SEG37 nexttext
|
||||
// Choose the next text to show - by updating the text pointer pointed to by the passed pointer to a pointer
|
||||
nexttext: {
|
||||
.label textp = main.text
|
||||
//SEG38 [15] (byte~) nexttext::$0 ← (byte) textid#11 & (byte/signed byte/word/signed word/dword/signed dword) 1 -- vbuaa=vbuz1_band_vbuc1
|
||||
lda #1
|
||||
and textid
|
||||
//SEG39 [16] (byte) textid#13 ← ++ (byte) textid#11 -- vbuz1=_inc_vbuz1
|
||||
inc textid
|
||||
//SEG40 [17] if((byte~) nexttext::$0==(byte/signed byte/word/signed word/dword/signed dword) 0) goto nexttext::@1 -- vbuaa_eq_0_then_la1
|
||||
cmp #0
|
||||
beq b1
|
||||
//SEG41 nexttext::@2
|
||||
//SEG42 [18] *((const byte**) nexttext::textp#0) ← (const byte[]) text2#0 -- _deref_pptc1=pbuc2
|
||||
lda #<text2
|
||||
sta textp
|
||||
lda #>text2
|
||||
sta textp+1
|
||||
//SEG43 nexttext::@return
|
||||
breturn:
|
||||
//SEG44 [19] return
|
||||
rts
|
||||
//SEG45 nexttext::@1
|
||||
b1:
|
||||
//SEG46 [20] *((const byte**) nexttext::textp#0) ← (const byte[]) text1#0 -- _deref_pptc1=pbuc2
|
||||
lda #<text1
|
||||
sta textp
|
||||
lda #>text1
|
||||
sta textp+1
|
||||
jmp breturn
|
||||
}
|
||||
text1: .text "camelot @"
|
||||
text2: .text "rex @"
|
||||
|
40
src/test/ref/pointer-pointer-2.sym
Normal file
40
src/test/ref/pointer-pointer-2.sym
Normal file
@ -0,0 +1,40 @@
|
||||
(label) @1
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 16.5
|
||||
(byte) main::i#5 reg byte x 3.142857142857143
|
||||
(byte*) main::screen
|
||||
(byte*) main::screen#1 screen zp ZP_WORD:5 101.0
|
||||
(byte*) main::screen#2 screen zp ZP_WORD:5 65.0
|
||||
(byte*) main::screen#4 screen zp ZP_WORD:5 11.0
|
||||
(byte*) main::text
|
||||
(byte*) main::text#1 text zp ZP_WORD:2 202.0
|
||||
(byte*) main::text#2 text zp ZP_WORD:2 11.0
|
||||
(byte*) main::text#3 text zp ZP_WORD:2 70.99999999999999
|
||||
(void()) nexttext((byte**) nexttext::textp)
|
||||
(byte~) nexttext::$0 reg byte a 2.0
|
||||
(label) nexttext::@1
|
||||
(label) nexttext::@2
|
||||
(label) nexttext::@return
|
||||
(byte**) nexttext::textp
|
||||
(const byte**) nexttext::textp#0 textp = &(byte*) main::text#2
|
||||
(byte[]) text1
|
||||
(const byte[]) text1#0 text1 = (string) "camelot @"
|
||||
(byte[]) text2
|
||||
(const byte[]) text2#0 text2 = (string) "rex @"
|
||||
(byte) textid
|
||||
(byte) textid#11 textid zp ZP_BYTE:4 7.5
|
||||
(byte) textid#13 textid zp ZP_BYTE:4 1.0
|
||||
|
||||
zp ZP_WORD:2 [ main::text#2 main::text#3 main::text#1 ]
|
||||
zp ZP_BYTE:4 [ textid#11 textid#13 ]
|
||||
zp ZP_WORD:5 [ main::screen#4 main::screen#2 main::screen#1 ]
|
||||
reg byte x [ main::i#5 main::i#1 ]
|
||||
reg byte a [ nexttext::$0 ]
|
@ -345,16 +345,18 @@ setByte: {
|
||||
}
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [17] *((byte*) setByte::ptr#3) ← (byte) setByte::b#3 [ main::b1#0 main::b2#0 main::b3#0 ] ( main:2::setByte:7 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:9 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:11 [ main::b1#0 main::b2#0 main::b3#0 ] ) always clobbers reg byte y
|
||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:5 [ main::b1#0 ]
|
||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:6 [ main::b2#0 ]
|
||||
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:7 [ main::b3#0 ]
|
||||
Statement [4] (byte) main::b1#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::b1#0 ] ( main:2 [ main::b1#0 ] ) always clobbers reg byte a
|
||||
Statement [5] (byte) main::b2#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::b1#0 main::b2#0 ] ( main:2 [ main::b1#0 main::b2#0 ] ) always clobbers reg byte a
|
||||
Statement [6] (byte) main::b3#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::b1#0 main::b2#0 main::b3#0 ] ( main:2 [ main::b1#0 main::b2#0 main::b3#0 ] ) always clobbers reg byte a
|
||||
Statement [12] *((const byte*) main::SCREEN#0) ← (byte) main::b1#0 [ main::b2#0 main::b3#0 ] ( main:2 [ main::b2#0 main::b3#0 ] ) always clobbers reg byte a
|
||||
Statement [13] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 1) ← (byte) main::b2#0 [ main::b3#0 ] ( main:2 [ main::b3#0 ] ) always clobbers reg byte a
|
||||
Statement [14] *((const byte*) main::SCREEN#0+(byte/signed byte/word/signed word/dword/signed dword) 2) ← (byte) main::b3#0 [ ] ( main:2 [ ] ) always clobbers reg byte a
|
||||
Statement [17] *((byte*) setByte::ptr#3) ← (byte) setByte::b#3 [ main::b1#0 main::b2#0 main::b3#0 ] ( main:2::setByte:7 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:9 [ main::b1#0 main::b2#0 main::b3#0 ] main:2::setByte:11 [ main::b1#0 main::b2#0 main::b3#0 ] ) always clobbers reg byte y
|
||||
Potential registers zp ZP_BYTE:2 [ setByte::b#3 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp ZP_WORD:3 [ setByte::ptr#3 ] : zp ZP_WORD:3 ,
|
||||
Potential registers zp ZP_BYTE:5 [ main::b1#0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x ,
|
||||
Potential registers zp ZP_BYTE:6 [ main::b2#0 ] : zp ZP_BYTE:6 , reg byte a , reg byte x ,
|
||||
Potential registers zp ZP_BYTE:7 [ main::b3#0 ] : zp ZP_BYTE:7 , reg byte a , reg byte x ,
|
||||
Potential registers zp ZP_BYTE:5 [ main::b1#0 ] : zp ZP_BYTE:5 ,
|
||||
Potential registers zp ZP_BYTE:6 [ main::b2#0 ] : zp ZP_BYTE:6 ,
|
||||
Potential registers zp ZP_BYTE:7 [ main::b3#0 ] : zp ZP_BYTE:7 ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [setByte] 2: zp ZP_BYTE:2 [ setByte::b#3 ] 2: zp ZP_WORD:3 [ setByte::ptr#3 ]
|
||||
|
Loading…
Reference in New Issue
Block a user