diff --git a/compiler/res/version.txt b/compiler/res/version.txt index d96ae405e..a7a768e6f 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -1.52 +1.53-dev diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 9bcfb9626..999814aa1 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -21,37 +21,39 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge is NumericLiteralValue -> translateExpression(expression) is RegisterExpr -> translateExpression(expression) is IdentifierReference -> translateExpression(expression) - is FunctionCall -> { - val functionName = expression.target.nameInSource.last() - val builtinFunc = BuiltinFunctions[functionName] - if(builtinFunc!=null) { - asmgen.translateFunctioncallExpression(expression, builtinFunc) - } else { - asmgen.translateFunctionCall(expression) - val sub = expression.target.targetSubroutine(program.namespace)!! - val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters) - for((_, reg) in returns) { - if(!reg.stack) { - // result value in cpu or status registers, put it on the stack - if(reg.registerOrPair!=null) { - when(reg.registerOrPair) { - RegisterOrPair.A -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") - RegisterOrPair.Y -> asmgen.out(" tya | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") - RegisterOrPair.AY -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | tya | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") - RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY -> throw AssemblyError("can't push X register - use a variable") - } - } - // return value from a statusregister is not put on the stack, it should be acted on via a conditional branch such as if_cc - } - } - } - } + is FunctionCall -> translateExpression(expression) is ArrayLiteralValue, is StringLiteralValue -> TODO("string/array/struct assignment?") is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened") is RangeExpr -> throw AssemblyError("range expression should have been changed into array values") } } + private fun translateExpression(expression: FunctionCall) { + val functionName = expression.target.nameInSource.last() + val builtinFunc = BuiltinFunctions[functionName] + if (builtinFunc != null) { + asmgen.translateFunctioncallExpression(expression, builtinFunc) + } else { + asmgen.translateFunctionCall(expression) + val sub = expression.target.targetSubroutine(program.namespace)!! + val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters) + for ((_, reg) in returns) { + if (!reg.stack) { + // result value in cpu or status registers, put it on the stack + if (reg.registerOrPair != null) { + when (reg.registerOrPair) { + RegisterOrPair.A -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + RegisterOrPair.Y -> asmgen.out(" tya | sta ${MachineDefinition.ESTACK_LO_HEX},x | dex") + RegisterOrPair.AY -> asmgen.out(" sta ${MachineDefinition.ESTACK_LO_HEX},x | tya | sta ${MachineDefinition.ESTACK_HI_HEX},x | dex") + RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY -> throw AssemblyError("can't push X register - use a variable") + } + } + // return value from a statusregister is not put on the stack, it should be acted on via a conditional branch such as if_cc + } + } + } + } + private fun translateExpression(expr: TypecastExpression) { translateExpression(expr.expression) when(expr.expression.inferType(program).typeOrElse(DataType.STRUCT)) { @@ -175,7 +177,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge private val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40) private val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40) - private val powerOfTwos = setOf(0,1,2,4,8,16,32,64,128,256) + private val powersOfTwo = setOf(0,1,2,4,8,16,32,64,128,256) private fun translateExpression(expr: BinaryExpression) { val leftIDt = expr.left.inferType(program) @@ -215,7 +217,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge if(value!=null) { if(rightDt in IntegerDatatypes) { val amount = value.number.toInt() - if(amount in powerOfTwos) + if(amount in powersOfTwo) printWarning("${expr.right.position} multiplication by power of 2 should have been optimized into a left shift instruction: $amount") when(rightDt) { DataType.UBYTE -> { @@ -312,7 +314,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } } - private fun translatePushFromArray(arrayExpr: ArrayIndexedExpression) { // assume *reading* from an array val index = arrayExpr.arrayspec.index diff --git a/compiler/src/prog8/optimizer/SimplifyExpressions.kt b/compiler/src/prog8/optimizer/SimplifyExpressions.kt index 2dc1acd79..ba51530a0 100644 --- a/compiler/src/prog8/optimizer/SimplifyExpressions.kt +++ b/compiler/src/prog8/optimizer/SimplifyExpressions.kt @@ -608,8 +608,8 @@ internal class SimplifyExpressions(private val program: Program) : IAstModifying } - private val powersOfTwo = (1 .. 16).map { (2.0).pow(it) } - private val negativePowersOfTwo = powersOfTwo.map { -it } + private val powersOfTwo = (1 .. 16).map { (2.0).pow(it) }.toSet() + private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet() private fun optimizeDivision(expr: BinaryExpression, leftVal: NumericLiteralValue?, rightVal: NumericLiteralValue?): Expression { if(leftVal==null && rightVal==null) @@ -712,7 +712,7 @@ internal class SimplifyExpressions(private val program: Program) : IAstModifying optimizationsDone++ return expr.left } - 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 2048.0, 4096.0, 8192.0, 16384.0, 32768.0, 65536.0 -> { + in powersOfTwo -> { if(leftValue.inferType(program).typeOrElse(DataType.STRUCT) in IntegerDatatypes) { // times a power of two => shift left optimizationsDone++ @@ -720,7 +720,7 @@ internal class SimplifyExpressions(private val program: Program) : IAstModifying return BinaryExpression(expr.left, "<<", NumericLiteralValue.optimalInteger(numshifts, expr.position), expr.position) } } - -2.0, -4.0, -8.0, -16.0, -32.0, -64.0, -128.0, -256.0, -512.0, -1024.0, -2048.0, -4096.0, -8192.0, -16384.0, -32768.0, -65536.0 -> { + in negativePowersOfTwo -> { if(leftValue.inferType(program).typeOrElse(DataType.STRUCT) in IntegerDatatypes) { // times a negative power of two => negate, then shift left optimizationsDone++ diff --git a/examples/cube3d-sprites.p8 b/examples/cube3d-sprites.p8 index ed2840c0a..60c6c6366 100644 --- a/examples/cube3d-sprites.p8 +++ b/examples/cube3d-sprites.p8 @@ -1,8 +1,6 @@ %import c64lib %import c64utils -; TODO: some optimizer breaks this.. runs fine without optimization - spritedata $2000 { ; this memory block contains the sprite data ; it must start on an address aligned to 64 bytes. diff --git a/examples/testarrays.p8 b/examples/testarrays.p8 index 9f505035c..1cf1afa60 100644 --- a/examples/testarrays.p8 +++ b/examples/testarrays.p8 @@ -2,7 +2,7 @@ %zeropage basicsafe %option enable_floats -; TODO complete codegeneration for all lines in this +; TODO complete asm code generation for all lines in this