diff --git a/src/main/java/dk/camelot64/kickc/TODO.txt b/src/main/java/dk/camelot64/kickc/TODO.txt index a347d889a..1161a61ac 100644 --- a/src/main/java/dk/camelot64/kickc/TODO.txt +++ b/src/main/java/dk/camelot64/kickc/TODO.txt @@ -7,6 +7,7 @@ Known Problems - (useuninitialized.kc) Using an uninitialized variable fails in the optimizer phase. It should fail much earlier. Features +- Inline contants that are only call parameters used once (eg. x0#0 and x0#1 in callconstparam.kc) - Move the main code into a main() function, and disallow code outside functions. The main function per default has no parameters and exits with RTS. - Improve locality of block sequence for if(cond) { stmt1; } else { stmt2; } to if(!cond) goto @else stmt1; jmp @end; @else: stmt2; @end: - Optimize if/else by swapping if & else if cond is easier to evaluate than !cond. @@ -31,6 +32,12 @@ Features - Add UpliftRemains support for attempting to uplift potentials to ALU (requires modifying two registers: 1. the ALU potential to ALU - the one added to the ALU potential to A.) - Support array-initializer syntax as literal word syntax. byte* plotter = { lo, hi }; +Word Math +- Support Word table lookup (through 2 byte-tables) +- Support word math operations (addition, subtraction) +- Implement a word-ALU +- Usage: word[] plotter_x; word[] plotter_y; byte* plotter = plotter_x[x] + plotter_y[y]; -> lda plotter_x_lo,x; clc; adc plotter_y_lo,y; sta plotter; lda plotter_x_hi,x; adc plotter_y_hi,y; sta plotter+1 + Arrays / Strings / Inline data - New semantic: Arrays are always allocated inline (and must therefore have a size). Pointers are never. - Allow complex array expressions in lValues eg. (SCREEN+$100)[idx] @@ -72,6 +79,8 @@ Register Allocation - Improve combination testing by finding live range overlaps and not creating combinations that would create an overlap conflict. - Combinations should be created in a tree-structure instead of just doing all combinations - Example: For equivalence classes a, b, c if a&c have overlapping live ranges they can never have the same register. Therefore the combination iterator should not create combinations where C has the same register as a. +- Optimize registers in local windows - creating smaller sets of combinations. Currently some programs easily has millions of possible combinations. + Process/Code Structure Improvement - Eliminate copy visitor @@ -149,4 +158,6 @@ Done + Make each phase return a separate object graph (allowing for keeeping the history in memory & performing rollbacks) + Remove "string" keyword (if it exists). + Support hi/lo-byte lvalues - plotter = plot_xhi[x]+plot_yhi[y]; -+ Add ALU support for lo/hi operators on pointers - to avoid unnecessary zp-variable holding for cases like byte v = y&$7 | (); this.program = program; String conditionalJumpSignature = conditionalJumpSignature(conditionalJump, block, graph); @@ -47,7 +47,7 @@ public class AsmFragment { } public AsmFragment(StatementAssignment assignment, Program program) { - this.scope = program.getGraph().getBlockFromStatementIdx(assignment.getIndex()).getScope(); + this.codeScopeRef = program.getGraph().getBlockFromStatementIdx(assignment.getIndex()).getScope(); this.bindings = new LinkedHashMap<>(); this.program = program; setSignature(assignmentSignature( @@ -57,65 +57,22 @@ public class AsmFragment { assignment.getrValue2())); } - public AsmFragment(LValue lValue, RValue rValue, Program program, ScopeRef scope) { - this.scope = scope; + public AsmFragment(LValue lValue, RValue rValue, Program program, ScopeRef codeScopeRef) { + this.codeScopeRef = codeScopeRef; this.bindings = new LinkedHashMap<>(); this.program = program; setSignature(assignmentSignature(lValue, null, null, rValue)); } public AsmFragment(StatementAssignment assignment, StatementAssignment assignmentAlu, Program program) { - this.scope = program.getGraph().getBlockFromStatementIdx(assignment.getIndex()).getScope(); + this.codeScopeRef = program.getGraph().getBlockFromStatementIdx(assignment.getIndex()).getScope(); this.bindings = new LinkedHashMap<>(); this.program = program; setSignature(assignmentWithAluSignature(assignment, assignmentAlu)); } - /** - * Get ASM code for a constant value - * - * @param value The constant value - * @param precedence The precedence of the outer expression operator. Used to generate perenthesis when needed. - * - * @return The ASM string representing the constant value - */ - public static String getAsmConstant(Program program, ConstantValue value, int precedence) { - if (value instanceof ConstantRef) { - ConstantVar constantVar = program.getScope().getConstant((ConstantRef) value); - String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName(); - return asmName.replace("#", "_").replace("$", "_"); - } else if (value instanceof ConstantInteger) { - return getAsmNumber(((ConstantInteger) value).getNumber()); - } else if (value instanceof ConstantChar) { - return "'"+((ConstantChar) value).getValue()+"'"; - } else if (value instanceof ConstantString) { - return "\""+((ConstantString) value).getValue()+"\""; - } else if (value instanceof ConstantUnary) { - ConstantUnary unary = (ConstantUnary) value; - Operator operator = unary.getOperator(); - boolean parenthesis = operator.getPrecedence()>precedence; - return - (parenthesis ? "(" : "") + - operator.getOperator() + - getAsmConstant(program, unary.getOperand(), operator.getPrecedence()) + - (parenthesis? ")" : ""); - } else if (value instanceof ConstantBinary) { - ConstantBinary binary = (ConstantBinary) value; - Operator operator = binary.getOperator(); - boolean parenthesis = operator.getPrecedence()>precedence; - return - (parenthesis? "(" : "") + - getAsmConstant(program, binary.getLeft(), operator.getPrecedence()) + - operator.getOperator() + - getAsmConstant(program, binary.getRight(), operator.getPrecedence()) + - (parenthesis? ")" : ""); - } else { - throw new RuntimeException("Constant type not supported " + value); - } - } - private String assignmentWithAluSignature(StatementAssignment assignment, StatementAssignment assignmentAlu) { - this.scope = program.getGraph().getBlockFromStatementIdx(assignment.getIndex()).getScope(); + this.codeScopeRef = program.getGraph().getBlockFromStatementIdx(assignment.getIndex()).getScope(); if (!(assignment.getrValue2() instanceof VariableRef)) { throw new AluNotApplicableException("Error! ALU register only allowed as rValue2. " + assignment); } @@ -291,6 +248,11 @@ public class AsmFragment { this.signature = signature; } + private Scope getCodeScope() { + return program.getScope().getScope(codeScopeRef); + } + + /** * Zero page register name indexing. */ @@ -436,18 +398,18 @@ public class AsmFragment { Variable boundVar = (Variable) boundValue; Registers.Register register = boundVar.getAllocation(); if (register != null && register instanceof Registers.RegisterZp) { - return new AsmParameter(getAsmParameter(boundVar), true); + return new AsmParameter(getAsmParamName(boundVar), true); } else { throw new RuntimeException("Register Type not implemented " + register); } } else if (boundValue instanceof ConstantVar) { ConstantVar constantVar = (ConstantVar) boundValue; - String constantValueAsm = getAsmConstant(program, constantVar.getRef(), 99); + String constantValueAsm = getAsmConstant(program, constantVar.getRef(), 99, getCodeScope()); boolean constantValueZp = SymbolTypeBasic.BYTE.equals(constantVar.getType(program.getScope())); return new AsmParameter(constantValueAsm, constantValueZp); } else if (boundValue instanceof ConstantValue) { ConstantValue boundConst = (ConstantValue) boundValue; - String constantValueAsm = getAsmConstant(program, boundConst, 99); + String constantValueAsm = getAsmConstant(program, boundConst, 99, getCodeScope()); boolean constantValueZp = SymbolTypeBasic.BYTE.equals(boundConst.getType(program.getScope())); return new AsmParameter(constantValueAsm, constantValueZp); } else if (boundValue instanceof Label) { @@ -458,6 +420,50 @@ public class AsmFragment { } } + /** + * Get ASM code for a constant value + * + * @param value The constant value + * @param precedence The precedence of the outer expression operator. Used to generate perenthesis when needed. + * @param codeScope The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope). + * + * @return The ASM string representing the constant value + */ + public static String getAsmConstant(Program program, ConstantValue value, int precedence, Scope codeScope) { + if (value instanceof ConstantRef) { + ConstantVar constantVar = program.getScope().getConstant((ConstantRef) value); + String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName(); + return getAsmParamName(constantVar.getScope(), asmName, codeScope); + } else if (value instanceof ConstantInteger) { + return getAsmNumber(((ConstantInteger) value).getNumber()); + } else if (value instanceof ConstantChar) { + return "'"+((ConstantChar) value).getValue()+"'"; + } else if (value instanceof ConstantString) { + return "\""+((ConstantString) value).getValue()+"\""; + } else if (value instanceof ConstantUnary) { + ConstantUnary unary = (ConstantUnary) value; + Operator operator = unary.getOperator(); + boolean parenthesis = operator.getPrecedence()>precedence; + return + (parenthesis ? "(" : "") + + operator.getOperator() + + getAsmConstant(program, unary.getOperand(), operator.getPrecedence(), codeScope) + + (parenthesis? ")" : ""); + } else if (value instanceof ConstantBinary) { + ConstantBinary binary = (ConstantBinary) value; + Operator operator = binary.getOperator(); + boolean parenthesis = operator.getPrecedence()>precedence; + return + (parenthesis? "(" : "") + + getAsmConstant(program, binary.getLeft(), operator.getPrecedence(), codeScope) + + operator.getOperator() + + getAsmConstant(program, binary.getRight(), operator.getPrecedence(), codeScope) + + (parenthesis? ")" : ""); + } else { + throw new RuntimeException("Constant type not supported " + value); + } + } + public static String getAsmNumber(Number number) { if(number instanceof Integer) { if(number.intValue()>=0 && number.intValue()<=9) { @@ -474,31 +480,33 @@ public class AsmFragment { * @param boundVar The variable * @return The ASM parameter to use in the ASM code */ - private String getAsmParameter(Variable boundVar) { + private String getAsmParamName(Variable boundVar) { Scope varScope = boundVar.getScope(); String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName(); - return getAsmParameter(varScope, asmName); + return getAsmParamName(varScope, asmName, getCodeScope()); } + /** * Get the ASM parameter for a specific bound constant * @param boundVar The constant * @return The ASM parameter to use in the ASM code */ - private String getAsmParameter(ConstantVar boundVar) { + private String getAsmParamName(ConstantVar boundVar) { Scope varScope = boundVar.getScope(); String asmName = boundVar.getAsmName() == null ? boundVar.getLocalName() : boundVar.getAsmName(); - return getAsmParameter(varScope, asmName); + return getAsmParamName(varScope, asmName, getCodeScope()); } /** * Get the ASM parameter for a specific bound constant/ variable * @param varScope The scope containing the var/const * @param asmName The ASM name of the variable (local name or specific ASM name). + * @param codeScope The scope containing the code being generated. Used for adding scope to the name when needed (eg. line.x1 when referencing x1 variable inside line scope from outside line scope). * @return The ASM parameter to use in the ASM code */ - private String getAsmParameter(Scope varScope, String asmName) { - if (!varScope.getRef().equals(scope) && varScope.getRef().getFullName().length() > 0) { + private static String getAsmParamName(Scope varScope, String asmName, Scope codeScope) { + if (!varScope.equals(codeScope) && varScope.getRef().getFullName().length() > 0) { String param = varScope.getFullName() + "." + asmName .replace('@', 'b') .replace(':', '_') diff --git a/src/main/java/dk/camelot64/kickc/fragment/asm/aby_lt_xby_then_la1.asm b/src/main/java/dk/camelot64/kickc/fragment/asm/aby_lt_xby_then_la1.asm new file mode 100644 index 000000000..4ee83b60d --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/fragment/asm/aby_lt_xby_then_la1.asm @@ -0,0 +1,3 @@ +stx $ff +cmp $ff +bcc {la1} \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/model/Registers.java b/src/main/java/dk/camelot64/kickc/model/Registers.java index 9d92ac738..91d66ce34 100644 --- a/src/main/java/dk/camelot64/kickc/model/Registers.java +++ b/src/main/java/dk/camelot64/kickc/model/Registers.java @@ -236,6 +236,13 @@ public class Registers { /** Special register used for constants. Has no corresponding CPU register. */ public static class RegisterConstant implements Register { + + private ConstantValue constantValue; + + public RegisterConstant(ConstantValue constantValue) { + this.constantValue = constantValue; + } + @Override public RegisterType getType() { return RegisterType.CONSTANT; @@ -246,20 +253,28 @@ public class Registers { return false; } + public ConstantValue getConstantValue() { + return constantValue; + } + @Override public String toString(Program program) { - return "const"; + return "const "+constantValue.toString(program); } @Override public int hashCode() { - return 31; + return constantValue != null ? constantValue.hashCode() : 0; } @Override - public boolean equals(Object obj) { - return obj instanceof RegisterConstant; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RegisterConstant that = (RegisterConstant) o; + return constantValue != null ? constantValue.equals(that.constantValue) : that.constantValue == null; } + } } diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 84cce1c47..10229ff03 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -95,7 +95,7 @@ public class Pass4CodeGeneration { if(! (constantVar.getValue() instanceof ConstantArray || constantVar.getValue() instanceof ConstantString)) { String asmName = constantVar.getAsmName() == null ? constantVar.getLocalName() : constantVar.getAsmName(); if (asmName != null && !added.contains(asmName)) { - asm.addConstant(asmName.replace("#", "_").replace("$", "_"), AsmFragment.getAsmConstant(program, constantVar.getValue(), 99)); + asm.addConstant(asmName.replace("#", "_").replace("$", "_"), AsmFragment.getAsmConstant(program, constantVar.getValue(), 99, scope)); added.add(asmName); } } @@ -119,7 +119,7 @@ public class Pass4CodeGeneration { if (asmName != null && !added.contains(asmName)) { List asmElements = new ArrayList<>(); for (ConstantValue element : constantArray.getElements()) { - String asmElement = AsmFragment.getAsmConstant(program, element, 99); + String asmElement = AsmFragment.getAsmConstant(program, element, 99, scope); asmElements.add(asmElement); } if(SymbolTypeBasic.BYTE.equals(constantArray.getElementType())) { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java index c6b173126..49fd6d18c 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java @@ -74,7 +74,7 @@ public class Pass4RegistersFinalize extends Pass2Base { for (ConstantVar constantVar : scope.getAllConstants(false)) { String asmName = constantVar.getAsmName(); - Registers.Register allocation = new Registers.RegisterConstant(); + Registers.Register allocation = new Registers.RegisterConstant(constantVar.getValue()); if (asmName.contains("#")) { String shortName = asmName.substring(0, asmName.indexOf("#")); if (shortNames.get(shortName) == null || shortNames.get(shortName).equals(allocation)) { diff --git a/src/main/java/dk/camelot64/kickc/test/TestErrors.java b/src/main/java/dk/camelot64/kickc/test/TestErrors.java index 4a9593d27..bc3d1216a 100644 --- a/src/main/java/dk/camelot64/kickc/test/TestErrors.java +++ b/src/main/java/dk/camelot64/kickc/test/TestErrors.java @@ -53,11 +53,6 @@ public class TestErrors extends TestCase { compileAndCompare(filename); } - public void testCallConstParamProblem() throws IOException, URISyntaxException { - String filename = "callconstparamproblem"; - compileAndCompare(filename); - } - private void compileAndCompare(String filename) throws IOException, URISyntaxException { TestErrors tester = new TestErrors(); tester.testFile(filename); diff --git a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java index 3493f2184..f13b8c29d 100644 --- a/src/main/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/main/java/dk/camelot64/kickc/test/TestPrograms.java @@ -28,6 +28,12 @@ public class TestPrograms extends TestCase { compileAndCompare("bitmap-bresenham"); } + public void testCallConstParam() throws IOException, URISyntaxException { + String filename = "callconstparam"; + compileAndCompare(filename); + } + + public void testScrollClobber() throws IOException, URISyntaxException { compileAndCompare("scroll-clobber"); } diff --git a/src/main/java/dk/camelot64/kickc/test/bitmap-bresenham.kc b/src/main/java/dk/camelot64/kickc/test/bitmap-bresenham.kc index fcde9528d..a35594fbd 100644 --- a/src/main/java/dk/camelot64/kickc/test/bitmap-bresenham.kc +++ b/src/main/java/dk/camelot64/kickc/test/bitmap-bresenham.kc @@ -93,6 +93,8 @@ void plot(byte x, byte y) { plotter = plot_xhi[x]+plot_yhi[y]; // TODO: plotter part. Requires new logic? + // TODO: New logic needed is 1) word-table lookup (split into two byte-tables) 2) word-addition 3) ALU-capable word-addition + *plotter = *plotter | plot_bit[x]; } diff --git a/src/main/java/dk/camelot64/kickc/test/callconstparamproblem.kc b/src/main/java/dk/camelot64/kickc/test/callconstparam.kc similarity index 100% rename from src/main/java/dk/camelot64/kickc/test/callconstparamproblem.kc rename to src/main/java/dk/camelot64/kickc/test/callconstparam.kc diff --git a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.asm b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.asm index 17710d51b..1847436e7 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.asm +++ b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.asm @@ -30,18 +30,18 @@ main: { sta D018 jsr initscreen jsr initplottables - lda #y0 + lda #line.y0 sta line.y ldx #$a - lda #x0 + lda #line.x0 sta line.x lda #$14 sta line.x1 jsr line - lda #y0 + lda #line.y0_1 sta line.y ldx #$28 - lda #x0 + lda #line.x0_1 sta line.x lda #$28 sta line.x1 @@ -51,6 +51,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label xd = 8 .label yd = 9 .label x = 3 diff --git a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log index 5fe510154..e38b7fb34 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log +++ b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.log @@ -93,6 +93,8 @@ void plot(byte x, byte y) { plotter = plot_xhi[x]+plot_yhi[y]; // TODO: plotter part. Requires new logic? + // TODO: New logic needed is 1) word-table lookup (split into two byte-tables) 2) word-addition 3) ALU-capable word-addition + *plotter = *plotter | plot_bit[x]; } @@ -5900,13 +5902,13 @@ main: { //SEG17 [10] phi from main::@2 to line [phi:main::@2->line] line_from_b2: //SEG18 [10] phi (byte) line::y#0 = (const byte) line::y0#0 [phi:main::@2->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0 sta line.y //SEG19 [10] phi (byte) line::y1#2 = (byte) 10 [phi:main::@2->line#1] -- zpby1=coby1 lda #$a sta line.y1 //SEG20 [10] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main::@2->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0 sta line.x //SEG21 [10] phi (byte) line::x1#2 = (byte) 20 [phi:main::@2->line#3] -- zpby1=coby1 lda #$14 @@ -5919,13 +5921,13 @@ main: { //SEG24 [10] phi from main::@3 to line [phi:main::@3->line] line_from_b3: //SEG25 [10] phi (byte) line::y#0 = (const byte) line::y0#1 [phi:main::@3->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0_1 sta line.y //SEG26 [10] phi (byte) line::y1#2 = (byte) 40 [phi:main::@3->line#1] -- zpby1=coby1 lda #$28 sta line.y1 //SEG27 [10] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@3->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0_1 sta line.x //SEG28 [10] phi (byte) line::x1#2 = (byte) 40 [phi:main::@3->line#3] -- zpby1=coby1 lda #$28 @@ -5941,6 +5943,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label _10 = 20 .label xd = 16 .label yd = 17 @@ -6567,12 +6571,12 @@ main: { //SEG17 [10] phi from main::@2 to line [phi:main::@2->line] line_from_b2: //SEG18 [10] phi (byte) line::y#0 = (const byte) line::y0#0 [phi:main::@2->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0 sta line.y //SEG19 [10] phi (byte) line::y1#2 = (byte) 10 [phi:main::@2->line#1] -- xby=coby1 ldx #$a //SEG20 [10] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main::@2->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0 sta line.x //SEG21 [10] phi (byte) line::x1#2 = (byte) 20 [phi:main::@2->line#3] -- zpby1=coby1 lda #$14 @@ -6584,12 +6588,12 @@ main: { //SEG24 [10] phi from main::@3 to line [phi:main::@3->line] line_from_b3: //SEG25 [10] phi (byte) line::y#0 = (const byte) line::y0#1 [phi:main::@3->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0_1 sta line.y //SEG26 [10] phi (byte) line::y1#2 = (byte) 40 [phi:main::@3->line#1] -- xby=coby1 ldx #$28 //SEG27 [10] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@3->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0_1 sta line.x //SEG28 [10] phi (byte) line::x1#2 = (byte) 40 [phi:main::@3->line#3] -- zpby1=coby1 lda #$28 @@ -6604,6 +6608,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label xd = 8 .label yd = 9 .label x = 3 @@ -6969,12 +6975,12 @@ main: { //SEG17 [10] phi from main::@2 to line [phi:main::@2->line] line_from_b2: //SEG18 [10] phi (byte) line::y#0 = (const byte) line::y0#0 [phi:main::@2->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0 sta line.y //SEG19 [10] phi (byte) line::y1#2 = (byte) 10 [phi:main::@2->line#1] -- xby=coby1 ldx #$a //SEG20 [10] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main::@2->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0 sta line.x //SEG21 [10] phi (byte) line::x1#2 = (byte) 20 [phi:main::@2->line#3] -- zpby1=coby1 lda #$14 @@ -6986,12 +6992,12 @@ main: { //SEG24 [10] phi from main::@3 to line [phi:main::@3->line] line_from_b3: //SEG25 [10] phi (byte) line::y#0 = (const byte) line::y0#1 [phi:main::@3->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0_1 sta line.y //SEG26 [10] phi (byte) line::y1#2 = (byte) 40 [phi:main::@3->line#1] -- xby=coby1 ldx #$28 //SEG27 [10] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@3->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0_1 sta line.x //SEG28 [10] phi (byte) line::x1#2 = (byte) 40 [phi:main::@3->line#3] -- zpby1=coby1 lda #$28 @@ -7006,6 +7012,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label xd = 8 .label yd = 9 .label x = 3 @@ -7387,12 +7395,12 @@ main: { //SEG16 [7] call line param-assignment [ ] //SEG17 [10] phi from main::@2 to line [phi:main::@2->line] //SEG18 [10] phi (byte) line::y#0 = (const byte) line::y0#0 [phi:main::@2->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0 sta line.y //SEG19 [10] phi (byte) line::y1#2 = (byte) 10 [phi:main::@2->line#1] -- xby=coby1 ldx #$a //SEG20 [10] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main::@2->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0 sta line.x //SEG21 [10] phi (byte) line::x1#2 = (byte) 20 [phi:main::@2->line#3] -- zpby1=coby1 lda #$14 @@ -7403,12 +7411,12 @@ main: { //SEG23 [8] call line param-assignment [ ] //SEG24 [10] phi from main::@3 to line [phi:main::@3->line] //SEG25 [10] phi (byte) line::y#0 = (const byte) line::y0#1 [phi:main::@3->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0_1 sta line.y //SEG26 [10] phi (byte) line::y1#2 = (byte) 40 [phi:main::@3->line#1] -- xby=coby1 ldx #$28 //SEG27 [10] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@3->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0_1 sta line.x //SEG28 [10] phi (byte) line::x1#2 = (byte) 40 [phi:main::@3->line#3] -- zpby1=coby1 lda #$28 @@ -7423,6 +7431,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label xd = 8 .label yd = 9 .label x = 3 @@ -7783,12 +7793,12 @@ main: { //SEG16 [7] call line param-assignment [ ] //SEG17 [10] phi from main::@2 to line [phi:main::@2->line] //SEG18 [10] phi (byte) line::y#0 = (const byte) line::y0#0 [phi:main::@2->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0 sta line.y //SEG19 [10] phi (byte) line::y1#2 = (byte) 10 [phi:main::@2->line#1] -- xby=coby1 ldx #$a //SEG20 [10] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main::@2->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0 sta line.x //SEG21 [10] phi (byte) line::x1#2 = (byte) 20 [phi:main::@2->line#3] -- zpby1=coby1 lda #$14 @@ -7798,12 +7808,12 @@ main: { //SEG23 [8] call line param-assignment [ ] //SEG24 [10] phi from main::@3 to line [phi:main::@3->line] //SEG25 [10] phi (byte) line::y#0 = (const byte) line::y0#1 [phi:main::@3->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0_1 sta line.y //SEG26 [10] phi (byte) line::y1#2 = (byte) 40 [phi:main::@3->line#1] -- xby=coby1 ldx #$28 //SEG27 [10] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@3->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0_1 sta line.x //SEG28 [10] phi (byte) line::x1#2 = (byte) 40 [phi:main::@3->line#3] -- zpby1=coby1 lda #$28 @@ -7817,6 +7827,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label xd = 8 .label yd = 9 .label x = 3 @@ -8150,12 +8162,12 @@ main: { //SEG16 [7] call line param-assignment [ ] //SEG17 [10] phi from main::@2 to line [phi:main::@2->line] //SEG18 [10] phi (byte) line::y#0 = (const byte) line::y0#0 [phi:main::@2->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0 sta line.y //SEG19 [10] phi (byte) line::y1#2 = (byte) 10 [phi:main::@2->line#1] -- xby=coby1 ldx #$a //SEG20 [10] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main::@2->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0 sta line.x //SEG21 [10] phi (byte) line::x1#2 = (byte) 20 [phi:main::@2->line#3] -- zpby1=coby1 lda #$14 @@ -8165,12 +8177,12 @@ main: { //SEG23 [8] call line param-assignment [ ] //SEG24 [10] phi from main::@3 to line [phi:main::@3->line] //SEG25 [10] phi (byte) line::y#0 = (const byte) line::y0#1 [phi:main::@3->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0_1 sta line.y //SEG26 [10] phi (byte) line::y1#2 = (byte) 40 [phi:main::@3->line#1] -- xby=coby1 ldx #$28 //SEG27 [10] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@3->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0_1 sta line.x //SEG28 [10] phi (byte) line::x1#2 = (byte) 40 [phi:main::@3->line#3] -- zpby1=coby1 lda #$28 @@ -8184,6 +8196,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label xd = 8 .label yd = 9 .label x = 3 @@ -8549,7 +8563,7 @@ FINAL SYMBOL TABLE (byte) line::x#2 x zp ZP_BYTE:3 8.75 (byte) line::x0 (const byte) line::x0#0 x0 = (byte) 0 -(const byte) line::x0#1 x0 = (byte) 10 +(const byte) line::x0#1 x0#1 = (byte) 10 (byte) line::x1 (byte) line::x1#2 x1 zp ZP_BYTE:2 0.8125 (byte) line::xd @@ -8561,7 +8575,7 @@ FINAL SYMBOL TABLE (byte) line::y#4 y zp ZP_BYTE:4 11.0 (byte) line::y0 (const byte) line::y0#0 y0 = (byte) 0 -(const byte) line::y0#1 y0 = (byte) 20 +(const byte) line::y0#1 y0#1 = (byte) 20 (byte) line::y1 (byte) line::y1#2 reg byte x 1.0 (byte) line::yd @@ -8679,12 +8693,12 @@ main: { //SEG16 [7] call line param-assignment [ ] //SEG17 [10] phi from main::@2 to line [phi:main::@2->line] //SEG18 [10] phi (byte) line::y#0 = (const byte) line::y0#0 [phi:main::@2->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0 sta line.y //SEG19 [10] phi (byte) line::y1#2 = (byte) 10 [phi:main::@2->line#1] -- xby=coby1 ldx #$a //SEG20 [10] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main::@2->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0 sta line.x //SEG21 [10] phi (byte) line::x1#2 = (byte) 20 [phi:main::@2->line#3] -- zpby1=coby1 lda #$14 @@ -8694,12 +8708,12 @@ main: { //SEG23 [8] call line param-assignment [ ] //SEG24 [10] phi from main::@3 to line [phi:main::@3->line] //SEG25 [10] phi (byte) line::y#0 = (const byte) line::y0#1 [phi:main::@3->line#0] -- zpby1=coby1 - lda #y0 + lda #line.y0_1 sta line.y //SEG26 [10] phi (byte) line::y1#2 = (byte) 40 [phi:main::@3->line#1] -- xby=coby1 ldx #$28 //SEG27 [10] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@3->line#2] -- zpby1=coby1 - lda #x0 + lda #line.x0_1 sta line.x //SEG28 [10] phi (byte) line::x1#2 = (byte) 40 [phi:main::@3->line#3] -- zpby1=coby1 lda #$28 @@ -8713,6 +8727,8 @@ main: { line: { .const x0 = 0 .const y0 = 0 + .const x0_1 = $a + .const y0_1 = $14 .label xd = 8 .label yd = 9 .label x = 3 diff --git a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.sym b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.sym index 62cc1e982..9475011d4 100644 --- a/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.sym +++ b/src/main/java/dk/camelot64/kickc/test/ref/bitmap-bresenham.sym @@ -90,7 +90,7 @@ (byte) line::x#2 x zp ZP_BYTE:3 8.75 (byte) line::x0 (const byte) line::x0#0 x0 = (byte) 0 -(const byte) line::x0#1 x0 = (byte) 10 +(const byte) line::x0#1 x0#1 = (byte) 10 (byte) line::x1 (byte) line::x1#2 x1 zp ZP_BYTE:2 0.8125 (byte) line::xd @@ -102,7 +102,7 @@ (byte) line::y#4 y zp ZP_BYTE:4 11.0 (byte) line::y0 (const byte) line::y0#0 y0 = (byte) 0 -(const byte) line::y0#1 y0 = (byte) 20 +(const byte) line::y0#1 y0#1 = (byte) 20 (byte) line::y1 (byte) line::y1#2 reg byte x 1.0 (byte) line::yd diff --git a/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.asm b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.asm new file mode 100644 index 000000000..889516435 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.asm @@ -0,0 +1,34 @@ + .label screen = 3 + jsr main +main: { + lda #2 + sta line.x1 + lda #<$400 + sta screen + lda #>$400 + sta screen+1 + ldx #line.x0 + jsr line + lda #5 + sta line.x1 + ldx #line.x0_1 + jsr line + rts +} +line: { + .const x0 = 1 + .const x0_1 = 3 + .label x1 = 2 + b1: + txa + ldy #0 + sta (screen),y + inc screen + bne !+ + inc screen+1 + !: + inx + cpx x1 + bcc b1 + rts +} diff --git a/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.cfg b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.cfg new file mode 100644 index 000000000..61ff454d0 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.cfg @@ -0,0 +1,30 @@ +@begin: scope:[] from + [0] call main param-assignment [ ] + to:@end +@end: scope:[] from @begin +main: scope:[main] from @begin + [1] phi() [ ] + [2] call line param-assignment [ ] + to:main::@1 +main::@1: scope:[main] from main + [3] call line param-assignment [ ] + to:main::@return +main::@return: scope:[main] from main::@1 + [4] return [ ] + to:@return +line: scope:[line] from main main::@1 + [5] (byte) line::x1#2 ← phi( main/(byte) 2 main::@1/(byte) 5 ) [ line::x#0 screen#14 line::x1#2 ] + [5] (byte*) screen#14 ← phi( main/(word) 1024 main::@1/(byte*) screen#1 ) [ line::x#0 screen#14 line::x1#2 ] + [5] (byte) line::x#0 ← phi( main/(const byte) line::x0#0 main::@1/(const byte) line::x0#1 ) [ line::x#0 screen#14 line::x1#2 ] + to:line::@1 +line::@1: scope:[line] from line line::@1 + [6] (byte*) screen#11 ← phi( line/(byte*) screen#14 line::@1/(byte*) screen#1 ) [ line::x1#2 line::x#2 screen#11 ] + [6] (byte) line::x#2 ← phi( line/(byte) line::x#0 line::@1/(byte) line::x#1 ) [ line::x1#2 line::x#2 screen#11 ] + [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] + [8] (byte*) screen#1 ← ++ (byte*) screen#11 [ line::x1#2 line::x#2 screen#1 ] + [9] (byte) line::x#1 ← ++ (byte) line::x#2 [ line::x1#2 line::x#1 screen#1 ] + [10] if((byte) line::x#1<(byte) line::x1#2) goto line::@1 [ line::x1#2 line::x#1 screen#1 ] + to:line::@return +line::@return: scope:[line] from line::@1 + [11] return [ ] + to:@return diff --git a/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.log b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.log new file mode 100644 index 000000000..98fa74bc9 --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.log @@ -0,0 +1,1241 @@ +// Multiple calls with different (constant?) parameters should yield different values at runtime +// Currently the same constant parameter is passed on every call. +// Reason: Multiple versioned parameter constants x0#0, x0#1 are only output as a single constant in the ASM .const x0 = 0 + +byte* screen = $0400; + +main(); + +void main() { + line(1,2); + line(3,5); +} + +void line(byte x0, byte x1) { + for(byte x = x0; xmain] +main_from_bbegin: + jsr main + jmp bend +//SEG4 @end +bend: +//SEG5 main +main: { + //SEG6 [2] call line param-assignment [ ] + //SEG7 [5] phi from main to line [phi:main->line] + line_from_main: + //SEG8 [5] phi (byte) line::x1#2 = (byte) 2 [phi:main->line#0] -- zpby1=coby1 + lda #2 + sta line.x1 + //SEG9 [5] phi (byte*) screen#14 = (word) 1024 [phi:main->line#1] -- zpptrby1=cowo1 + lda #<$400 + sta screen + lda #>$400 + sta screen+1 + //SEG10 [5] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main->line#2] -- zpby1=coby1 + lda #line.x0 + sta line.x + jsr line + jmp b1 + //SEG11 main::@1 + b1: + //SEG12 [3] call line param-assignment [ ] + //SEG13 [5] phi from main::@1 to line [phi:main::@1->line] + line_from_b1: + //SEG14 [5] phi (byte) line::x1#2 = (byte) 5 [phi:main::@1->line#0] -- zpby1=coby1 + lda #5 + sta line.x1 + //SEG15 [5] phi (byte*) screen#14 = (byte*) screen#1 [phi:main::@1->line#1] -- register_copy + //SEG16 [5] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@1->line#2] -- zpby1=coby1 + lda #line.x0_1 + sta line.x + jsr line + jmp breturn + //SEG17 main::@return + breturn: + //SEG18 [4] return [ ] + rts +} +//SEG19 line +line: { + .const x0 = 1 + .const x0_1 = 3 + .label x = 3 + .label x1 = 2 + //SEG20 [6] phi from line line::@1 to line::@1 [phi:line/line::@1->line::@1] + b1_from_line: + b1_from_b1: + //SEG21 [6] phi (byte*) screen#11 = (byte*) screen#14 [phi:line/line::@1->line::@1#0] -- register_copy + //SEG22 [6] phi (byte) line::x#2 = (byte) line::x#0 [phi:line/line::@1->line::@1#1] -- register_copy + jmp b1 + //SEG23 line::@1 + b1: + //SEG24 [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] -- _star_zpptrby1=zpby1 + ldy #0 + lda x + sta (screen),y + //SEG25 [8] (byte*) screen#1 ← ++ (byte*) screen#11 [ line::x1#2 line::x#2 screen#1 ] -- zpptrby1=_inc_zpptrby1 + inc screen + bne !+ + inc screen+1 + !: + //SEG26 [9] (byte) line::x#1 ← ++ (byte) line::x#2 [ line::x1#2 line::x#1 screen#1 ] -- zpby1=_inc_zpby1 + inc x + //SEG27 [10] if((byte) line::x#1<(byte) line::x1#2) goto line::@1 [ line::x1#2 line::x#1 screen#1 ] -- zpby1_lt_zpby2_then_la1 + lda x + cmp x1 + bcc b1_from_b1 + jmp breturn + //SEG28 line::@return + breturn: + //SEG29 [11] return [ ] + rts +} + +Statement [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] always clobbers reg byte y +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:2 [ line::x1#2 ] +Removing always clobbered register reg byte y as potential for zp ZP_BYTE:3 [ line::x#2 line::x#0 line::x#1 ] +Statement [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] always clobbers reg byte y +REGISTER UPLIFT POTENTIAL REGISTERS +Potential registers zp ZP_BYTE:2 [ line::x1#2 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , +Potential registers zp ZP_BYTE:3 [ line::x#2 line::x#0 line::x#1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , +Potential registers zp ZP_PTR_BYTE:4 [ screen#11 screen#14 screen#1 ] : zp ZP_PTR_BYTE:4 , + +REGISTER UPLIFT SCOPES +Uplift Scope [line] 30.17: zp ZP_BYTE:3 [ line::x#2 line::x#0 line::x#1 ] 1.83: zp ZP_BYTE:2 [ line::x1#2 ] +Uplift Scope [] 29.5: zp ZP_PTR_BYTE:4 [ screen#11 screen#14 screen#1 ] +Uplift Scope [main] + +Uplifting [line] best 423 combination reg byte x [ line::x#2 line::x#0 line::x#1 ] zp ZP_BYTE:2 [ line::x1#2 ] +Uplifting [] best 423 combination zp ZP_PTR_BYTE:4 [ screen#11 screen#14 screen#1 ] +Uplifting [main] best 423 combination +Attempting to uplift remaining variables inzp ZP_BYTE:2 [ line::x1#2 ] +Uplifting [line] best 423 combination zp ZP_BYTE:2 [ line::x1#2 ] +Allocated (was zp ZP_PTR_BYTE:4) zp ZP_PTR_BYTE:3 [ screen#11 screen#14 screen#1 ] +Removing instruction jmp bend +Removing instruction jmp b1 +Removing instruction jmp breturn +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +ASSEMBLER +//SEG0 Global Constants & labels + .label screen = 3 +//SEG1 @begin +bbegin: +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main [phi:@begin->main] +main_from_bbegin: + jsr main +//SEG4 @end +bend: +//SEG5 main +main: { + //SEG6 [2] call line param-assignment [ ] + //SEG7 [5] phi from main to line [phi:main->line] + line_from_main: + //SEG8 [5] phi (byte) line::x1#2 = (byte) 2 [phi:main->line#0] -- zpby1=coby1 + lda #2 + sta line.x1 + //SEG9 [5] phi (byte*) screen#14 = (word) 1024 [phi:main->line#1] -- zpptrby1=cowo1 + lda #<$400 + sta screen + lda #>$400 + sta screen+1 + //SEG10 [5] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main->line#2] -- xby=coby1 + ldx #line.x0 + jsr line + //SEG11 main::@1 + b1: + //SEG12 [3] call line param-assignment [ ] + //SEG13 [5] phi from main::@1 to line [phi:main::@1->line] + line_from_b1: + //SEG14 [5] phi (byte) line::x1#2 = (byte) 5 [phi:main::@1->line#0] -- zpby1=coby1 + lda #5 + sta line.x1 + //SEG15 [5] phi (byte*) screen#14 = (byte*) screen#1 [phi:main::@1->line#1] -- register_copy + //SEG16 [5] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@1->line#2] -- xby=coby1 + ldx #line.x0_1 + jsr line + //SEG17 main::@return + breturn: + //SEG18 [4] return [ ] + rts +} +//SEG19 line +line: { + .const x0 = 1 + .const x0_1 = 3 + .label x1 = 2 + //SEG20 [6] phi from line line::@1 to line::@1 [phi:line/line::@1->line::@1] + b1_from_line: + b1_from_b1: + //SEG21 [6] phi (byte*) screen#11 = (byte*) screen#14 [phi:line/line::@1->line::@1#0] -- register_copy + //SEG22 [6] phi (byte) line::x#2 = (byte) line::x#0 [phi:line/line::@1->line::@1#1] -- register_copy + //SEG23 line::@1 + b1: + //SEG24 [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] -- _star_zpptrby1=xby + txa + ldy #0 + sta (screen),y + //SEG25 [8] (byte*) screen#1 ← ++ (byte*) screen#11 [ line::x1#2 line::x#2 screen#1 ] -- zpptrby1=_inc_zpptrby1 + inc screen + bne !+ + inc screen+1 + !: + //SEG26 [9] (byte) line::x#1 ← ++ (byte) line::x#2 [ line::x1#2 line::x#1 screen#1 ] -- xby=_inc_xby + inx + //SEG27 [10] if((byte) line::x#1<(byte) line::x1#2) goto line::@1 [ line::x1#2 line::x#1 screen#1 ] -- xby_lt_zpby1_then_la1 + cpx x1 + bcc b1_from_b1 + //SEG28 line::@return + breturn: + //SEG29 [11] return [ ] + rts +} + +Replacing label b1_from_b1 with b1 +Removing instruction main_from_bbegin: +Removing instruction line_from_b1: +Removing instruction b1_from_line: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +ASSEMBLER +//SEG0 Global Constants & labels + .label screen = 3 +//SEG1 @begin +bbegin: +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main [phi:@begin->main] + jsr main +//SEG4 @end +bend: +//SEG5 main +main: { + //SEG6 [2] call line param-assignment [ ] + //SEG7 [5] phi from main to line [phi:main->line] + line_from_main: + //SEG8 [5] phi (byte) line::x1#2 = (byte) 2 [phi:main->line#0] -- zpby1=coby1 + lda #2 + sta line.x1 + //SEG9 [5] phi (byte*) screen#14 = (word) 1024 [phi:main->line#1] -- zpptrby1=cowo1 + lda #<$400 + sta screen + lda #>$400 + sta screen+1 + //SEG10 [5] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main->line#2] -- xby=coby1 + ldx #line.x0 + jsr line + //SEG11 main::@1 + b1: + //SEG12 [3] call line param-assignment [ ] + //SEG13 [5] phi from main::@1 to line [phi:main::@1->line] + //SEG14 [5] phi (byte) line::x1#2 = (byte) 5 [phi:main::@1->line#0] -- zpby1=coby1 + lda #5 + sta line.x1 + //SEG15 [5] phi (byte*) screen#14 = (byte*) screen#1 [phi:main::@1->line#1] -- register_copy + //SEG16 [5] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@1->line#2] -- xby=coby1 + ldx #line.x0_1 + jsr line + //SEG17 main::@return + breturn: + //SEG18 [4] return [ ] + rts +} +//SEG19 line +line: { + .const x0 = 1 + .const x0_1 = 3 + .label x1 = 2 + //SEG20 [6] phi from line line::@1 to line::@1 [phi:line/line::@1->line::@1] + //SEG21 [6] phi (byte*) screen#11 = (byte*) screen#14 [phi:line/line::@1->line::@1#0] -- register_copy + //SEG22 [6] phi (byte) line::x#2 = (byte) line::x#0 [phi:line/line::@1->line::@1#1] -- register_copy + //SEG23 line::@1 + b1: + //SEG24 [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] -- _star_zpptrby1=xby + txa + ldy #0 + sta (screen),y + //SEG25 [8] (byte*) screen#1 ← ++ (byte*) screen#11 [ line::x1#2 line::x#2 screen#1 ] -- zpptrby1=_inc_zpptrby1 + inc screen + bne !+ + inc screen+1 + !: + //SEG26 [9] (byte) line::x#1 ← ++ (byte) line::x#2 [ line::x1#2 line::x#1 screen#1 ] -- xby=_inc_xby + inx + //SEG27 [10] if((byte) line::x#1<(byte) line::x1#2) goto line::@1 [ line::x1#2 line::x#1 screen#1 ] -- xby_lt_zpby1_then_la1 + cpx x1 + bcc b1 + //SEG28 line::@return + breturn: + //SEG29 [11] return [ ] + rts +} + +Removing instruction bbegin: +Removing instruction bend: +Removing instruction line_from_main: +Removing instruction b1: +Removing instruction breturn: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +ASSEMBLER +//SEG0 Global Constants & labels + .label screen = 3 +//SEG1 @begin +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main [phi:@begin->main] + jsr main +//SEG4 @end +//SEG5 main +main: { + //SEG6 [2] call line param-assignment [ ] + //SEG7 [5] phi from main to line [phi:main->line] + //SEG8 [5] phi (byte) line::x1#2 = (byte) 2 [phi:main->line#0] -- zpby1=coby1 + lda #2 + sta line.x1 + //SEG9 [5] phi (byte*) screen#14 = (word) 1024 [phi:main->line#1] -- zpptrby1=cowo1 + lda #<$400 + sta screen + lda #>$400 + sta screen+1 + //SEG10 [5] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main->line#2] -- xby=coby1 + ldx #line.x0 + jsr line + //SEG11 main::@1 + //SEG12 [3] call line param-assignment [ ] + //SEG13 [5] phi from main::@1 to line [phi:main::@1->line] + //SEG14 [5] phi (byte) line::x1#2 = (byte) 5 [phi:main::@1->line#0] -- zpby1=coby1 + lda #5 + sta line.x1 + //SEG15 [5] phi (byte*) screen#14 = (byte*) screen#1 [phi:main::@1->line#1] -- register_copy + //SEG16 [5] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@1->line#2] -- xby=coby1 + ldx #line.x0_1 + jsr line + //SEG17 main::@return + //SEG18 [4] return [ ] + rts +} +//SEG19 line +line: { + .const x0 = 1 + .const x0_1 = 3 + .label x1 = 2 + //SEG20 [6] phi from line line::@1 to line::@1 [phi:line/line::@1->line::@1] + //SEG21 [6] phi (byte*) screen#11 = (byte*) screen#14 [phi:line/line::@1->line::@1#0] -- register_copy + //SEG22 [6] phi (byte) line::x#2 = (byte) line::x#0 [phi:line/line::@1->line::@1#1] -- register_copy + //SEG23 line::@1 + b1: + //SEG24 [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] -- _star_zpptrby1=xby + txa + ldy #0 + sta (screen),y + //SEG25 [8] (byte*) screen#1 ← ++ (byte*) screen#11 [ line::x1#2 line::x#2 screen#1 ] -- zpptrby1=_inc_zpptrby1 + inc screen + bne !+ + inc screen+1 + !: + //SEG26 [9] (byte) line::x#1 ← ++ (byte) line::x#2 [ line::x1#2 line::x#1 screen#1 ] -- xby=_inc_xby + inx + //SEG27 [10] if((byte) line::x#1<(byte) line::x1#2) goto line::@1 [ line::x1#2 line::x#1 screen#1 ] -- xby_lt_zpby1_then_la1 + cpx x1 + bcc b1 + //SEG28 line::@return + //SEG29 [11] return [ ] + rts +} + +FINAL SYMBOL TABLE +(label) @begin +(label) @end +(void()) line((byte) line::x0 , (byte) line::x1) +(label) line::@1 +(label) line::@return +(byte) line::x +(byte) line::x#0 reg byte x 2.0 +(byte) line::x#1 reg byte x 16.5 +(byte) line::x#2 reg byte x 11.666666666666666 +(byte) line::x0 +(const byte) line::x0#0 x0 = (byte) 1 +(const byte) line::x0#1 x0#1 = (byte) 3 +(byte) line::x1 +(byte) line::x1#2 x1 zp ZP_BYTE:2 1.8333333333333333 +(void()) main() +(label) main::@1 +(label) main::@return +(byte*) screen +(byte*) screen#1 screen zp ZP_PTR_BYTE:3 8.0 +(byte*) screen#11 screen zp ZP_PTR_BYTE:3 17.5 +(byte*) screen#14 screen zp ZP_PTR_BYTE:3 4.0 + +zp ZP_BYTE:2 [ line::x1#2 ] +reg byte x [ line::x#2 line::x#0 line::x#1 ] +zp ZP_PTR_BYTE:3 [ screen#11 screen#14 screen#1 ] + +FINAL CODE +//SEG0 Global Constants & labels + .label screen = 3 +//SEG1 @begin +//SEG2 [0] call main param-assignment [ ] +//SEG3 [1] phi from @begin to main [phi:@begin->main] + jsr main +//SEG4 @end +//SEG5 main +main: { + //SEG6 [2] call line param-assignment [ ] + //SEG7 [5] phi from main to line [phi:main->line] + //SEG8 [5] phi (byte) line::x1#2 = (byte) 2 [phi:main->line#0] -- zpby1=coby1 + lda #2 + sta line.x1 + //SEG9 [5] phi (byte*) screen#14 = (word) 1024 [phi:main->line#1] -- zpptrby1=cowo1 + lda #<$400 + sta screen + lda #>$400 + sta screen+1 + //SEG10 [5] phi (byte) line::x#0 = (const byte) line::x0#0 [phi:main->line#2] -- xby=coby1 + ldx #line.x0 + jsr line + //SEG11 main::@1 + //SEG12 [3] call line param-assignment [ ] + //SEG13 [5] phi from main::@1 to line [phi:main::@1->line] + //SEG14 [5] phi (byte) line::x1#2 = (byte) 5 [phi:main::@1->line#0] -- zpby1=coby1 + lda #5 + sta line.x1 + //SEG15 [5] phi (byte*) screen#14 = (byte*) screen#1 [phi:main::@1->line#1] -- register_copy + //SEG16 [5] phi (byte) line::x#0 = (const byte) line::x0#1 [phi:main::@1->line#2] -- xby=coby1 + ldx #line.x0_1 + jsr line + //SEG17 main::@return + //SEG18 [4] return [ ] + rts +} +//SEG19 line +line: { + .const x0 = 1 + .const x0_1 = 3 + .label x1 = 2 + //SEG20 [6] phi from line line::@1 to line::@1 [phi:line/line::@1->line::@1] + //SEG21 [6] phi (byte*) screen#11 = (byte*) screen#14 [phi:line/line::@1->line::@1#0] -- register_copy + //SEG22 [6] phi (byte) line::x#2 = (byte) line::x#0 [phi:line/line::@1->line::@1#1] -- register_copy + //SEG23 line::@1 + b1: + //SEG24 [7] *((byte*) screen#11) ← (byte) line::x#2 [ line::x1#2 line::x#2 screen#11 ] -- _star_zpptrby1=xby + txa + ldy #0 + sta (screen),y + //SEG25 [8] (byte*) screen#1 ← ++ (byte*) screen#11 [ line::x1#2 line::x#2 screen#1 ] -- zpptrby1=_inc_zpptrby1 + inc screen + bne !+ + inc screen+1 + !: + //SEG26 [9] (byte) line::x#1 ← ++ (byte) line::x#2 [ line::x1#2 line::x#1 screen#1 ] -- xby=_inc_xby + inx + //SEG27 [10] if((byte) line::x#1<(byte) line::x1#2) goto line::@1 [ line::x1#2 line::x#1 screen#1 ] -- xby_lt_zpby1_then_la1 + cpx x1 + bcc b1 + //SEG28 line::@return + //SEG29 [11] return [ ] + rts +} + diff --git a/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.sym b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.sym new file mode 100644 index 000000000..4d3b23ebc --- /dev/null +++ b/src/main/java/dk/camelot64/kickc/test/ref/callconstparam.sym @@ -0,0 +1,25 @@ +(label) @begin +(label) @end +(void()) line((byte) line::x0 , (byte) line::x1) +(label) line::@1 +(label) line::@return +(byte) line::x +(byte) line::x#0 reg byte x 2.0 +(byte) line::x#1 reg byte x 16.5 +(byte) line::x#2 reg byte x 11.666666666666666 +(byte) line::x0 +(const byte) line::x0#0 x0 = (byte) 1 +(const byte) line::x0#1 x0#1 = (byte) 3 +(byte) line::x1 +(byte) line::x1#2 x1 zp ZP_BYTE:2 1.8333333333333333 +(void()) main() +(label) main::@1 +(label) main::@return +(byte*) screen +(byte*) screen#1 screen zp ZP_PTR_BYTE:3 8.0 +(byte*) screen#11 screen zp ZP_PTR_BYTE:3 17.5 +(byte*) screen#14 screen zp ZP_PTR_BYTE:3 4.0 + +zp ZP_BYTE:2 [ line::x1#2 ] +reg byte x [ line::x#2 line::x#0 line::x#1 ] +zp ZP_PTR_BYTE:3 [ screen#11 screen#14 screen#1 ]