1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-21 02:24:34 +00:00

Working on fixing void pointers #186

This commit is contained in:
jespergravgaard 2019-06-20 22:39:45 +02:00
parent d3e21133fa
commit 0a4ef77056
23 changed files with 1676 additions and 56 deletions

View File

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

View File

@ -181,12 +181,16 @@ public class Compiler {
new Pass1AssertNoLValueIntermediate(program).execute();
new Pass1PointerSizeofFix(program).execute(); // After this point in the code all pointer math is byte-based
new PassNSizeOfSimplification(program).execute(); // Needed to eliminate sizeof() referencing pointer value variables
//new PassNAddTypeConversionAssignment(program).execute();
//new Pass1AssertProcedureCallParameters(program).execute();
new Pass1UnwindStructValues(program).execute();
new PassNStructPointerRewriting(program).execute();
new PassNAddBooleanCasts(program).execute();
new PassNAddTypeConversionAssignment(program).execute();
//new Pass1AssertProcedureCallParameters(program).execute();
new Pass1EarlyConstantIdentification(program).execute();
new Pass1ProcedureInline(program).execute();

View File

@ -358,6 +358,8 @@ public class AsmFragmentInstanceSpecFactory {
return "pds";
} else if(SymbolType.BOOLEAN.equals(elementType)) {
return "pbo";
} else if(SymbolType.VOID.equals(elementType)) {
return "pvo";
} else if(elementType instanceof SymbolTypeProcedure) {
return "ppr";
} else if(elementType instanceof SymbolTypePointer) {

View File

@ -29,7 +29,7 @@ public class OperatorDivide extends OperatorBinary {
@Override
public SymbolType inferType(SymbolType left, SymbolType right) {
if(left instanceof SymbolTypePointer) {
if(SymbolType.BYTE.equals(right) || SymbolType.WORD.equals(right) || SymbolType.NUMBER.equals(right)|| SymbolType.UNUMBER.equals(right)|| SymbolType.SNUMBER.equals(right)) {
if(SymbolType.isInteger(right)) {
return left;
} else {
throw new NoMatchingType("Cannot divide pointer by "+right.toString());

View File

@ -1,7 +1,10 @@
package dk.camelot64.kickc.model.operators;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.types.*;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.types.SymbolType;
import dk.camelot64.kickc.model.types.SymbolTypeConversion;
import dk.camelot64.kickc.model.types.SymbolTypeInteger;
import dk.camelot64.kickc.model.types.SymbolTypePointer;
import dk.camelot64.kickc.model.values.ConstantChar;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantLiteral;
@ -25,7 +28,7 @@ public class OperatorMinus extends OperatorBinary {
} else if(left instanceof ConstantChar && right instanceof ConstantInteger) {
return new ConstantInteger(((ConstantChar) left).getChar() - ((ConstantInteger) right).getInteger());
}
throw new CompileError("Calculation not implemented " + left + " " + getOperator() + " " + right);
throw new InternalError("Calculation not implemented " + left + " " + getOperator() + " " + right);
}
@Override
@ -40,7 +43,7 @@ public class OperatorMinus extends OperatorBinary {
if(SymbolType.isInteger(type1) && SymbolType.isInteger(type2)) {
return SymbolTypeConversion.convertedMathType((SymbolTypeInteger) type1, (SymbolTypeInteger) type2);
}
throw new RuntimeException("Type inference case not handled " + type1 + " " + getOperator() + " " + type2);
throw new InternalError("Type inference case not handled " + type1 + " " + getOperator() + " " + type2);
}
}

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model.operators;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.types.*;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.ConstantLiteral;
@ -17,7 +17,7 @@ public class OperatorMultiply extends OperatorBinary {
if(left instanceof ConstantInteger && right instanceof ConstantInteger) {
return new ConstantInteger(((ConstantInteger) left).getInteger() * ((ConstantInteger) right).getInteger());
}
throw new CompileError("Calculation not implemented " + left + " " + getOperator() + " " + right);
throw new ConstantNotLiteral("Not literal "+left.toString()+"*"+right.toString());
}
@Override

View File

@ -103,15 +103,12 @@ public class SymbolTypeConversion {
if(rightType instanceof SymbolTypePointer) rightType = SymbolType.WORD;
// Identify which of the two operands is a number and which is a fixed type
RValue numberVal;
SymbolTypeIntegerFixed fixedType;
if(SymbolType.NUMBER.equals(leftType) && SymbolType.isInteger(rightType)) {
// Left is the number type - right is the fixed type
numberVal = left;
fixedType = (SymbolTypeIntegerFixed) rightType;
} else if(SymbolType.NUMBER.equals(rightType) && SymbolType.isInteger(leftType)) {
// Right is the number type - left is the fixed type
numberVal = right;
fixedType = (SymbolTypeIntegerFixed) leftType;
} else {
// Binary operator combining number and non-integer
@ -187,6 +184,8 @@ public class SymbolTypeConversion {
* @return true if the types match up
*/
public static boolean assignmentTypeMatch(SymbolType lValueType, SymbolType rValueType) {
if(SymbolType.VAR.equals(rValueType))
return true;
if(lValueType.equals(rValueType))
return true;
if(SymbolType.WORD.equals(lValueType) && SymbolType.BYTE.equals(rValueType))

View File

@ -2,6 +2,7 @@ package dk.camelot64.kickc.model.types;
import dk.camelot64.kickc.fragment.AsmFragmentInstanceSpec;
import dk.camelot64.kickc.model.CompileError;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.operators.OperatorBinary;
import dk.camelot64.kickc.model.operators.OperatorUnary;
@ -43,7 +44,7 @@ public class SymbolTypeInference {
SymbolType rightType = inferType(symbols, constBin.getRight());
return constBin.getOperator().inferType(leftType, rightType);
} else if(rValue instanceof ValueList) {
type = inferTypeList(symbols, (ValueList) rValue);
return SymbolType.VAR;
} else if(rValue instanceof PointerDereference) {
SymbolType pointerType = inferType(symbols, ((PointerDereference) rValue).getPointer());
if(pointerType instanceof SymbolTypePointer) {
@ -51,7 +52,7 @@ public class SymbolTypeInference {
} else if(pointerType.equals(SymbolType.STRING)) {
return SymbolType.BYTE;
} else {
throw new RuntimeException("Cannot infer pointer element type from pointer type " + pointerType);
throw new InternalError("Cannot infer pointer element type from pointer type " + pointerType);
}
} else if(rValue instanceof ConstantArrayList) {
return new SymbolTypeArray(((ConstantArrayList) rValue).getElementType());
@ -97,7 +98,7 @@ public class SymbolTypeInference {
SymbolType rightType = inferType(symbols, rValue2);
rValueType = ((OperatorBinary) assignment.getOperator()).inferType(leftType, rightType);
} else {
throw new CompileError("Cannot infer type of " + assignment.toString());
throw new InternalError("Cannot infer type of " + assignment.toString());
}
return rValueType;
} else if(rValue instanceof StructMemberRef) {
@ -119,35 +120,9 @@ public class SymbolTypeInference {
return ((StructUnwoundPlaceholder) rValue).getTypeStruct();
}
if(type == null) {
throw new RuntimeException("Cannot infer type for " + rValue.toString());
throw new InternalError("Cannot infer type for " + rValue.toString());
}
return type;
}
private static SymbolType inferTypeList(ProgramScope symbols, ValueList list) {
SymbolType elmType = null;
for(RValue elm : list.getList()) {
SymbolType type = inferType(symbols, elm);
if(elmType == null) {
elmType = type;
} else {
if(!elmType.equals(type)) {
if(SymbolType.NUMBER.equals(elmType) && SymbolType.isInteger(type)) {
elmType = SymbolType.NUMBER;
} else if(SymbolType.isInteger(elmType) && SymbolType.NUMBER.equals(type)) {
elmType = SymbolType.NUMBER;
} else {
throw new CompileError("Array element has type mismatch "+elm.toString() + " not matching type " + elmType.getTypeName());
}
}
}
}
if(elmType != null) {
long size = list.getList().size();
return new SymbolTypeArray(elmType, new ConstantInteger(size, size<256?SymbolType.BYTE:SymbolType.WORD));
} else {
throw new RuntimeException("Cannot infer list element type " + list.toString());
}
}
}

View File

@ -1,6 +1,6 @@
package dk.camelot64.kickc.model.types;
/** Integer type marker interface. */
public interface SymbolTypeInteger extends SymbolType {
public interface SymbolTypeInteger extends SymbolType {
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.operators.OperatorBinary;
import dk.camelot64.kickc.model.operators.OperatorUnary;
@ -98,7 +99,7 @@ public class Pass2ConstantRValueConsolidation extends Pass2SsaOptimization {
} else {
if(!listType.equals(elmType)) {
// No overlap between list type and element type
throw new RuntimeException("Array type " + listType + " does not match element type " + elmType + ". Array: " + valueList.toString(getProgram()));
throw new InternalError("Array type " + listType + " does not match element type " + elmType + ". Array: " + valueList.toString(getProgram()));
}
}
elements.add(constantValue);

View File

@ -4,9 +4,10 @@ import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramExpressionBinary;
import dk.camelot64.kickc.model.iterator.ProgramExpressionIterator;
import dk.camelot64.kickc.model.types.*;
import dk.camelot64.kickc.model.values.ConstantInteger;
import dk.camelot64.kickc.model.values.RValue;
import dk.camelot64.kickc.model.values.ValueList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@ -29,8 +30,7 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
RValue right = binary.getRight();
SymbolType leftType = SymbolTypeInference.inferType(getProgram().getScope(), left);
SymbolType rightType = SymbolTypeInference.inferType(getProgram().getScope(), right);
if(!SymbolTypeConversion.assignmentTypeMatch(leftType, rightType)) {
if(!SymbolTypeConversion.assignmentTypeMatch(leftType, rightType) || SymbolType.VAR.equals(rightType)) {
// Assigning a pointer from an unsigned word
if(programExpression instanceof ProgramExpressionBinary.ProgramExpressionBinaryAssignmentLValue) {
if((leftType instanceof SymbolTypePointer) && SymbolType.isInteger(rightType)) {
@ -45,19 +45,19 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
getLog().append("Adding pointer type conversion cast to void pointer (" + leftType + ") " + binary.getRight().toString() + " in " + currentStmt.toString(getProgram(), false));
binary.addRightCast(leftType, stmtIt, currentBlock.getScope(), getScope());
modified.set(true);
} else if(SymbolType.WORD.equals(leftType) && isLiteralWordCandidate(rightType)) {
} else if(SymbolType.WORD.equals(leftType) && isLiteralWordCandidate(right)) {
// Detect word literal constructor
SymbolType conversionType = SymbolType.WORD;
getLog().append("Identified literal word (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false)));
binary.addRightCast(conversionType, stmtIt, currentBlock == null ? null : currentBlock.getScope(), getScope());
modified.set(true);
} else if(leftType instanceof SymbolTypePointer && isLiteralWordCandidate(rightType)) {
} else if(leftType instanceof SymbolTypePointer && !(leftType instanceof SymbolTypeArray) && isLiteralWordCandidate(right)) {
// Detect word literal constructor
SymbolType conversionType = SymbolType.WORD;
getLog().append("Identified literal word (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false)));
binary.addRightCast(conversionType, stmtIt, currentBlock == null ? null : currentBlock.getScope(), getScope());
modified.set(true);
} else if(SymbolType.DWORD.equals(leftType) && isLiteralWordCandidate(rightType)) {
} else if(SymbolType.DWORD.equals(leftType) && isLiteralWordCandidate(right)) {
// Detect dword literal constructor
SymbolType conversionType = SymbolType.DWORD;
getLog().append("Identified literal word (" + conversionType + ") " + binary.getRight().toString() + " in " + (currentStmt == null ? "" : currentStmt.toString(getProgram(), false)));
@ -72,12 +72,18 @@ public class PassNAddTypeConversionAssignment extends Pass2SsaOptimization {
return modified.get();
}
public static boolean isLiteralWordCandidate(SymbolType rightType) {
if(rightType instanceof SymbolTypeArray) {
SymbolTypeArray rightArray = (SymbolTypeArray) rightType;
if(new ConstantInteger(2L, SymbolType.BYTE).equals(rightArray.getSize()))
if(SymbolType.isInteger(rightArray.getElementType()))
return true;
private boolean isLiteralWordCandidate(RValue rValue) {
if(rValue instanceof ValueList) {
List<RValue> list = ((ValueList) rValue).getList();
if(list.size() == 2) {
for(RValue elm : list) {
if(!SymbolType.isInteger(SymbolTypeInference.inferType(getProgram().getScope(), elm))) {
return false;
}
}
// Two integer elements
return true;
}
}
return false;
}

View File

@ -36,7 +36,24 @@ public class TestPrograms {
}
@Test
public void testPointerVoid() throws IOException, URISyntaxException {
public void testCallParameterAutocast() throws IOException, URISyntaxException {
compileAndCompare("call-parameter-autocast", log());
}
/** Awaiting type system fix for void pointers
@Test
public void testPointerVoid2() throws IOException, URISyntaxException {
compileAndCompare("pointer-void-2", log());
}
*/
@Test
public void testPointerVoid1() throws IOException, URISyntaxException {
compileAndCompare("pointer-void-1");
}
@Test
public void testPointerVoid0() throws IOException, URISyntaxException {
compileAndCompare("pointer-void-0");
}

View File

@ -0,0 +1,15 @@
// Test auto-casting of call-parameters
void main() {
word w = 0x1234;
print(0x1234);
print(w);
print( {0x12,0x34} );
}
const word* SCREEN = 0x0400;
byte idx = 0;
void print(word w) {
SCREEN[idx++] = w;
}

View File

@ -0,0 +1,20 @@
// Test simple void pointer - void pointer function
void main() {
dword d = 0x12345678;
word w = 0x1234;
byte b = 0x12;
void* vb = &b;
void* vw = &w;
void* vd = &d;
print(vb);
print(vw);
print(vd);
}
const byte* SCREEN = 0x0400;
byte idx = 0;
void print(void* ptr) {
SCREEN[idx++] = *((byte*)ptr);
}

View File

@ -0,0 +1,17 @@
// Test simple void pointer - void pointer function
void main() {
dword d = 0x12345678;
word w = 0x1234;
byte b = 0x12;
print(&b);
print(&w);
print(&d);
}
const byte* SCREEN = 0x0400;
byte idx = 0;
void print(void* ptr) {
SCREEN[idx++] = *((byte*)ptr);
}

View File

@ -0,0 +1,38 @@
// Test auto-casting of call-parameters
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
.const w = $1234
lda #<$1234
sta print.w
lda #>$1234
sta print.w+1
ldx #0
jsr print
lda #<w
sta print.w
lda #>w
sta print.w+1
jsr print
lda #<$12*$100+$34
sta print.w
lda #>$12*$100+$34
sta print.w+1
jsr print
rts
}
// print(word zeropage(2) w)
print: {
.label w = 2
txa
asl
tay
lda w
sta SCREEN,y
lda w+1
sta SCREEN+1,y
inx
rts
}

View File

@ -0,0 +1,34 @@
@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()
[5] call print
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print
to:main::@2
main::@2: scope:[main] from main::@1
[8] phi()
[9] call print
to:main::@return
main::@return: scope:[main] from main::@2
[10] return
to:@return
print: scope:[print] from main main::@1 main::@2
[11] (word) print::w#3 ← phi( main/(word) $1234 main::@1/(const word) main::w#0 main::@2/(byte) $12*(word) $100+(byte) $34 )
[11] (byte) idx#12 ← phi( main/(byte) 0 main::@1/(byte) idx#13 main::@2/(byte) idx#13 )
[12] (byte~) print::$0 ← (byte) idx#12 << (byte) 1
[13] *((const word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3
[14] (byte) idx#13 ← ++ (byte) idx#12
to:print::@return
print::@return: scope:[print] from print
[15] return
to:@return

View File

@ -0,0 +1,617 @@
Fixing pointer array-indexing *((word*) SCREEN + (byte) idx)
Adding pointer type conversion cast (word*) SCREEN in (word*) SCREEN ← (number) $400
Identified constant variable (word) main::w
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @2
(byte) idx#15 ← phi( @2/(byte) idx#16 )
(word) main::w#0 ← (number) $1234
(word) print::w#0 ← (number) $1234
call print
to:main::@1
main::@1: scope:[main] from main
(byte) idx#8 ← phi( main/(byte) idx#6 )
(byte) idx#0 ← (byte) idx#8
(word) print::w#1 ← (word) main::w#0
call print
to:main::@2
main::@2: scope:[main] from main::@1
(byte) idx#9 ← phi( main::@1/(byte) idx#6 )
(byte) idx#1 ← (byte) idx#9
(word) print::w#2 ← { (number) $12, (number) $34 }
call print
to:main::@3
main::@3: scope:[main] from main::@2
(byte) idx#10 ← phi( main::@2/(byte) idx#6 )
(byte) idx#2 ← (byte) idx#10
to:main::@return
main::@return: scope:[main] from main::@3
(byte) idx#11 ← phi( main::@3/(byte) idx#2 )
(byte) idx#3 ← (byte) idx#11
return
to:@return
@1: scope:[] from @begin
(word*) SCREEN#0 ← ((word*)) (number) $400
(byte) idx#4 ← (number) 0
to:@2
print: scope:[print] from main main::@1 main::@2
(word) print::w#3 ← phi( main/(word) print::w#0 main::@1/(word) print::w#1 main::@2/(word) print::w#2 )
(byte) idx#12 ← phi( main/(byte) idx#15 main::@1/(byte) idx#0 main::@2/(byte) idx#1 )
(byte~) print::$0 ← (byte) idx#12 * (const byte) SIZEOF_WORD
*((word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3
(byte) idx#5 ← ++ (byte) idx#12
to:print::@return
print::@return: scope:[print] from print
(byte) idx#13 ← phi( print/(byte) idx#5 )
(byte) idx#6 ← (byte) idx#13
return
to:@return
@2: scope:[] from @1
(byte) idx#16 ← phi( @1/(byte) idx#4 )
call main
to:@3
@3: scope:[] from @2
(byte) idx#14 ← phi( @2/(byte) idx#3 )
(byte) idx#7 ← (byte) idx#14
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(word*) SCREEN
(word*) SCREEN#0
(const byte) SIZEOF_WORD = (byte) 2
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#10
(byte) idx#11
(byte) idx#12
(byte) idx#13
(byte) idx#14
(byte) idx#15
(byte) idx#16
(byte) idx#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(word) main::w
(word) main::w#0
(void()) print((word) print::w)
(byte~) print::$0
(label) print::@return
(word) print::w
(word) print::w#0
(word) print::w#1
(word) print::w#2
(word) print::w#3
Adding number conversion cast (unumber) $1234 in (word) main::w#0 ← (number) $1234
Adding number conversion cast (unumber) $1234 in (word) print::w#0 ← (number) $1234
Adding number conversion cast (unumber) 0 in (byte) idx#4 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (word) main::w#0 ← (unumber)(number) $1234
Inlining cast (word) print::w#0 ← (unumber)(number) $1234
Inlining cast (word*) SCREEN#0 ← (word*)(number) $400
Inlining cast (byte) idx#4 ← (unumber)(number) 0
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $1234
Simplifying constant integer cast $1234
Simplifying constant pointer cast (word*) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (word) $1234
Finalized unsigned number type (word) $1234
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Identified literal word (word) { $12, $34 } in (word) print::w#2 ← { (number) $12, (number) $34 }
Successful SSA optimization PassNAddTypeConversionAssignment
Alias (byte) idx#0 = (byte) idx#8
Alias (byte) idx#1 = (byte) idx#9
Alias (byte) idx#10 = (byte) idx#2 (byte) idx#11 (byte) idx#3
Alias (byte) idx#13 = (byte) idx#5 (byte) idx#6
Alias (byte) idx#16 = (byte) idx#4
Alias (byte) idx#14 = (byte) idx#7
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#15 (byte) idx#16
Identical Phi Values (byte) idx#0 (byte) idx#13
Identical Phi Values (byte) idx#1 (byte) idx#13
Identical Phi Values (byte) idx#10 (byte) idx#13
Identical Phi Values (byte) idx#14 (byte) idx#10
Successful SSA optimization Pass2IdenticalPhiElimination
Constant (const word) main::w#0 = $1234
Constant (const word) print::w#0 = $1234
Constant (const word*) SCREEN#0 = (word*) 1024
Constant (const byte) idx#16 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant (const word) print::w#1 = main::w#0
Successful SSA optimization Pass2ConstantIdentification
Fixing inline constructor with main::$3 ← (byte)$12 w= (byte)$34
Successful SSA optimization Pass2FixInlineConstructorsNew
Simplifying constant integer cast $12
Simplifying constant integer cast $34
Successful SSA optimization PassNCastSimplification
Alias (word) print::w#2 = (word~) main::$3
Successful SSA optimization Pass2AliasElimination
Constant right-side identified [2] (word) print::w#2 ← (byte) $12 w= (byte) $34
Successful SSA optimization Pass2ConstantRValueConsolidation
Adding number conversion cast (unumber) $12*$100+$34 in (word) print::w#2 ← (byte) $12*(number) $100+(byte) $34
Adding number conversion cast (unumber) $12*$100 in (word) print::w#2 ← ((unumber)) (byte) $12*(number) $100+(byte) $34
Adding number conversion cast (unumber) $100 in (word) print::w#2 ← ((unumber)) (unumber)(byte) $12*(number) $100+(byte) $34
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (word) print::w#2 ← (unumber)(unumber)(byte) $12*(unumber)(number) $100+(byte) $34
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast (unumber)(byte) $12*(unumber)(number) $100+(byte) $34
Simplifying constant integer cast (byte) $12*(unumber)(number) $100
Simplifying constant integer cast $100
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (word) $100
Successful SSA optimization PassNFinalizeNumberTypeConversions
Constant (const word) print::w#2 = $12*$100+$34
Successful SSA optimization Pass2ConstantIdentification
Rewriting multiplication to use shift [5] (byte~) print::$0 ← (byte) idx#12 * (const byte) SIZEOF_WORD
Successful SSA optimization Pass2MultiplyToShiftRewriting
Inlining constant with var siblings (const word) print::w#0
Inlining constant with var siblings (const word) print::w#1
Inlining constant with var siblings (const word) print::w#2
Inlining constant with var siblings (const byte) idx#16
Constant inlined print::w#2 = (byte) $12*(word) $100+(byte) $34
Constant inlined print::w#1 = (const word) main::w#0
Constant inlined print::w#0 = (word) $1234
Constant inlined idx#16 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Eliminating unused constant (const byte) SIZEOF_WORD
Successful SSA optimization PassNEliminateUnusedVars
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@3
CALL GRAPH
Calls in [] to main:3
Calls in [main] to print:7 print:9 print:11
Created 2 initial phi equivalence classes
Coalesced [8] idx#17 ← idx#13
Coalesced (already) [10] idx#18 ← idx#13
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Culled Empty Block (label) main::@3
Renumbering block @2 to @1
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
Adding NOP phi() at start of main::@1
Adding NOP phi() at start of main::@2
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()
[5] call print
to:main::@1
main::@1: scope:[main] from main
[6] phi()
[7] call print
to:main::@2
main::@2: scope:[main] from main::@1
[8] phi()
[9] call print
to:main::@return
main::@return: scope:[main] from main::@2
[10] return
to:@return
print: scope:[print] from main main::@1 main::@2
[11] (word) print::w#3 ← phi( main/(word) $1234 main::@1/(const word) main::w#0 main::@2/(byte) $12*(word) $100+(byte) $34 )
[11] (byte) idx#12 ← phi( main/(byte) 0 main::@1/(byte) idx#13 main::@2/(byte) idx#13 )
[12] (byte~) print::$0 ← (byte) idx#12 << (byte) 1
[13] *((const word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3
[14] (byte) idx#13 ← ++ (byte) idx#12
to:print::@return
print::@return: scope:[print] from print
[15] return
to:@return
VARIABLE REGISTER WEIGHTS
(word*) SCREEN
(byte) idx
(byte) idx#12 2.6666666666666665
(byte) idx#13 1.0
(void()) main()
(word) main::w
(void()) print((word) print::w)
(byte~) print::$0 4.0
(word) print::w
(word) print::w#3 1.0
Initial phi equivalence classes
[ idx#12 idx#13 ]
[ print::w#3 ]
Added variable print::$0 to zero page equivalence class [ print::$0 ]
Complete equivalence classes
[ idx#12 idx#13 ]
[ print::w#3 ]
[ print::$0 ]
Allocated zp ZP_BYTE:2 [ idx#12 idx#13 ]
Allocated zp ZP_WORD:3 [ print::w#3 ]
Allocated zp ZP_BYTE:5 [ print::$0 ]
INITIAL ASM
//SEG0 File Comments
// Test auto-casting of call-parameters
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label idx = 2
//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: {
.const w = $1234
//SEG11 [5] call print
//SEG12 [11] phi from main to print [phi:main->print]
print_from_main:
//SEG13 [11] phi (word) print::w#3 = (word) $1234 [phi:main->print#0] -- vwuz1=vwuc1
lda #<$1234
sta print.w
lda #>$1234
sta print.w+1
//SEG14 [11] phi (byte) idx#12 = (byte) 0 [phi:main->print#1] -- vbuz1=vbuc1
lda #0
sta idx
jsr print
//SEG15 [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
//SEG16 main::@1
b1:
//SEG17 [7] call print
//SEG18 [11] phi from main::@1 to print [phi:main::@1->print]
print_from_b1:
//SEG19 [11] phi (word) print::w#3 = (const word) main::w#0 [phi:main::@1->print#0] -- vwuz1=vwuc1
lda #<w
sta print.w
lda #>w
sta print.w+1
//SEG20 [11] phi (byte) idx#12 = (byte) idx#13 [phi:main::@1->print#1] -- register_copy
jsr print
//SEG21 [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
jmp b2
//SEG22 main::@2
b2:
//SEG23 [9] call print
//SEG24 [11] phi from main::@2 to print [phi:main::@2->print]
print_from_b2:
//SEG25 [11] phi (word) print::w#3 = (byte) $12*(word) $100+(byte) $34 [phi:main::@2->print#0] -- vwuz1=vwuc1
lda #<$12*$100+$34
sta print.w
lda #>$12*$100+$34
sta print.w+1
//SEG26 [11] phi (byte) idx#12 = (byte) idx#13 [phi:main::@2->print#1] -- register_copy
jsr print
jmp breturn
//SEG27 main::@return
breturn:
//SEG28 [10] return
rts
}
//SEG29 print
// print(word zeropage(3) w)
print: {
.label _0 = 5
.label w = 3
//SEG30 [12] (byte~) print::$0 ← (byte) idx#12 << (byte) 1 -- vbuz1=vbuz2_rol_1
lda idx
asl
sta _0
//SEG31 [13] *((const word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3 -- pwuc1_derefidx_vbuz1=vwuz2
ldy _0
lda w
sta SCREEN,y
lda w+1
sta SCREEN+1,y
//SEG32 [14] (byte) idx#13 ← ++ (byte) idx#12 -- vbuz1=_inc_vbuz1
inc idx
jmp breturn
//SEG33 print::@return
breturn:
//SEG34 [15] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [12] (byte~) print::$0 ← (byte) idx#12 << (byte) 1 [ idx#12 print::w#3 print::$0 ] ( main:2::print:5 [ idx#12 print::w#3 print::$0 ] main:2::print:7 [ idx#12 print::w#3 print::$0 ] main:2::print:9 [ idx#12 print::w#3 print::$0 ] ) always clobbers reg byte a
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ idx#12 idx#13 ]
Statement [13] *((const word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3 [ idx#12 ] ( main:2::print:5 [ idx#12 ] main:2::print:7 [ idx#12 ] main:2::print:9 [ idx#12 ] ) always clobbers reg byte a
Statement [12] (byte~) print::$0 ← (byte) idx#12 << (byte) 1 [ idx#12 print::w#3 print::$0 ] ( main:2::print:5 [ idx#12 print::w#3 print::$0 ] main:2::print:7 [ idx#12 print::w#3 print::$0 ] main:2::print:9 [ idx#12 print::w#3 print::$0 ] ) always clobbers reg byte a
Statement [13] *((const word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3 [ idx#12 ] ( main:2::print:5 [ idx#12 ] main:2::print:7 [ idx#12 ] main:2::print:9 [ idx#12 ] ) always clobbers reg byte a
Potential registers zp ZP_BYTE:2 [ idx#12 idx#13 ] : zp ZP_BYTE:2 , reg byte x , reg byte y ,
Potential registers zp ZP_WORD:3 [ print::w#3 ] : zp ZP_WORD:3 ,
Potential registers zp ZP_BYTE:5 [ print::$0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [print] 4: zp ZP_BYTE:5 [ print::$0 ] 1: zp ZP_WORD:3 [ print::w#3 ]
Uplift Scope [] 3.67: zp ZP_BYTE:2 [ idx#12 idx#13 ]
Uplift Scope [main]
Uplifting [print] best 117 combination reg byte a [ print::$0 ] zp ZP_WORD:3 [ print::w#3 ]
Uplifting [] best 110 combination reg byte x [ idx#12 idx#13 ]
Uplifting [main] best 110 combination
Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ print::w#3 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Test auto-casting of call-parameters
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
//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: {
.const w = $1234
//SEG11 [5] call print
//SEG12 [11] phi from main to print [phi:main->print]
print_from_main:
//SEG13 [11] phi (word) print::w#3 = (word) $1234 [phi:main->print#0] -- vwuz1=vwuc1
lda #<$1234
sta print.w
lda #>$1234
sta print.w+1
//SEG14 [11] phi (byte) idx#12 = (byte) 0 [phi:main->print#1] -- vbuxx=vbuc1
ldx #0
jsr print
//SEG15 [6] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
//SEG16 main::@1
b1:
//SEG17 [7] call print
//SEG18 [11] phi from main::@1 to print [phi:main::@1->print]
print_from_b1:
//SEG19 [11] phi (word) print::w#3 = (const word) main::w#0 [phi:main::@1->print#0] -- vwuz1=vwuc1
lda #<w
sta print.w
lda #>w
sta print.w+1
//SEG20 [11] phi (byte) idx#12 = (byte) idx#13 [phi:main::@1->print#1] -- register_copy
jsr print
//SEG21 [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
jmp b2
//SEG22 main::@2
b2:
//SEG23 [9] call print
//SEG24 [11] phi from main::@2 to print [phi:main::@2->print]
print_from_b2:
//SEG25 [11] phi (word) print::w#3 = (byte) $12*(word) $100+(byte) $34 [phi:main::@2->print#0] -- vwuz1=vwuc1
lda #<$12*$100+$34
sta print.w
lda #>$12*$100+$34
sta print.w+1
//SEG26 [11] phi (byte) idx#12 = (byte) idx#13 [phi:main::@2->print#1] -- register_copy
jsr print
jmp breturn
//SEG27 main::@return
breturn:
//SEG28 [10] return
rts
}
//SEG29 print
// print(word zeropage(2) w)
print: {
.label w = 2
//SEG30 [12] (byte~) print::$0 ← (byte) idx#12 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
//SEG31 [13] *((const word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3 -- pwuc1_derefidx_vbuaa=vwuz1
tay
lda w
sta SCREEN,y
lda w+1
sta SCREEN+1,y
//SEG32 [14] (byte) idx#13 ← ++ (byte) idx#12 -- vbuxx=_inc_vbuxx
inx
jmp breturn
//SEG33 print::@return
breturn:
//SEG34 [15] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp breturn
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction main_from_b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_main:
Removing instruction print_from_b1:
Removing instruction b2_from_b1:
Removing instruction print_from_b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction print_from_main:
Removing instruction b1:
Removing instruction b2:
Removing instruction breturn:
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
(word*) SCREEN
(const word*) SCREEN#0 SCREEN = (word*) 1024
(byte) idx
(byte) idx#12 reg byte x 2.6666666666666665
(byte) idx#13 reg byte x 1.0
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::w
(const word) main::w#0 w = (word) $1234
(void()) print((word) print::w)
(byte~) print::$0 reg byte a 4.0
(label) print::@return
(word) print::w
(word) print::w#3 w zp ZP_WORD:2 1.0
reg byte x [ idx#12 idx#13 ]
zp ZP_WORD:2 [ print::w#3 ]
reg byte a [ print::$0 ]
FINAL ASSEMBLER
Score: 86
//SEG0 File Comments
// Test auto-casting of call-parameters
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
//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: {
.const w = $1234
//SEG11 [5] call print
//SEG12 [11] phi from main to print [phi:main->print]
//SEG13 [11] phi (word) print::w#3 = (word) $1234 [phi:main->print#0] -- vwuz1=vwuc1
lda #<$1234
sta print.w
lda #>$1234
sta print.w+1
//SEG14 [11] phi (byte) idx#12 = (byte) 0 [phi:main->print#1] -- vbuxx=vbuc1
ldx #0
jsr print
//SEG15 [6] phi from main to main::@1 [phi:main->main::@1]
//SEG16 main::@1
//SEG17 [7] call print
//SEG18 [11] phi from main::@1 to print [phi:main::@1->print]
//SEG19 [11] phi (word) print::w#3 = (const word) main::w#0 [phi:main::@1->print#0] -- vwuz1=vwuc1
lda #<w
sta print.w
lda #>w
sta print.w+1
//SEG20 [11] phi (byte) idx#12 = (byte) idx#13 [phi:main::@1->print#1] -- register_copy
jsr print
//SEG21 [8] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
//SEG22 main::@2
//SEG23 [9] call print
//SEG24 [11] phi from main::@2 to print [phi:main::@2->print]
//SEG25 [11] phi (word) print::w#3 = (byte) $12*(word) $100+(byte) $34 [phi:main::@2->print#0] -- vwuz1=vwuc1
lda #<$12*$100+$34
sta print.w
lda #>$12*$100+$34
sta print.w+1
//SEG26 [11] phi (byte) idx#12 = (byte) idx#13 [phi:main::@2->print#1] -- register_copy
jsr print
//SEG27 main::@return
//SEG28 [10] return
rts
}
//SEG29 print
// print(word zeropage(2) w)
print: {
.label w = 2
//SEG30 [12] (byte~) print::$0 ← (byte) idx#12 << (byte) 1 -- vbuaa=vbuxx_rol_1
txa
asl
//SEG31 [13] *((const word*) SCREEN#0 + (byte~) print::$0) ← (word) print::w#3 -- pwuc1_derefidx_vbuaa=vwuz1
tay
lda w
sta SCREEN,y
lda w+1
sta SCREEN+1,y
//SEG32 [14] (byte) idx#13 ← ++ (byte) idx#12 -- vbuxx=_inc_vbuxx
inx
//SEG33 print::@return
//SEG34 [15] return
rts
}

View File

@ -0,0 +1,23 @@
(label) @1
(label) @begin
(label) @end
(word*) SCREEN
(const word*) SCREEN#0 SCREEN = (word*) 1024
(byte) idx
(byte) idx#12 reg byte x 2.6666666666666665
(byte) idx#13 reg byte x 1.0
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(word) main::w
(const word) main::w#0 w = (word) $1234
(void()) print((word) print::w)
(byte~) print::$0 reg byte a 4.0
(label) print::@return
(word) print::w
(word) print::w#3 w zp ZP_WORD:2 1.0
reg byte x [ idx#12 idx#13 ]
zp ZP_WORD:2 [ print::w#3 ]
reg byte a [ print::$0 ]

View File

@ -0,0 +1,53 @@
// Test simple void pointer - void pointer function
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
.label vb = b
.label vw = w
.label vd = d
.label d = 4
.label w = 8
.label b = $a
lda #<$12345678
sta d
lda #>$12345678
sta d+1
lda #<$12345678>>$10
sta d+2
lda #>$12345678>>$10
sta d+3
lda #<$1234
sta w
lda #>$1234
sta w+1
lda #$12
sta b
ldx #0
lda #<vb
sta print.ptr
lda #>vb
sta print.ptr+1
jsr print
lda #<vw
sta print.ptr
lda #>vw
sta print.ptr+1
jsr print
lda #<vd
sta print.ptr
lda #>vd
sta print.ptr+1
jsr print
rts
}
// print(void* zeropage(2) ptr)
print: {
.label ptr = 2
ldy #0
lda (ptr),y
sta SCREEN,x
inx
rts
}

View File

@ -0,0 +1,35 @@
@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] (dword) main::d#0 ← (dword) $12345678
[5] (word) main::w#0 ← (word) $1234
[6] (byte) main::b#0 ← (byte) $12
[7] call print
to:main::@1
main::@1: scope:[main] from main
[8] phi()
[9] call print
to:main::@2
main::@2: scope:[main] from main::@1
[10] phi()
[11] call print
to:main::@return
main::@return: scope:[main] from main::@2
[12] return
to:@return
print: scope:[print] from main main::@1 main::@2
[13] (byte) idx#12 ← phi( main/(byte) 0 main::@1/(byte) idx#13 main::@2/(byte) idx#13 )
[13] (void*) print::ptr#3 ← phi( main/(const void*) main::vb#0 main::@1/(const void*) main::vw#0 main::@2/(const void*) main::vd#0 )
[14] *((const byte*) SCREEN#0 + (byte) idx#12) ← *((byte*)(void*) print::ptr#3)
[15] (byte) idx#13 ← ++ (byte) idx#12
to:print::@return
print::@return: scope:[print] from print
[16] return
to:@return

View File

@ -0,0 +1,723 @@
Setting inferred volatile on symbol affected by address-of (byte*~) main::$0 ← & (byte) main::b
Setting inferred volatile on symbol affected by address-of (word*~) main::$1 ← & (word) main::w
Setting inferred volatile on symbol affected by address-of (dword*~) main::$2 ← & (dword) main::d
Adding void pointer type conversion cast (void*) main::$0 in (void*) main::vb ← (byte*~) main::$0
Adding void pointer type conversion cast (void*) main::$1 in (void*) main::vw ← (word*~) main::$1
Adding void pointer type conversion cast (void*) main::$2 in (void*) main::vd ← (dword*~) main::$2
Adding pointer type conversion cast (byte*) SCREEN in (byte*) SCREEN ← (number) $400
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
to:@1
main: scope:[main] from @2
(byte) idx#15 ← phi( @2/(byte) idx#16 )
(dword) main::d#0 ← (number) $12345678
(word) main::w#0 ← (number) $1234
(byte) main::b#0 ← (number) $12
(byte*~) main::$0 ← & (byte) main::b#0
(void*) main::vb#0 ← ((void*)) (byte*~) main::$0
(word*~) main::$1 ← & (word) main::w#0
(void*) main::vw#0 ← ((void*)) (word*~) main::$1
(dword*~) main::$2 ← & (dword) main::d#0
(void*) main::vd#0 ← ((void*)) (dword*~) main::$2
(void*) print::ptr#0 ← (void*) main::vb#0
call print
to:main::@1
main::@1: scope:[main] from main
(void*) main::vd#2 ← phi( main/(void*) main::vd#0 )
(void*) main::vw#1 ← phi( main/(void*) main::vw#0 )
(byte) idx#8 ← phi( main/(byte) idx#6 )
(byte) idx#0 ← (byte) idx#8
(void*) print::ptr#1 ← (void*) main::vw#1
call print
to:main::@2
main::@2: scope:[main] from main::@1
(void*) main::vd#1 ← phi( main::@1/(void*) main::vd#2 )
(byte) idx#9 ← phi( main::@1/(byte) idx#6 )
(byte) idx#1 ← (byte) idx#9
(void*) print::ptr#2 ← (void*) main::vd#1
call print
to:main::@3
main::@3: scope:[main] from main::@2
(byte) idx#10 ← phi( main::@2/(byte) idx#6 )
(byte) idx#2 ← (byte) idx#10
to:main::@return
main::@return: scope:[main] from main::@3
(byte) idx#11 ← phi( main::@3/(byte) idx#2 )
(byte) idx#3 ← (byte) idx#11
return
to:@return
@1: scope:[] from @begin
(byte*) SCREEN#0 ← ((byte*)) (number) $400
(byte) idx#4 ← (number) 0
to:@2
print: scope:[print] from main main::@1 main::@2
(byte) idx#12 ← phi( main/(byte) idx#15 main::@1/(byte) idx#0 main::@2/(byte) idx#1 )
(void*) print::ptr#3 ← phi( main/(void*) print::ptr#0 main::@1/(void*) print::ptr#1 main::@2/(void*) print::ptr#2 )
(byte*~) print::$0 ← ((byte*)) (void*) print::ptr#3
*((byte*) SCREEN#0 + (byte) idx#12) ← *((byte*~) print::$0)
(byte) idx#5 ← ++ (byte) idx#12
to:print::@return
print::@return: scope:[print] from print
(byte) idx#13 ← phi( print/(byte) idx#5 )
(byte) idx#6 ← (byte) idx#13
return
to:@return
@2: scope:[] from @1
(byte) idx#16 ← phi( @1/(byte) idx#4 )
call main
to:@3
@3: scope:[] from @2
(byte) idx#14 ← phi( @2/(byte) idx#3 )
(byte) idx#7 ← (byte) idx#14
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(byte*) SCREEN
(byte*) SCREEN#0
(byte) idx
(byte) idx#0
(byte) idx#1
(byte) idx#10
(byte) idx#11
(byte) idx#12
(byte) idx#13
(byte) idx#14
(byte) idx#15
(byte) idx#16
(byte) idx#2
(byte) idx#3
(byte) idx#4
(byte) idx#5
(byte) idx#6
(byte) idx#7
(byte) idx#8
(byte) idx#9
(void()) main()
(byte*~) main::$0
(word*~) main::$1
(dword*~) main::$2
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@return
(byte) main::b
(byte) main::b#0
(dword) main::d
(dword) main::d#0
(void*) main::vb
(void*) main::vb#0
(void*) main::vd
(void*) main::vd#0
(void*) main::vd#1
(void*) main::vd#2
(void*) main::vw
(void*) main::vw#0
(void*) main::vw#1
(word) main::w
(word) main::w#0
(void()) print((void*) print::ptr)
(byte*~) print::$0
(label) print::@return
(void*) print::ptr
(void*) print::ptr#0
(void*) print::ptr#1
(void*) print::ptr#2
(void*) print::ptr#3
Adding number conversion cast (unumber) $12345678 in (dword) main::d#0 ← (number) $12345678
Adding number conversion cast (unumber) $1234 in (word) main::w#0 ← (number) $1234
Adding number conversion cast (unumber) $12 in (byte) main::b#0 ← (number) $12
Adding number conversion cast (unumber) 0 in (byte) idx#4 ← (number) 0
Successful SSA optimization PassNAddNumberTypeConversions
Inlining cast (dword) main::d#0 ← (unumber)(number) $12345678
Inlining cast (word) main::w#0 ← (unumber)(number) $1234
Inlining cast (byte) main::b#0 ← (unumber)(number) $12
Inlining cast (void*) main::vb#0 ← (void*)(byte*~) main::$0
Inlining cast (void*) main::vw#0 ← (void*)(word*~) main::$1
Inlining cast (void*) main::vd#0 ← (void*)(dword*~) main::$2
Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400
Inlining cast (byte) idx#4 ← (unumber)(number) 0
Inlining cast (byte*~) print::$0 ← (byte*)(void*) print::ptr#3
Successful SSA optimization Pass2InlineCast
Simplifying constant integer cast $12345678
Simplifying constant integer cast $1234
Simplifying constant integer cast $12
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (dword) $12345678
Finalized unsigned number type (word) $1234
Finalized unsigned number type (byte) $12
Finalized unsigned number type (byte) 0
Successful SSA optimization PassNFinalizeNumberTypeConversions
Alias (void*) main::vw#0 = (void*) main::vw#1
Alias (void*) main::vd#0 = (void*) main::vd#2 (void*) main::vd#1
Alias (byte) idx#0 = (byte) idx#8
Alias (byte) idx#1 = (byte) idx#9
Alias (byte) idx#10 = (byte) idx#2 (byte) idx#11 (byte) idx#3
Alias (byte) idx#13 = (byte) idx#5 (byte) idx#6
Alias (byte) idx#16 = (byte) idx#4
Alias (byte) idx#14 = (byte) idx#7
Successful SSA optimization Pass2AliasElimination
Identical Phi Values (byte) idx#15 (byte) idx#16
Identical Phi Values (byte) idx#0 (byte) idx#13
Identical Phi Values (byte) idx#1 (byte) idx#13
Identical Phi Values (byte) idx#10 (byte) idx#13
Identical Phi Values (byte) idx#14 (byte) idx#10
Successful SSA optimization Pass2IdenticalPhiElimination
Constant right-side identified [4] (byte*~) main::$0 ← & (byte) main::b#0
Constant right-side identified [6] (word*~) main::$1 ← & (word) main::w#0
Constant right-side identified [8] (dword*~) main::$2 ← & (dword) main::d#0
Successful SSA optimization Pass2ConstantRValueConsolidation
Constant (const byte*) main::$0 = &main::b#0
Constant (const word*) main::$1 = &main::w#0
Constant (const dword*) main::$2 = &main::d#0
Constant (const byte*) SCREEN#0 = (byte*) 1024
Constant (const byte) idx#16 = 0
Successful SSA optimization Pass2ConstantIdentification
Constant value identified (void*)main::$0 in [5] (void*) main::vb#0 ← (void*)(const byte*) main::$0
Constant value identified (void*)main::$1 in [7] (void*) main::vw#0 ← (void*)(const word*) main::$1
Constant value identified (void*)main::$2 in [9] (void*) main::vd#0 ← (void*)(const dword*) main::$2
Successful SSA optimization Pass2ConstantValues
Constant (const void*) main::vb#0 = (void*)main::$0
Constant (const void*) main::vw#0 = (void*)main::$1
Constant (const void*) main::vd#0 = (void*)main::$2
Successful SSA optimization Pass2ConstantIdentification
Constant (const void*) print::ptr#0 = main::vb#0
Constant (const void*) print::ptr#1 = main::vw#0
Constant (const void*) print::ptr#2 = main::vd#0
Successful SSA optimization Pass2ConstantIdentification
Inlining Noop Cast [8] (byte*~) print::$0 ← (byte*)(void*) print::ptr#3 keeping print::ptr#3
Successful SSA optimization Pass2NopCastInlining
Inlining constant with var siblings (const void*) print::ptr#0
Inlining constant with var siblings (const void*) print::ptr#1
Inlining constant with var siblings (const void*) print::ptr#2
Inlining constant with var siblings (const byte) idx#16
Constant inlined print::ptr#2 = (const void*) main::vd#0
Constant inlined main::$1 = &(word) main::w#0
Constant inlined main::$2 = &(dword) main::d#0
Constant inlined main::$0 = &(byte) main::b#0
Constant inlined print::ptr#0 = (const void*) main::vb#0
Constant inlined print::ptr#1 = (const void*) main::vw#0
Constant inlined idx#16 = (byte) 0
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @1
Adding NOP phi() at start of @2
Adding NOP phi() at start of @3
Adding NOP phi() at start of @end
Adding NOP phi() at start of main::@3
CALL GRAPH
Calls in [] to main:3
Calls in [main] to print:9 print:11 print:13
Created 2 initial phi equivalence classes
Coalesced [10] idx#17 ← idx#13
Coalesced (already) [12] idx#18 ← idx#13
Coalesced down to 2 phi equivalence classes
Culled Empty Block (label) @1
Culled Empty Block (label) @3
Culled Empty Block (label) main::@3
Renumbering block @2 to @1
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::@1
Adding NOP phi() at start of main::@2
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] (dword) main::d#0 ← (dword) $12345678
[5] (word) main::w#0 ← (word) $1234
[6] (byte) main::b#0 ← (byte) $12
[7] call print
to:main::@1
main::@1: scope:[main] from main
[8] phi()
[9] call print
to:main::@2
main::@2: scope:[main] from main::@1
[10] phi()
[11] call print
to:main::@return
main::@return: scope:[main] from main::@2
[12] return
to:@return
print: scope:[print] from main main::@1 main::@2
[13] (byte) idx#12 ← phi( main/(byte) 0 main::@1/(byte) idx#13 main::@2/(byte) idx#13 )
[13] (void*) print::ptr#3 ← phi( main/(const void*) main::vb#0 main::@1/(const void*) main::vw#0 main::@2/(const void*) main::vd#0 )
[14] *((const byte*) SCREEN#0 + (byte) idx#12) ← *((byte*)(void*) print::ptr#3)
[15] (byte) idx#13 ← ++ (byte) idx#12
to:print::@return
print::@return: scope:[print] from print
[16] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) SCREEN
(byte) idx
(byte) idx#12 4.0
(byte) idx#13 1.0
(void()) main()
(byte) main::b
(byte) main::b#0 20.0
(dword) main::d
(dword) main::d#0 20.0
(void*) main::vb
(void*) main::vd
(void*) main::vw
(word) main::w
(word) main::w#0 20.0
(void()) print((void*) print::ptr)
(void*) print::ptr
(void*) print::ptr#3
Initial phi equivalence classes
[ print::ptr#3 ]
[ idx#12 idx#13 ]
Complete equivalence classes
[ print::ptr#3 ]
[ idx#12 idx#13 ]
[ main::d#0 ]
[ main::w#0 ]
[ main::b#0 ]
Allocated zp ZP_WORD:2 [ print::ptr#3 ]
Allocated zp ZP_BYTE:4 [ idx#12 idx#13 ]
Allocated zp ZP_DWORD:5 [ main::d#0 ]
Allocated zp ZP_WORD:9 [ main::w#0 ]
Allocated zp ZP_BYTE:11 [ main::b#0 ]
INITIAL ASM
//SEG0 File Comments
// Test simple void pointer - void pointer function
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
.label idx = 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
jsr main
//SEG7 [3] phi from @1 to @end [phi:@1->@end]
bend_from_b1:
jmp bend
//SEG8 @end
bend:
//SEG9 main
main: {
.label vb = b
.label vw = w
.label vd = d
.label d = 5
.label w = 9
.label b = $b
//SEG10 [4] (dword) main::d#0 ← (dword) $12345678 -- vduz1=vduc1
lda #<$12345678
sta d
lda #>$12345678
sta d+1
lda #<$12345678>>$10
sta d+2
lda #>$12345678>>$10
sta d+3
//SEG11 [5] (word) main::w#0 ← (word) $1234 -- vwuz1=vwuc1
lda #<$1234
sta w
lda #>$1234
sta w+1
//SEG12 [6] (byte) main::b#0 ← (byte) $12 -- vbuz1=vbuc1
lda #$12
sta b
//SEG13 [7] call print
//SEG14 [13] phi from main to print [phi:main->print]
print_from_main:
//SEG15 [13] phi (byte) idx#12 = (byte) 0 [phi:main->print#0] -- vbuz1=vbuc1
lda #0
sta idx
//SEG16 [13] phi (void*) print::ptr#3 = (const void*) main::vb#0 [phi:main->print#1] -- pvoz1=pvoc1
lda #<vb
sta print.ptr
lda #>vb
sta print.ptr+1
jsr print
//SEG17 [8] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
//SEG18 main::@1
b1:
//SEG19 [9] call print
//SEG20 [13] phi from main::@1 to print [phi:main::@1->print]
print_from_b1:
//SEG21 [13] phi (byte) idx#12 = (byte) idx#13 [phi:main::@1->print#0] -- register_copy
//SEG22 [13] phi (void*) print::ptr#3 = (const void*) main::vw#0 [phi:main::@1->print#1] -- pvoz1=pvoc1
lda #<vw
sta print.ptr
lda #>vw
sta print.ptr+1
jsr print
//SEG23 [10] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
jmp b2
//SEG24 main::@2
b2:
//SEG25 [11] call print
//SEG26 [13] phi from main::@2 to print [phi:main::@2->print]
print_from_b2:
//SEG27 [13] phi (byte) idx#12 = (byte) idx#13 [phi:main::@2->print#0] -- register_copy
//SEG28 [13] phi (void*) print::ptr#3 = (const void*) main::vd#0 [phi:main::@2->print#1] -- pvoz1=pvoc1
lda #<vd
sta print.ptr
lda #>vd
sta print.ptr+1
jsr print
jmp breturn
//SEG29 main::@return
breturn:
//SEG30 [12] return
rts
}
//SEG31 print
// print(void* zeropage(2) ptr)
print: {
.label ptr = 2
//SEG32 [14] *((const byte*) SCREEN#0 + (byte) idx#12) ← *((byte*)(void*) print::ptr#3) -- pbuc1_derefidx_vbuz1=_deref_pbuz2
ldx idx
ldy #0
lda (ptr),y
sta SCREEN,x
//SEG33 [15] (byte) idx#13 ← ++ (byte) idx#12 -- vbuz1=_inc_vbuz1
inc idx
jmp breturn
//SEG34 print::@return
breturn:
//SEG35 [16] return
rts
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [4] (dword) main::d#0 ← (dword) $12345678 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [5] (word) main::w#0 ← (word) $1234 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [6] (byte) main::b#0 ← (byte) $12 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [14] *((const byte*) SCREEN#0 + (byte) idx#12) ← *((byte*)(void*) print::ptr#3) [ idx#12 ] ( main:2::print:7 [ idx#12 ] main:2::print:9 [ idx#12 ] main:2::print:11 [ idx#12 ] ) always clobbers reg byte a reg byte y
Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ idx#12 idx#13 ]
Removing always clobbered register reg byte y as potential for zp ZP_BYTE:4 [ idx#12 idx#13 ]
Statement [4] (dword) main::d#0 ← (dword) $12345678 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [5] (word) main::w#0 ← (word) $1234 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [6] (byte) main::b#0 ← (byte) $12 [ ] ( main:2 [ ] ) always clobbers reg byte a
Statement [14] *((const byte*) SCREEN#0 + (byte) idx#12) ← *((byte*)(void*) print::ptr#3) [ idx#12 ] ( main:2::print:7 [ idx#12 ] main:2::print:9 [ idx#12 ] main:2::print:11 [ idx#12 ] ) always clobbers reg byte a reg byte y
Potential registers zp ZP_WORD:2 [ print::ptr#3 ] : zp ZP_WORD:2 ,
Potential registers zp ZP_BYTE:4 [ idx#12 idx#13 ] : zp ZP_BYTE:4 , reg byte x ,
Potential registers zp ZP_DWORD:5 [ main::d#0 ] : zp ZP_DWORD:5 ,
Potential registers zp ZP_WORD:9 [ main::w#0 ] : zp ZP_WORD:9 ,
Potential registers zp ZP_BYTE:11 [ main::b#0 ] : zp ZP_BYTE:11 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 20: zp ZP_DWORD:5 [ main::d#0 ] 20: zp ZP_WORD:9 [ main::w#0 ] 20: zp ZP_BYTE:11 [ main::b#0 ]
Uplift Scope [] 5: zp ZP_BYTE:4 [ idx#12 idx#13 ]
Uplift Scope [print] 0: zp ZP_WORD:2 [ print::ptr#3 ]
Uplifting [main] best 144 combination zp ZP_DWORD:5 [ main::d#0 ] zp ZP_WORD:9 [ main::w#0 ] zp ZP_BYTE:11 [ main::b#0 ]
Uplifting [] best 135 combination reg byte x [ idx#12 idx#13 ]
Uplifting [print] best 135 combination zp ZP_WORD:2 [ print::ptr#3 ]
Attempting to uplift remaining variables inzp ZP_BYTE:11 [ main::b#0 ]
Uplifting [main] best 135 combination zp ZP_BYTE:11 [ main::b#0 ]
Allocated (was zp ZP_DWORD:5) zp ZP_DWORD:4 [ main::d#0 ]
Allocated (was zp ZP_WORD:9) zp ZP_WORD:8 [ main::w#0 ]
Allocated (was zp ZP_BYTE:11) zp ZP_BYTE:10 [ main::b#0 ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Test simple void pointer - void pointer function
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
//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 vb = b
.label vw = w
.label vd = d
.label d = 4
.label w = 8
.label b = $a
//SEG10 [4] (dword) main::d#0 ← (dword) $12345678 -- vduz1=vduc1
lda #<$12345678
sta d
lda #>$12345678
sta d+1
lda #<$12345678>>$10
sta d+2
lda #>$12345678>>$10
sta d+3
//SEG11 [5] (word) main::w#0 ← (word) $1234 -- vwuz1=vwuc1
lda #<$1234
sta w
lda #>$1234
sta w+1
//SEG12 [6] (byte) main::b#0 ← (byte) $12 -- vbuz1=vbuc1
lda #$12
sta b
//SEG13 [7] call print
//SEG14 [13] phi from main to print [phi:main->print]
print_from_main:
//SEG15 [13] phi (byte) idx#12 = (byte) 0 [phi:main->print#0] -- vbuxx=vbuc1
ldx #0
//SEG16 [13] phi (void*) print::ptr#3 = (const void*) main::vb#0 [phi:main->print#1] -- pvoz1=pvoc1
lda #<vb
sta print.ptr
lda #>vb
sta print.ptr+1
jsr print
//SEG17 [8] phi from main to main::@1 [phi:main->main::@1]
b1_from_main:
jmp b1
//SEG18 main::@1
b1:
//SEG19 [9] call print
//SEG20 [13] phi from main::@1 to print [phi:main::@1->print]
print_from_b1:
//SEG21 [13] phi (byte) idx#12 = (byte) idx#13 [phi:main::@1->print#0] -- register_copy
//SEG22 [13] phi (void*) print::ptr#3 = (const void*) main::vw#0 [phi:main::@1->print#1] -- pvoz1=pvoc1
lda #<vw
sta print.ptr
lda #>vw
sta print.ptr+1
jsr print
//SEG23 [10] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
b2_from_b1:
jmp b2
//SEG24 main::@2
b2:
//SEG25 [11] call print
//SEG26 [13] phi from main::@2 to print [phi:main::@2->print]
print_from_b2:
//SEG27 [13] phi (byte) idx#12 = (byte) idx#13 [phi:main::@2->print#0] -- register_copy
//SEG28 [13] phi (void*) print::ptr#3 = (const void*) main::vd#0 [phi:main::@2->print#1] -- pvoz1=pvoc1
lda #<vd
sta print.ptr
lda #>vd
sta print.ptr+1
jsr print
jmp breturn
//SEG29 main::@return
breturn:
//SEG30 [12] return
rts
}
//SEG31 print
// print(void* zeropage(2) ptr)
print: {
.label ptr = 2
//SEG32 [14] *((const byte*) SCREEN#0 + (byte) idx#12) ← *((byte*)(void*) print::ptr#3) -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (ptr),y
sta SCREEN,x
//SEG33 [15] (byte) idx#13 ← ++ (byte) idx#12 -- vbuxx=_inc_vbuxx
inx
jmp breturn
//SEG34 print::@return
breturn:
//SEG35 [16] return
rts
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp bend
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp breturn
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1_from_bbegin:
Removing instruction b1:
Removing instruction bend_from_b1:
Removing instruction b1_from_main:
Removing instruction print_from_b1:
Removing instruction b2_from_b1:
Removing instruction print_from_b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction bend:
Removing instruction print_from_main:
Removing instruction b1:
Removing instruction b2:
Removing instruction breturn:
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
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx
(byte) idx#12 reg byte x 4.0
(byte) idx#13 reg byte x 1.0
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::b
(byte) main::b#0 b zp ZP_BYTE:10 20.0
(dword) main::d
(dword) main::d#0 d zp ZP_DWORD:4 20.0
(void*) main::vb
(const void*) main::vb#0 vb = (void*)&(byte) main::b#0
(void*) main::vd
(const void*) main::vd#0 vd = (void*)&(dword) main::d#0
(void*) main::vw
(const void*) main::vw#0 vw = (void*)&(word) main::w#0
(word) main::w
(word) main::w#0 w zp ZP_WORD:8 20.0
(void()) print((void*) print::ptr)
(label) print::@return
(void*) print::ptr
(void*) print::ptr#3 ptr zp ZP_WORD:2
zp ZP_WORD:2 [ print::ptr#3 ]
reg byte x [ idx#12 idx#13 ]
zp ZP_DWORD:4 [ main::d#0 ]
zp ZP_WORD:8 [ main::w#0 ]
zp ZP_BYTE:10 [ main::b#0 ]
FINAL ASSEMBLER
Score: 111
//SEG0 File Comments
// Test simple void pointer - void pointer function
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label SCREEN = $400
//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 vb = b
.label vw = w
.label vd = d
.label d = 4
.label w = 8
.label b = $a
//SEG10 [4] (dword) main::d#0 ← (dword) $12345678 -- vduz1=vduc1
lda #<$12345678
sta d
lda #>$12345678
sta d+1
lda #<$12345678>>$10
sta d+2
lda #>$12345678>>$10
sta d+3
//SEG11 [5] (word) main::w#0 ← (word) $1234 -- vwuz1=vwuc1
lda #<$1234
sta w
lda #>$1234
sta w+1
//SEG12 [6] (byte) main::b#0 ← (byte) $12 -- vbuz1=vbuc1
lda #$12
sta b
//SEG13 [7] call print
//SEG14 [13] phi from main to print [phi:main->print]
//SEG15 [13] phi (byte) idx#12 = (byte) 0 [phi:main->print#0] -- vbuxx=vbuc1
ldx #0
//SEG16 [13] phi (void*) print::ptr#3 = (const void*) main::vb#0 [phi:main->print#1] -- pvoz1=pvoc1
lda #<vb
sta print.ptr
lda #>vb
sta print.ptr+1
jsr print
//SEG17 [8] phi from main to main::@1 [phi:main->main::@1]
//SEG18 main::@1
//SEG19 [9] call print
//SEG20 [13] phi from main::@1 to print [phi:main::@1->print]
//SEG21 [13] phi (byte) idx#12 = (byte) idx#13 [phi:main::@1->print#0] -- register_copy
//SEG22 [13] phi (void*) print::ptr#3 = (const void*) main::vw#0 [phi:main::@1->print#1] -- pvoz1=pvoc1
lda #<vw
sta print.ptr
lda #>vw
sta print.ptr+1
jsr print
//SEG23 [10] phi from main::@1 to main::@2 [phi:main::@1->main::@2]
//SEG24 main::@2
//SEG25 [11] call print
//SEG26 [13] phi from main::@2 to print [phi:main::@2->print]
//SEG27 [13] phi (byte) idx#12 = (byte) idx#13 [phi:main::@2->print#0] -- register_copy
//SEG28 [13] phi (void*) print::ptr#3 = (const void*) main::vd#0 [phi:main::@2->print#1] -- pvoz1=pvoc1
lda #<vd
sta print.ptr
lda #>vd
sta print.ptr+1
jsr print
//SEG29 main::@return
//SEG30 [12] return
rts
}
//SEG31 print
// print(void* zeropage(2) ptr)
print: {
.label ptr = 2
//SEG32 [14] *((const byte*) SCREEN#0 + (byte) idx#12) ← *((byte*)(void*) print::ptr#3) -- pbuc1_derefidx_vbuxx=_deref_pbuz1
ldy #0
lda (ptr),y
sta SCREEN,x
//SEG33 [15] (byte) idx#13 ← ++ (byte) idx#12 -- vbuxx=_inc_vbuxx
inx
//SEG34 print::@return
//SEG35 [16] return
rts
}

View File

@ -0,0 +1,34 @@
(label) @1
(label) @begin
(label) @end
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (byte*) 1024
(byte) idx
(byte) idx#12 reg byte x 4.0
(byte) idx#13 reg byte x 1.0
(void()) main()
(label) main::@1
(label) main::@2
(label) main::@return
(byte) main::b
(byte) main::b#0 b zp ZP_BYTE:10 20.0
(dword) main::d
(dword) main::d#0 d zp ZP_DWORD:4 20.0
(void*) main::vb
(const void*) main::vb#0 vb = (void*)&(byte) main::b#0
(void*) main::vd
(const void*) main::vd#0 vd = (void*)&(dword) main::d#0
(void*) main::vw
(const void*) main::vw#0 vw = (void*)&(word) main::w#0
(word) main::w
(word) main::w#0 w zp ZP_WORD:8 20.0
(void()) print((void*) print::ptr)
(label) print::@return
(void*) print::ptr
(void*) print::ptr#3 ptr zp ZP_WORD:2
zp ZP_WORD:2 [ print::ptr#3 ]
reg byte x [ idx#12 idx#13 ]
zp ZP_DWORD:4 [ main::d#0 ]
zp ZP_WORD:8 [ main::w#0 ]
zp ZP_BYTE:10 [ main::b#0 ]