diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 7d2fe437e..5ba21dc8a 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -309,6 +309,24 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, } } + private fun opcodeAdd(dt: DataType): Opcode { + return when (dt) { + DataType.BYTE -> Opcode.ADD_B + DataType.WORD -> Opcode.ADD_W + DataType.FLOAT -> Opcode.ADD_F + else -> throw CompilerException("invalid dt $dt") + } + } + + private fun opcodeSub(dt: DataType): Opcode { + return when (dt) { + DataType.BYTE -> Opcode.SUB_B + DataType.WORD -> Opcode.SUB_W + DataType.FLOAT -> Opcode.SUB_F + else -> throw CompilerException("invalid dt $dt") + } + } + private fun opcodePushvar(dt: DataType): Opcode { return when (dt) { DataType.BYTE -> Opcode.PUSH_VAR @@ -711,14 +729,62 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, if(leftDt!=rightDt) throw CompilerException("operands have different datatypes") val opcode = when(operator) { - // todo variants depending on leftdt/rightdt (b/w/f) - "+" -> Opcode.ADD - "-" -> Opcode.SUB - "*" -> Opcode.MUL - "/" -> Opcode.DIV - "//" -> Opcode.FLOORDIV - "%" -> Opcode.REMAINDER - "**" -> Opcode.POW + "+" -> { + when(leftDt) { + DataType.BYTE -> Opcode.ADD_B + DataType.WORD -> Opcode.ADD_W + DataType.FLOAT -> Opcode.ADD_F + else -> throw CompilerException("only byte/word/float possible") + } + } + "-" -> { + when(leftDt) { + DataType.BYTE -> Opcode.SUB_B + DataType.WORD -> Opcode.SUB_W + DataType.FLOAT -> Opcode.SUB_F + else -> throw CompilerException("only byte/word/float possible") + } + } + "*" -> { + when(leftDt) { + DataType.BYTE -> Opcode.MUL_B + DataType.WORD -> Opcode.MUL_W + DataType.FLOAT -> Opcode.MUL_F + else -> throw CompilerException("only byte/word/float possible") + } + } + "/" -> { + when(leftDt) { + DataType.BYTE -> Opcode.DIV_B + DataType.WORD -> Opcode.DIV_W + DataType.FLOAT -> Opcode.DIV_F + else -> throw CompilerException("only byte/word/float possible") + } + } + "//" -> { + when(leftDt) { + DataType.BYTE -> Opcode.FLOORDIV_B + DataType.WORD -> Opcode.FLOORDIV_W + DataType.FLOAT -> Opcode.FLOORDIV_F + else -> throw CompilerException("only byte/word/float possible") + } + } + "%" -> { + when(leftDt) { + DataType.BYTE -> Opcode.REMAINDER_B + DataType.WORD -> Opcode.REMAINDER_W + DataType.FLOAT -> Opcode.REMAINDER_F + else -> throw CompilerException("only byte/word/float possible") + } + } + "**" -> { + when(leftDt) { + DataType.BYTE -> Opcode.POW_B + DataType.WORD -> Opcode.POW_W + DataType.FLOAT -> Opcode.POW_F + else -> throw CompilerException("only byte/word/float possible") + } + } "&" -> { when(leftDt) { DataType.BYTE -> Opcode.BITAND @@ -819,7 +885,14 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, throw CompilerException("operand datatype not known") val opcode = when(operator) { "+" -> Opcode.NOP - "-" -> Opcode.NEG // todo b/w/f + "-" -> { + when (operandDt) { + DataType.BYTE -> Opcode.NEG_B + DataType.WORD -> Opcode.NEG_W + DataType.FLOAT -> Opcode.NEG_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } "~" -> { when(operandDt) { DataType.BYTE -> Opcode.INV @@ -858,9 +931,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, // calc matrix index i=y*columns+x // (the const-folding will have removed this for us when both x and y are constants) translate(y) - stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, (variable!!.arrayspec!!.x as LiteralValue).asIntegerValue!!)) - stackvmProg.instr(Opcode.MUL) - stackvmProg.instr(Opcode.ADD) + stackvmProg.instr(Opcode.PUSH, Value(DataType.WORD, (variable!!.arrayspec!!.x as LiteralValue).asIntegerValue!!)) + stackvmProg.instr(Opcode.MUL_W) + stackvmProg.instr(Opcode.ADD_W) } if(write) @@ -921,8 +994,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, val opcode = opcodePush(one.type) stackvmProg.instr(opcode, one) when(stmt.operator) { - "++" -> stackvmProg.instr(Opcode.ADD) - "--" -> stackvmProg.instr(Opcode.SUB) + "++" -> stackvmProg.instr(opcodeAdd(one.type)) + "--" -> stackvmProg.instr(opcodeSub(one.type)) } translate(stmt.target.arrayindexed!!, true) } @@ -1008,12 +1081,54 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, if(valueDt !in validDt) throw CompilerException("invalid datatype(s) for operand(s)") val opcode = when(aug_op) { - "+=" -> Opcode.ADD - "-=" -> Opcode.SUB - "/=" -> Opcode.DIV - "//=" -> Opcode.FLOORDIV - "*=" -> Opcode.MUL - "**=" -> Opcode.POW + "+=" -> { + when (valueDt) { + DataType.BYTE -> Opcode.ADD_B + DataType.WORD -> Opcode.ADD_W + DataType.FLOAT -> Opcode.ADD_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "-=" -> { + when (valueDt) { + DataType.BYTE -> Opcode.SUB_B + DataType.WORD -> Opcode.SUB_W + DataType.FLOAT -> Opcode.SUB_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "/=" -> { + when (valueDt) { + DataType.BYTE -> Opcode.DIV_B + DataType.WORD -> Opcode.DIV_W + DataType.FLOAT -> Opcode.DIV_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "//=" -> { + when (valueDt) { + DataType.BYTE -> Opcode.FLOORDIV_B + DataType.WORD -> Opcode.FLOORDIV_W + DataType.FLOAT -> Opcode.FLOORDIV_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "*=" -> { + when (valueDt) { + DataType.BYTE -> Opcode.MUL_B + DataType.WORD -> Opcode.MUL_W + DataType.FLOAT -> Opcode.MUL_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } + "**=" -> { + when (valueDt) { + DataType.BYTE -> Opcode.POW_B + DataType.WORD -> Opcode.POW_W + DataType.FLOAT -> Opcode.POW_F + else -> throw CompilerException("only byte/word/lfoat possible") + } + } "&=" -> { when(valueDt) { DataType.BYTE -> Opcode.BITAND @@ -1200,7 +1315,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, // TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH / SUB opcodes and make use of the wrapping around of the value. stackvmProg.instr(opcodePush(zero.type), Value(zero.type, numElements)) stackvmProg.instr(opcodePushvar(zero.type), callLabel = indexVar) - stackvmProg.instr(Opcode.SUB) + stackvmProg.instr(opcodeSub(zero.type)) stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel) stackvmProg.label(breakLabel) @@ -1248,13 +1363,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, range.step>1 -> { stackvmProg.instr(opcodePushvar(varDt), callLabel = varname) stackvmProg.instr(opcodePush(varDt), Value(varDt, range.step)) - stackvmProg.instr(Opcode.ADD) + stackvmProg.instr(opcodeSub(varDt)) stackvmProg.instr(opcodePopvar(varDt), callLabel = varname) } range.step<1 -> { stackvmProg.instr(opcodePushvar(varDt), callLabel = varname) stackvmProg.instr(opcodePush(varDt), Value(varDt, abs(range.step))) - stackvmProg.instr(Opcode.SUB) + stackvmProg.instr(opcodeSub(varDt)) stackvmProg.instr(opcodePopvar(varDt), callLabel = varname) } } @@ -1262,7 +1377,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, // TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH / SUB opcodes and make use of the wrapping around of the value. stackvmProg.instr(opcodePush(varDt), Value(varDt, range.last+range.step)) stackvmProg.instr(opcodePushvar(varDt), callLabel = varname) - stackvmProg.instr(Opcode.SUB) + stackvmProg.instr(opcodeSub(varDt)) stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel) stackvmProg.label(breakLabel) diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 52b1de2d9..a791807b0 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -33,14 +33,30 @@ enum class Opcode { POP_VAR_F, // pop float value into variable // numeric arithmetic - ADD, // todo b/w/f - SUB, // todo b/w/f - MUL, // todo b/w/f - DIV, // todo b/w/f - FLOORDIV, // todo b/w/f - REMAINDER, // todo b/w/f - POW, // todo b/w/f - NEG, // todo b/w/f + ADD_B, + ADD_W, + ADD_F, + SUB_B, + SUB_W, + SUB_F, + MUL_B, + MUL_W, + MUL_F, + DIV_B, + DIV_W, + DIV_F, + FLOORDIV_B, + FLOORDIV_W, + FLOORDIV_F, + REMAINDER_B, + REMAINDER_W, + REMAINDER_F, + POW_B, + POW_W, + POW_F, + NEG_B, + NEG_W, + NEG_F, // bit shifts and bitwise arithmetic SHL, @@ -470,44 +486,145 @@ class StackVm(private var traceOutputFile: String?) { val address = ins.arg!!.integerValue() mem.setFloat(address, value.numericValue().toDouble()) } - Opcode.ADD -> { + Opcode.ADD_B -> { val (top, second) = evalstack.pop2() - // todo b/w/f + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) evalstack.push(second.add(top)) } - Opcode.SUB -> { + Opcode.ADD_W -> { val (top, second) = evalstack.pop2() - // todo b/w/f + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(second.add(top)) + } + Opcode.ADD_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) + evalstack.push(second.add(top)) + } + Opcode.SUB_B -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) evalstack.push(second.sub(top)) } - Opcode.MUL -> { + Opcode.SUB_W -> { val (top, second) = evalstack.pop2() - // todo b/w/f + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(second.sub(top)) + } + Opcode.SUB_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) + evalstack.push(second.sub(top)) + } + Opcode.MUL_B -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) evalstack.push(second.mul(top)) } - Opcode.DIV -> { + Opcode.MUL_W -> { val (top, second) = evalstack.pop2() - // todo b/w/f + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(second.mul(top)) + } + Opcode.MUL_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) + evalstack.push(second.mul(top)) + } + Opcode.DIV_B -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) evalstack.push(second.div(top)) } - Opcode.FLOORDIV -> { + Opcode.DIV_W -> { val (top, second) = evalstack.pop2() - // todo b/w/f + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(second.div(top)) + } + Opcode.DIV_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) + evalstack.push(second.div(top)) + } + Opcode.FLOORDIV_B -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) evalstack.push(second.floordiv(top)) } - Opcode.REMAINDER -> { + Opcode.FLOORDIV_W -> { val (top, second) = evalstack.pop2() - // todo b/w/f + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(second.floordiv(top)) + } + Opcode.FLOORDIV_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) + evalstack.push(second.floordiv(top)) + } + Opcode.REMAINDER_B -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) evalstack.push(second.remainder(top)) } - Opcode.POW -> { + Opcode.REMAINDER_W -> { val (top, second) = evalstack.pop2() - // todo b/w/f + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(second.remainder(top)) + } + Opcode.REMAINDER_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) + evalstack.push(second.remainder(top)) + } + Opcode.POW_B -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.BYTE) + checkDt(second, DataType.BYTE) evalstack.push(second.pow(top)) } - Opcode.NEG -> { + Opcode.POW_W -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.WORD) + checkDt(second, DataType.WORD) + evalstack.push(second.pow(top)) + } + Opcode.POW_F -> { + val (top, second) = evalstack.pop2() + checkDt(top, DataType.FLOAT) + checkDt(second, DataType.FLOAT) + evalstack.push(second.pow(top)) + } + Opcode.NEG_B -> { val v = evalstack.pop() - // todo b/w/f + checkDt(v, DataType.BYTE) + evalstack.push(v.neg()) + } + Opcode.NEG_W -> { + val v = evalstack.pop() + checkDt(v, DataType.WORD) + evalstack.push(v.neg()) + } + Opcode.NEG_F -> { + val v = evalstack.pop() + checkDt(v, DataType.FLOAT) evalstack.push(v.neg()) } Opcode.SHL -> { diff --git a/compiler/src/prog8/stackvm/Value.kt b/compiler/src/prog8/stackvm/Value.kt index 4098e1194..6663c29e3 100644 --- a/compiler/src/prog8/stackvm/Value.kt +++ b/compiler/src/prog8/stackvm/Value.kt @@ -97,17 +97,11 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) { } private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): Value { + if(leftDt!=rightDt) + throw VmExecutionException("left and right datatypes are not the same") if(result.toDouble() < 0 ) { return when(leftDt) { - DataType.BYTE -> { - // BYTE can become WORD if right operand is WORD, or when value is too large for byte - when(rightDt) { - DataType.BYTE -> Value(DataType.BYTE, result.toInt() and 255) - DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535) - DataType.FLOAT -> throw VmExecutionException("floating point loss of precision") - else -> throw VmExecutionException("$op on non-numeric result type") - } - } + DataType.BYTE -> Value(DataType.BYTE, result.toInt() and 255) DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535) DataType.FLOAT -> Value(DataType.FLOAT, result) else -> throw VmExecutionException("$op on non-numeric type") @@ -115,22 +109,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) { } return when(leftDt) { - DataType.BYTE -> { - // BYTE can become WORD if right operand is WORD, or when value is too large for byte - if(result.toDouble() >= 256 && rightDt!=DataType.FLOAT) - return Value(DataType.WORD, result) - when(rightDt) { - DataType.BYTE -> Value(DataType.BYTE, result) - DataType.WORD -> Value(DataType.WORD, result) - DataType.FLOAT -> throw VmExecutionException("floating point loss of precision on byte") - else -> throw VmExecutionException("$op on non-numeric result type") - } - } - DataType.WORD -> { - if(rightDt==DataType.FLOAT) - throw VmExecutionException("floating point loss of precision on word") - Value(DataType.WORD, result) - } + DataType.BYTE -> Value(DataType.BYTE, result.toInt() and 255) + DataType.WORD -> Value(DataType.WORD, result.toInt() and 65535) DataType.FLOAT -> Value(DataType.FLOAT, result) else -> throw VmExecutionException("$op on non-numeric type") } diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index f3a7fc644..760f8fd83 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -253,60 +253,65 @@ class TestStackVmOpcodes { @Test fun testAdd() { - testBinaryOperator(Value(DataType.WORD, 4000), Opcode.ADD, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000+40)) - testBinaryOperator(Value(DataType.WORD, 4000+40), Opcode.ADD, Value(DataType.WORD, 123), Value(DataType.WORD, 4000+40+123)) + testBinaryOperator(Value(DataType.BYTE, 140), Opcode.ADD_B, Value(DataType.BYTE, 222), Value(DataType.BYTE, 106)) + testBinaryOperator(Value(DataType.BYTE, 40), Opcode.ADD_B, Value(DataType.BYTE, 122), Value(DataType.BYTE, 162)) + testBinaryOperator(Value(DataType.WORD, 4000), Opcode.ADD_W, Value(DataType.WORD, 40), Value(DataType.WORD, 4040)) + testBinaryOperator(Value(DataType.WORD, 24000), Opcode.ADD_W, Value(DataType.WORD, 55000), Value(DataType.WORD, 13464)) + testBinaryOperator(Value(DataType.FLOAT, 4000.0), Opcode.ADD_F, Value(DataType.FLOAT, 123.22), Value(DataType.FLOAT, 4123.22)) assertFailsWith { - testBinaryOperator(Value(DataType.WORD, 4000 + 40), Opcode.ADD, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 + (4000 + 40))) + testBinaryOperator(Value(DataType.WORD, 4000 + 40), Opcode.ADD_W, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 + (4000 + 40))) } } @Test fun testSub() { - testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.BYTE, 40), Value(DataType.WORD, 4000-40)) - testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB, Value(DataType.WORD, 123), Value(DataType.WORD, 4000-123)) + testBinaryOperator(Value(DataType.BYTE, 250), Opcode.SUB_B, Value(DataType.BYTE, 70), Value(DataType.BYTE, 180)) + testBinaryOperator(Value(DataType.WORD, 4000), Opcode.SUB_W, Value(DataType.WORD, 123), Value(DataType.WORD, 4000-123)) + testBinaryOperator(Value(DataType.FLOAT, 123.44), Opcode.SUB_F, Value(DataType.FLOAT, 23.44), Value(DataType.FLOAT, 100.0)) assertFailsWith { - testBinaryOperator(Value(DataType.WORD, 4000 - 40), Opcode.SUB, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40))) + testBinaryOperator(Value(DataType.WORD, 4000 - 40), Opcode.SUB_W, Value(DataType.FLOAT, 42.25), Value(DataType.FLOAT, 42.25 - (4000 - 40))) } } @Test fun testMul() { - testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL, Value(DataType.BYTE, 4), Value(DataType.WORD, 401*4)) - testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL, Value(DataType.WORD, 4), Value(DataType.WORD, 401*4)) + testBinaryOperator(Value(DataType.BYTE, 41), Opcode.MUL_B, Value(DataType.BYTE, 4), Value(DataType.BYTE, 164)) + testBinaryOperator(Value(DataType.WORD, 401), Opcode.MUL_W, Value(DataType.WORD, 4), Value(DataType.WORD, 401*4)) + testBinaryOperator(Value(DataType.FLOAT, 40.1), Opcode.MUL_F, Value(DataType.FLOAT, 2.4), Value(DataType.FLOAT, 96.24)) assertFailsWith { - testBinaryOperator(Value(DataType.WORD, 401 * 4), Opcode.MUL, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4))) + testBinaryOperator(Value(DataType.WORD, 401 * 4), Opcode.MUL_W, Value(DataType.FLOAT, 42.2533), Value(DataType.FLOAT, 42.2533 * (401 * 4))) } } @Test fun testDiv() { - testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.BYTE, 40), Value(DataType.WORD, 99)) - testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV, Value(DataType.WORD, 40), Value(DataType.WORD, 99)) - testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV, Value(DataType.WORD, 99), Value(DataType.FLOAT, 42.25/99)) + testBinaryOperator(Value(DataType.BYTE, 250), Opcode.DIV_B, Value(DataType.BYTE, 12), Value(DataType.BYTE, 20)) + testBinaryOperator(Value(DataType.WORD, 3999), Opcode.DIV_W, Value(DataType.WORD, 40), Value(DataType.WORD, 99)) + testBinaryOperator(Value(DataType.FLOAT, 42.25), Opcode.DIV_F, Value(DataType.FLOAT, 99.0), Value(DataType.FLOAT, 42.25/99.0)) assertFailsWith { - testBinaryOperator(Value(DataType.WORD, 3333), Opcode.DIV, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22)) + testBinaryOperator(Value(DataType.WORD, 3333), Opcode.DIV_W, Value(DataType.FLOAT, 2.22), Value(DataType.FLOAT, 3333 / 2.22)) } } @Test fun testFloorDiv() { - testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.BYTE, 99), Value(DataType.WORD, 40)) - testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV, Value(DataType.WORD, 99), Value(DataType.WORD, 40)) - testBinaryOperator(Value(DataType.FLOAT, 4000.25), Opcode.FLOORDIV, Value(DataType.BYTE, 40), Value(DataType.FLOAT, 100.0)) + testBinaryOperator(Value(DataType.BYTE, 244), Opcode.FLOORDIV_B, Value(DataType.BYTE, 33), Value(DataType.BYTE, 7)) + testBinaryOperator(Value(DataType.WORD, 3999), Opcode.FLOORDIV_W, Value(DataType.WORD, 99), Value(DataType.WORD, 40)) + testBinaryOperator(Value(DataType.FLOAT, 4000.25), Opcode.FLOORDIV_F, Value(DataType.FLOAT, 40.2), Value(DataType.FLOAT, 99.0)) } @Test fun testPow() { - testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.BYTE, 4), Value(DataType.WORD, 81)) - testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW, Value(DataType.WORD, 4), Value(DataType.WORD, 81)) - testBinaryOperator(Value(DataType.FLOAT, 1.1), Opcode.POW, Value(DataType.BYTE, 81), Value(DataType.FLOAT, 2253.2402360440274)) + testBinaryOperator(Value(DataType.BYTE, 3), Opcode.POW_B, Value(DataType.BYTE, 4), Value(DataType.BYTE, 81)) + testBinaryOperator(Value(DataType.WORD, 3), Opcode.POW_W, Value(DataType.WORD, 4), Value(DataType.WORD, 81)) + testBinaryOperator(Value(DataType.FLOAT, 1.1), Opcode.POW_F, Value(DataType.FLOAT, 81.0), Value(DataType.FLOAT, 2253.2402360440274)) } @Test fun testRemainder() { - testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER, Value(DataType.BYTE, 29), Value(DataType.BYTE, 7)) - testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER, Value(DataType.WORD, 29), Value(DataType.BYTE, 7)) - testBinaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.REMAINDER, Value(DataType.BYTE, 7), Value(DataType.FLOAT, 6.5)) + testBinaryOperator(Value(DataType.BYTE, 250), Opcode.REMAINDER_B, Value(DataType.BYTE, 29), Value(DataType.BYTE, 18)) + testBinaryOperator(Value(DataType.WORD, 500), Opcode.REMAINDER_W, Value(DataType.WORD, 29), Value(DataType.WORD, 7)) + testBinaryOperator(Value(DataType.FLOAT, 2022.5), Opcode.REMAINDER_F, Value(DataType.FLOAT, 7.0), Value(DataType.FLOAT, 6.5)) } @Test @@ -387,9 +392,9 @@ class TestStackVmOpcodes { @Test fun testNeg() { - testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG, Value(DataType.BYTE, 244)) - testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG, Value(DataType.WORD, 64302)) - testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG, Value(DataType.FLOAT, -123.456)) + testUnaryOperator(Value(DataType.BYTE, 12), Opcode.NEG_B, Value(DataType.BYTE, 244)) + testUnaryOperator(Value(DataType.WORD, 1234), Opcode.NEG_W, Value(DataType.WORD, 64302)) + testUnaryOperator(Value(DataType.FLOAT, 123.456), Opcode.NEG_F, Value(DataType.FLOAT, -123.456)) } @Test diff --git a/compiler/test/ValueOperationsTests.kt b/compiler/test/ValueOperationsTests.kt index f6996b2cd..af81278b9 100644 --- a/compiler/test/ValueOperationsTests.kt +++ b/compiler/test/ValueOperationsTests.kt @@ -138,106 +138,25 @@ class TestStackVmValue { } @Test - fun testArithmeticByteFirstOperand() { - var r = Value(DataType.BYTE, 100).add(Value(DataType.BYTE, 120)) - assertEquals(DataType.BYTE, r.type) - assertEquals(220, r.integerValue()) - - r = Value(DataType.BYTE, 100).add(Value(DataType.BYTE, 199)) - assertEquals(DataType.WORD, r.type) - assertEquals(299, r.integerValue()) - - r = Value(DataType.BYTE, 100).sub(Value(DataType.BYTE, 88)) - assertEquals(DataType.BYTE, r.type) - assertEquals(12, r.integerValue()) - - r = Value(DataType.BYTE, 100).sub(Value(DataType.BYTE, 188)) - assertEquals(DataType.BYTE, r.type) - assertEquals(168, r.integerValue()) - - r = Value(DataType.BYTE, 5).mul(Value(DataType.BYTE, 33)) - assertEquals(DataType.BYTE, r.type) - assertEquals(165, r.integerValue()) - - r = Value(DataType.BYTE, 22).mul(Value(DataType.BYTE, 33)) - assertEquals(DataType.WORD, r.type) - assertEquals(726, r.integerValue()) - - r = Value(DataType.BYTE, 233).div(Value(DataType.BYTE, 12)) - assertEquals(DataType.BYTE, r.type) - assertEquals(19, r.integerValue()) - - r = Value(DataType.BYTE, 233).div(Value(DataType.BYTE, 0)) - assertEquals(DataType.BYTE, r.type) - assertEquals(255, r.integerValue()) - - r = Value(DataType.BYTE, 233).floordiv(Value(DataType.BYTE, 19)) - assertEquals(DataType.BYTE, r.type) - assertEquals(12, r.integerValue()) - - - r = Value(DataType.BYTE, 100).add(Value(DataType.WORD, 120)) - assertEquals(DataType.WORD, r.type) - assertEquals(220, r.integerValue()) - - r = Value(DataType.BYTE, 100).add(Value(DataType.WORD, 199)) - assertEquals(DataType.WORD, r.type) - assertEquals(299, r.integerValue()) - - r = Value(DataType.BYTE, 100).sub(Value(DataType.WORD, 88)) - assertEquals(DataType.WORD, r.type) - assertEquals(12, r.integerValue()) - - r = Value(DataType.BYTE, 100).sub(Value(DataType.WORD, 188)) - assertEquals(DataType.WORD, r.type) - assertEquals(65448, r.integerValue()) - - r = Value(DataType.BYTE, 5).mul(Value(DataType.WORD, 33)) - assertEquals(DataType.WORD, r.type) - assertEquals(165, r.integerValue()) - - r = Value(DataType.BYTE, 22).mul(Value(DataType.WORD, 33)) - assertEquals(DataType.WORD, r.type) - assertEquals(726, r.integerValue()) - - r = Value(DataType.BYTE, 233).div(Value(DataType.WORD, 12)) - assertEquals(DataType.BYTE, r.type) - assertEquals(19, r.integerValue()) - - r = Value(DataType.BYTE, 233).div(Value(DataType.WORD, 0)) - assertEquals(DataType.BYTE, r.type) - assertEquals(255, r.integerValue()) - - r = Value(DataType.BYTE, 233).floordiv(Value(DataType.WORD, 19)) - assertEquals(DataType.BYTE, r.type) - assertEquals(12, r.integerValue()) - } - - @Test - fun testArithmeticWordFirstOperand() { - var r = Value(DataType.WORD, 100).add(Value(DataType.BYTE, 120)) - assertEquals(DataType.WORD, r.type) - assertEquals(220, r.integerValue()) - - r = Value(DataType.WORD, 100).div(Value(DataType.BYTE, 10)) - assertEquals(DataType.WORD, r.type) - assertEquals(10, r.integerValue()) - - r = Value(DataType.WORD, 100).div(Value(DataType.BYTE, 0)) - assertEquals(DataType.WORD, r.type) - assertEquals(65535, r.integerValue()) - - r = Value(DataType.WORD, 100).div(Value(DataType.WORD, 0)) - assertEquals(DataType.WORD, r.type) - assertEquals(65535, r.integerValue()) - - r = Value(DataType.WORD, 33445).floordiv(Value(DataType.WORD, 123)) - assertEquals(DataType.WORD, r.type) - assertEquals(271, r.integerValue()) - - r = Value(DataType.WORD, 33445).floordiv(Value(DataType.WORD, 999)) - assertEquals(DataType.WORD, r.type) - assertEquals(33, r.integerValue()) + fun testNoDtConversion() { + assertFailsWith { + Value(DataType.WORD, 100).add(Value(DataType.BYTE, 120)) + } + assertFailsWith { + Value(DataType.BYTE, 100).add(Value(DataType.WORD, 120)) + } + assertFailsWith { + Value(DataType.FLOAT, 100.22).add(Value(DataType.WORD, 120)) + } + assertFailsWith { + Value(DataType.WORD, 1002).add(Value(DataType.FLOAT, 120.22)) + } + assertFailsWith { + Value(DataType.FLOAT, 100.22).add(Value(DataType.BYTE, 120)) + } + assertFailsWith { + Value(DataType.BYTE, 12).add(Value(DataType.FLOAT, 120.22)) + } } @Test