From 08697892141424d4b0e24ffc38ce25f05ce203cd Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 2 May 2022 23:38:32 +0200 Subject: [PATCH] vm: implement float type casts to integer types --- .../prog8/codegen/virtual/ExpressionGen.kt | 27 ++++++------ docs/source/todo.rst | 2 +- examples/test.p8 | 25 +++++------ virtualmachine/src/prog8/vm/Assembler.kt | 34 ++++++++++----- virtualmachine/src/prog8/vm/Instructions.kt | 2 - virtualmachine/src/prog8/vm/VirtualMachine.kt | 42 ++++++++++++++++++- 6 files changed, 92 insertions(+), 40 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index e43aebff6..f77d34cce 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -9,6 +9,7 @@ import prog8.code.core.PassByValueDatatypes import prog8.code.core.SignedDatatypes import prog8.vm.Opcode import prog8.vm.VmDataType +import java.nio.channels.FileLock internal class ExpressionGen(private val codeGen: CodeGen) { @@ -59,7 +60,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister) } } - is PtTypeCast -> code += translate(expr, resultRegister) + is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister) is PtPrefix -> code += translate(expr, resultRegister) is PtArrayIndexer -> code += translate(expr, resultRegister) is PtBinaryExpression -> code += translate(expr, resultRegister, resultFpRegister) @@ -192,27 +193,29 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return code } - private fun translate(cast: PtTypeCast, resultRegister: Int): VmCodeChunk { + private fun translate(cast: PtTypeCast, resultRegister: Int, predefinedResultFpRegister: Int): VmCodeChunk { val code = VmCodeChunk() if(cast.type==cast.value.type) return code - code += translateExpression(cast.value, resultRegister, -1) + val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.vmRegisters.nextFreeFloat() + if(cast.value.type==DataType.FLOAT) { + // a cast from float to integer, so evaluate the value into a float register first + code += translateExpression(cast.value, -1, actualResultFpReg) + } + else + code += translateExpression(cast.value, resultRegister, -1) when(cast.type) { DataType.UBYTE -> { when(cast.value.type) { DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ } - DataType.FLOAT -> { - TODO("float -> ubyte") // float not yet supported - } + DataType.FLOAT -> code += VmCodeInstruction(Opcode.FTOUB, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg) else -> throw AssemblyError("weird cast value type") } } DataType.BYTE -> { when(cast.value.type) { DataType.UBYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ } - DataType.FLOAT -> { - TODO("float -> byte") // float not yet supported - } + DataType.FLOAT -> code += VmCodeInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg) else -> throw AssemblyError("weird cast value type") } } @@ -228,7 +231,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } DataType.WORD -> { } DataType.FLOAT -> { - TODO("float -> uword") // float not yet supported + code += VmCodeInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg) } else -> throw AssemblyError("weird cast value type") } @@ -245,13 +248,13 @@ internal class ExpressionGen(private val codeGen: CodeGen) { } DataType.UWORD -> { } DataType.FLOAT -> { - TODO("float -> word") // float not yet supported + code += VmCodeInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = actualResultFpReg) } else -> throw AssemblyError("weird cast value type") } } DataType.FLOAT -> { - TODO("floating point not yet supported") + TODO("floating point to integer cast not yet supported") // when(cast.value.type) { // DataType.BYTE -> { // } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 1db6e94ac..a95ea0d2e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,7 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- vm: implement float type casts to integer types +- compiler: fix crash when print_ub(float as ubyte) - vm: implement float any, all, reverse, sort - vm: fix test fp calc result being 0 - vm: get rid of intermediate floats.xxx() functions somehow, instead generate the float instructions directly? diff --git a/examples/test.p8 b/examples/test.p8 index a02c64d3b..1dc492a47 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -8,22 +8,19 @@ main { sub start() { - float fl1 = 500.0 - float fzero = 0.0 - floats.print_f(fl1 / fzero) + float fl = -4.567 + float fl2 = fl / 1.0 + floats.print_f(fl2) + txt.nl() + txt.print_ub(fl2 as ubyte) ; TODO fix crash source dt size must be less or equal to target dt size + txt.nl() + txt.print_b(fl2 as byte) ; TODO fix crash + txt.nl() + txt.print_uw(fl2 as uword) ; TODO fix crash + txt.nl() + txt.print_w(fl2 as word) ; TODO fix crash txt.nl() - ubyte ub1 = 50 - ubyte ubzero = 0 - txt.print_ub(ub1/ubzero) - txt.nl() - - uword uw1 = 5000 - uword uwzero = 0 - txt.print_uw(uw1/uwzero) - txt.nl() - -; float fl = 500.0 ; txt.print("rad 180 = ") ; floats.print_f(floats.rad(180.0)) ; txt.print("rad 360 = ") diff --git a/virtualmachine/src/prog8/vm/Assembler.kt b/virtualmachine/src/prog8/vm/Assembler.kt index 515780962..7aa06986c 100644 --- a/virtualmachine/src/prog8/vm/Assembler.kt +++ b/virtualmachine/src/prog8/vm/Assembler.kt @@ -82,6 +82,18 @@ class Assembler { val (_, instr, typestr, rest) = match.groupValues val opcode = Opcode.valueOf(instr.uppercase()) var type: VmDataType? = convertType(typestr) + val formats = instructionFormats.getValue(opcode) + val format: InstructionFormat + if(type !in formats) { + type = VmDataType.BYTE + format = if(type !in formats) + formats.getValue(null) + else + formats.getValue(type) + } else { + format = formats.getValue(type) + } + // parse the operands val operands = rest.lowercase().split(",").toMutableList() var reg1: Int? = null var reg2: Int? = null @@ -129,17 +141,19 @@ class Assembler { } } } - val formats = instructionFormats.getValue(opcode) - val format: InstructionFormat - if(type !in formats) { - type = VmDataType.BYTE - format = if(type !in formats) - formats.getValue(null) - else - formats.getValue(type) - } else { - format = formats.getValue(type) + + // shift the operands back into place + while(reg1==null && reg2!=null) { + reg1 = reg2 + reg2 = reg3 + reg3 = null } + while(fpReg1==null && fpReg2!=null) { + fpReg1 = fpReg2 + fpReg2 = fpReg3 + fpReg3 = null + } + if(type!=null && type !in formats) throw IllegalArgumentException("invalid type code for $line") if(format.reg1 && reg1==null) diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index 72e08b0a1..119352cfc 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -330,8 +330,6 @@ data class Instruction( if (type==VmDataType.FLOAT) { if(format.fpValue && (fpValue==null && symbol==null)) throw IllegalArgumentException("$opcode: missing a fp-value or symbol") - if (reg1 != null || reg2 != null || reg3 != null) - throw java.lang.IllegalArgumentException("$opcode: floating point instruction can't use integer registers") } else { if(format.value && (value==null && symbol==null)) throw IllegalArgumentException("$opcode: missing a value or symbol") diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 5b00e86ad..d64ec7f7e 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -172,6 +172,27 @@ class VirtualMachine(val memory: Memory, program: List) { Opcode.BREAKPOINT -> InsBREAKPOINT() Opcode.CLC -> { statusCarry = false; pc++ } Opcode.SEC -> { statusCarry = true; pc++ } + + Opcode.FFROMUB -> TODO() + Opcode.FFROMSB -> TODO() + Opcode.FFROMUW -> TODO() + Opcode.FFROMSW -> TODO() + Opcode.FTOUB -> InsFTOUB(ins) + Opcode.FTOSB -> InsFTOSB(ins) + Opcode.FTOUW -> InsFTOUW(ins) + Opcode.FTOSW -> InsFTOSW(ins) + Opcode.FPOW -> TODO() + Opcode.FABS -> TODO() + Opcode.FSIN -> TODO() + Opcode.FCOS -> TODO() + Opcode.FTAN -> TODO() + Opcode.FATAN -> TODO() + Opcode.FLN -> TODO() + Opcode.FLOG -> TODO() + Opcode.FSQRT -> TODO() + Opcode.FROUND -> TODO() + Opcode.FFLOOR -> TODO() + Opcode.FCEIL -> TODO() else -> throw IllegalArgumentException("invalid opcode ${ins.opcode}") } } @@ -1041,6 +1062,26 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } + private fun InsFTOUB(i: Instruction) { + registers.setUB(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toUByte()) + pc++ + } + + private fun InsFTOUW(i: Instruction) { + registers.setUW(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toUShort()) + pc++ + } + + private fun InsFTOSB(i: Instruction) { + registers.setSB(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toByte()) + pc++ + } + + private fun InsFTOSW(i: Instruction) { + registers.setSW(i.reg1!!, registers.getFloat(i.fpReg1!!).toInt().toShort()) + pc++ + } + private fun getBranchOperands(i: Instruction): Pair { return when(i.type) { VmDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt()) @@ -1085,7 +1126,6 @@ class VirtualMachine(val memory: Memory, program: List) { } } - private fun getSetOnConditionOperands(ins: Instruction): Triple { return when(ins.type) { VmDataType.BYTE -> Triple(ins.reg1!!, registers.getSB(ins.reg2!!).toInt(), registers.getSB(ins.reg3!!).toInt())