diff --git a/src/main/fragment/pvoz1=pvoc1.asm b/src/main/fragment/pvoz1=pvoc1.asm new file mode 100644 index 000000000..4c71afd48 --- /dev/null +++ b/src/main/fragment/pvoz1=pvoc1.asm @@ -0,0 +1,4 @@ +lda #<{c1} +sta {z1} +lda #>{c1} +sta {z1}+1 \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 88503d1a7..3d3059145 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -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(); diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java index 8b66849a0..00888a1e1 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecFactory.java @@ -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) { diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java index e771d3bb4..dfa4ba264 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorDivide.java @@ -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()); diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java index 50c1fb6f7..7733271ef 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorMinus.java @@ -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); } } diff --git a/src/main/java/dk/camelot64/kickc/model/operators/OperatorMultiply.java b/src/main/java/dk/camelot64/kickc/model/operators/OperatorMultiply.java index a32595647..69fc6e962 100644 --- a/src/main/java/dk/camelot64/kickc/model/operators/OperatorMultiply.java +++ b/src/main/java/dk/camelot64/kickc/model/operators/OperatorMultiply.java @@ -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 diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java index 77945d06c..53e9b0436 100644 --- a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeConversion.java @@ -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)) diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInference.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInference.java index 455bd82f1..85b77822e 100644 --- a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInference.java +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInference.java @@ -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()); - } - } - } diff --git a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInteger.java b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInteger.java index 9a64e214d..485328c15 100644 --- a/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInteger.java +++ b/src/main/java/dk/camelot64/kickc/model/types/SymbolTypeInteger.java @@ -1,6 +1,6 @@ package dk.camelot64.kickc.model.types; /** Integer type marker interface. */ -public interface SymbolTypeInteger extends SymbolType { +public interface SymbolTypeInteger extends SymbolType { } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantRValueConsolidation.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantRValueConsolidation.java index edf2a49c3..f5b04e859 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantRValueConsolidation.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantRValueConsolidation.java @@ -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); diff --git a/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java b/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java index b695ce3e8..79f71e3cb 100644 --- a/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java +++ b/src/main/java/dk/camelot64/kickc/passes/PassNAddTypeConversionAssignment.java @@ -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 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; } diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index d8dc2fad6..c9d0ecdb0 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -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"); } diff --git a/src/test/kc/call-parameter-autocast.kc b/src/test/kc/call-parameter-autocast.kc new file mode 100644 index 000000000..beff09c63 --- /dev/null +++ b/src/test/kc/call-parameter-autocast.kc @@ -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; +} \ No newline at end of file diff --git a/src/test/kc/pointer-void-1.kc b/src/test/kc/pointer-void-1.kc new file mode 100644 index 000000000..50780286f --- /dev/null +++ b/src/test/kc/pointer-void-1.kc @@ -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); +} \ No newline at end of file diff --git a/src/test/kc/pointer-void-2.kc b/src/test/kc/pointer-void-2.kc new file mode 100644 index 000000000..0e7cd0928 --- /dev/null +++ b/src/test/kc/pointer-void-2.kc @@ -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); +} \ No newline at end of file diff --git a/src/test/ref/call-parameter-autocast.asm b/src/test/ref/call-parameter-autocast.asm new file mode 100644 index 000000000..f75244267 --- /dev/null +++ b/src/test/ref/call-parameter-autocast.asm @@ -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+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 +} diff --git a/src/test/ref/call-parameter-autocast.cfg b/src/test/ref/call-parameter-autocast.cfg new file mode 100644 index 000000000..ad6fb6392 --- /dev/null +++ b/src/test/ref/call-parameter-autocast.cfg @@ -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 diff --git a/src/test/ref/call-parameter-autocast.log b/src/test/ref/call-parameter-autocast.log new file mode 100644 index 000000000..48c4e9409 --- /dev/null +++ b/src/test/ref/call-parameter-autocast.log @@ -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+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+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+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 +} + diff --git a/src/test/ref/call-parameter-autocast.sym b/src/test/ref/call-parameter-autocast.sym new file mode 100644 index 000000000..9f212a185 --- /dev/null +++ b/src/test/ref/call-parameter-autocast.sym @@ -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 ] diff --git a/src/test/ref/pointer-void-1.asm b/src/test/ref/pointer-void-1.asm new file mode 100644 index 000000000..70e3113c1 --- /dev/null +++ b/src/test/ref/pointer-void-1.asm @@ -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+1 + jsr print + lda #vw + sta print.ptr+1 + jsr print + 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 +} diff --git a/src/test/ref/pointer-void-1.cfg b/src/test/ref/pointer-void-1.cfg new file mode 100644 index 000000000..9620ba507 --- /dev/null +++ b/src/test/ref/pointer-void-1.cfg @@ -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 diff --git a/src/test/ref/pointer-void-1.log b/src/test/ref/pointer-void-1.log new file mode 100644 index 000000000..3e9ff67cb --- /dev/null +++ b/src/test/ref/pointer-void-1.log @@ -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+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+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+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+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+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+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+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+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+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 +} + diff --git a/src/test/ref/pointer-void-1.sym b/src/test/ref/pointer-void-1.sym new file mode 100644 index 000000000..4d3db1b07 --- /dev/null +++ b/src/test/ref/pointer-void-1.sym @@ -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 ]