diff --git a/compiler/examples/cube3d.p8 b/compiler/examples/cube3d.p8 index 7bc493d8e..02a1b3352 100644 --- a/compiler/examples/cube3d.p8 +++ b/compiler/examples/cube3d.p8 @@ -84,11 +84,11 @@ byte e_to sub toscreenx(x: float, z: float) -> word { - return floor(x/(4.2+z) * height) + width // 2 + return floor(x/(4.2+z) * flt(height)) + width // 2 } sub toscreeny(y: float, z: float) -> word { - return floor(y/(4.2+z) * height) + height // 2 + return floor(y/(4.2+z) * flt(height)) + height // 2 } ; draw all edges of the object diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index d490cc986..ea708fd8b 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -135,7 +135,120 @@ class StackVmProgram(val name: String, val heap: HeapValues) { println("\nOptimizing stackVM code...") this.instructions.removeIf { it.opcode==Opcode.NOP && it !is LabelInstr } // remove nops (that are not a label) - // todo optimize stackvm code + + // - push value followed by a data type conversion -> push the value in the correct type and remove the conversion + // - push somthing followed by a discard -> remove both + + val typeConversionOpcodes = setOf( + Opcode.LSB, + Opcode.MSB, + Opcode.B2WORD, + Opcode.MSB2WORD, + Opcode.B2FLOAT, + Opcode.W2FLOAT, + Opcode.DISCARD, + Opcode.DISCARD_W, + Opcode.DISCARD_F + ) + + val instructionsToReplace = mutableMapOf() + val instructionsToRemove = mutableListOf() + + this.instructions.withIndex().windowed(2).forEach { + if(it[1].value.opcode in typeConversionOpcodes) { + when(it[0].value.opcode) { + Opcode.PUSH -> when (it[1].value.opcode) { + Opcode.LSB -> instructionsToRemove.add(it[1].index) + Opcode.MSB -> throw CompilerException("msb of a byte") + Opcode.B2WORD -> { + val ins = Instruction(Opcode.PUSH_W, Value(DataType.WORD, it[0].value.arg!!.integerValue())) + instructionsToReplace[it[0].index] = ins + instructionsToRemove.add(it[1].index) + } + Opcode.MSB2WORD -> { + val ins = Instruction(Opcode.PUSH_W, Value(DataType.WORD, 256 * it[0].value.arg!!.integerValue())) + instructionsToReplace[it[0].index] = ins + instructionsToRemove.add(it[1].index) + } + Opcode.B2FLOAT -> { + val ins = Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, it[0].value.arg!!.integerValue().toDouble())) + instructionsToReplace[it[0].index] = ins + instructionsToRemove.add(it[1].index) + } + Opcode.W2FLOAT -> throw CompilerException("invalid conversion following a byte") + Opcode.DISCARD -> { + instructionsToRemove.add(it[0].index) + instructionsToRemove.add(it[1].index) + } + Opcode.DISCARD_W, Opcode.DISCARD_F -> throw CompilerException("invalid discard type following a byte") + else -> {} + } + Opcode.PUSH_W -> when (it[1].value.opcode) { + Opcode.LSB -> { + val ins = Instruction(Opcode.PUSH, Value(DataType.BYTE, it[0].value.arg!!.integerValue() and 255)) + instructionsToReplace[it[0].index] = ins + instructionsToRemove.add(it[1].index) + } + Opcode.MSB -> { + val ins = Instruction(Opcode.PUSH, Value(DataType.BYTE, it[0].value.arg!!.integerValue() ushr 8 and 255)) + instructionsToReplace[it[0].index] = ins + instructionsToRemove.add(it[1].index) + } + Opcode.B2WORD, + Opcode.MSB2WORD, + Opcode.B2FLOAT -> throw CompilerException("invalid conversion following a word") + Opcode.W2FLOAT -> { + val ins = Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, it[0].value.arg!!.integerValue().toDouble())) + instructionsToReplace[it[0].index] = ins + instructionsToRemove.add(it[1].index) + } + Opcode.DISCARD_W -> { + instructionsToRemove.add(it[0].index) + instructionsToRemove.add(it[1].index) + } + Opcode.DISCARD, Opcode.DISCARD_F -> throw CompilerException("invalid discard type following a byte") + else -> {} + } + Opcode.PUSH_F -> when (it[1].value.opcode) { + Opcode.LSB, + Opcode.MSB, + Opcode.B2WORD, + Opcode.MSB2WORD, + Opcode.B2FLOAT, + Opcode.W2FLOAT -> throw CompilerException("invalid conversion following a float") + Opcode.DISCARD_F -> { + instructionsToRemove.add(it[0].index) + instructionsToRemove.add(it[1].index) + } + Opcode.DISCARD, Opcode.DISCARD_W -> throw CompilerException("invalid discard type following a float") + else -> {} + } + Opcode.PUSH_VAR_F, + Opcode.PUSH_VAR_W, + Opcode.PUSH_VAR, + Opcode.PUSH_MEM, + Opcode.PUSH_MEM_W, + Opcode.PUSH_MEM_F -> when (it[1].value.opcode) { + Opcode.DISCARD_F, Opcode.DISCARD_W, Opcode.DISCARD -> { + instructionsToRemove.add(it[0].index) + instructionsToRemove.add(it[1].index) + } + else -> {} + } + else -> {} + } + } + } + + for(rins in instructionsToReplace) { + instructions[rins.key] = rins.value + } + + for(ins in instructionsToRemove.reversed()) { + instructions.removeAt(ins) + } + + // todo optimize stackvm code more } fun blockvar(scopedname: String, decl: VarDecl) { diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index a791807b0..f91b5c916 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -103,10 +103,10 @@ enum class Opcode { BITXOR_W, INV, INV_W, + + // numeric type conversions LSB, MSB, - - // numeric type conversions not covered by other opcodes B2WORD, // convert a byte into a word where it is the lower eight bits $00xx MSB2WORD, // convert a byte into a word where it is the upper eight bits $xx00 B2FLOAT, // convert byte into floating point