From 090820958ee235e0431b3df69878127ac147e941 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 10 Apr 2023 15:23:20 +0200 Subject: [PATCH] ir divmod returns its results on valuestack, to keep consistency with the rule that only 1 register can be a returnvalue --- .../codegen/intermediate/BuiltinFuncGen.kt | 14 ++++++++-- docs/source/todo.rst | 2 ++ .../src/prog8/intermediate/IRInstructions.kt | 4 +-- virtualmachine/src/prog8/vm/VirtualMachine.kt | 28 +++++++++++-------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index e7da4225f..4a2b752cf 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -52,20 +52,28 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe val result = mutableListOf() val number = call.args[0] val divident = call.args[1] + val divisionReg: Int + val remainderReg: Int if(divident is PtNumber) { val tr = exprGen.translateExpression(number) addToResult(result, tr, tr.resultReg, -1) addInstr(result, IRInstruction(Opcode.DIVMOD, type, reg1 = tr.resultReg, immediate = divident.number.toInt()), null) + divisionReg = tr.resultReg + remainderReg = codeGen.registers.nextFree() } else { val numTr = exprGen.translateExpression(number) addToResult(result, numTr, numTr.resultReg, -1) val dividentTr = exprGen.translateExpression(divident) addToResult(result, dividentTr, dividentTr.resultReg, -1) addInstr(result, IRInstruction(Opcode.DIVMODR, type, reg1 = numTr.resultReg, reg2=dividentTr.resultReg), null) + divisionReg = numTr.resultReg + remainderReg = dividentTr.resultReg } - // DIVMOD result convention: division in r0, remainder in r1 - result += assignRegisterTo(call.args[2], 0) - result += assignRegisterTo(call.args[3], 1) + // DIVMOD result convention: on value stack, division and remainder on top. + addInstr(result, IRInstruction(Opcode.POP, type, reg1=remainderReg), null) + addInstr(result, IRInstruction(Opcode.POP, type, reg1=divisionReg), null) + result += assignRegisterTo(call.args[2], divisionReg) + result += assignRegisterTo(call.args[3], remainderReg) return ExpressionCodeResult(result, type, -1, -1) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 666de4ae0..46e5ffa46 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,8 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ +change syscalls to output results on value stack +change syscalls to take parameters on value stack (not in r65500+ registers) ... diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index af54538bf..c16c2a66d 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -130,8 +130,8 @@ divs reg1, value - signed division reg1 /= value not divsm reg1, address - signed memory at address /= reg2 note: division by zero yields max signed int 127 / 32767 modr reg1, reg2 - remainder (modulo) of unsigned division reg1 %= reg2 note: division by zero yields max signed int $ff/$ffff mod reg1, value - remainder (modulo) of unsigned division reg1 %= value note: division by zero yields max signed int $ff/$ffff -divmodr reg1, reg2 - unsigned division reg1/reg2, storing division in r0 and remainder in r2 (by convention, because we can't specify enough registers in the instruction) -divmod reg1, value - unsigned division reg1/value, storing division in r0 and remainder in r2 (by convention, because we can't specify enough registers in the instruction) +divmodr reg1, reg2 - unsigned division reg1/reg2, storing division and remainder on value stack (so need to be POPped off) +divmod reg1, value - unsigned division reg1/value, storing division and remainder on value stack (so need to be POPped off) sqrt reg1, reg2 - reg1 is the square root of reg2 sgn reg1, reg2 - reg1 is the sign of reg2 (0, 1 or -1) cmp reg1, reg2 - set processor status bits C, N, Z according to comparison of reg1 with reg2. (semantics taken from 6502/68000 CMP instruction) diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 534b81bf5..84c1f499a 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -1188,8 +1188,8 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsDIVMODR(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> divAndModUByte(i.reg1!!, i.reg2!!) // output in r0+r1 - IRDataType.WORD -> divAndModUWord(i.reg1!!, i.reg2!!) // output in r0+r1 + IRDataType.BYTE -> divAndModUByte(i.reg1!!, i.reg2!!) // division+remainder results on value stack + IRDataType.WORD -> divAndModUWord(i.reg1!!, i.reg2!!) // division+remainder results on value stack IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1197,8 +1197,8 @@ class VirtualMachine(irProgram: IRProgram) { private fun InsDIVMOD(i: IRInstruction) { when(i.type!!) { - IRDataType.BYTE -> divAndModConstUByte(i.reg1!!, i.immediate!!.toUByte()) // output in r0+r1 - IRDataType.WORD -> divAndModConstUWord(i.reg1!!, i.immediate!!.toUShort()) // output in r0+r1 + IRDataType.BYTE -> divAndModConstUByte(i.reg1!!, i.immediate!!.toUByte()) // division+remainder results on value stack + IRDataType.WORD -> divAndModConstUWord(i.reg1!!, i.immediate!!.toUShort()) // division+remainder results on value stack IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i") } nextPc() @@ -1375,16 +1375,16 @@ class VirtualMachine(irProgram: IRProgram) { val right = registers.getUB(reg2) val division = if(right==0.toUByte()) 0xffu else left / right val remainder = if(right==0.toUByte()) 0xffu else left % right - registers.setUB(0, division.toUByte()) - registers.setUB(1, remainder.toUByte()) + valueStack.push(division.toUByte()) + valueStack.push(remainder.toUByte()) } private fun divAndModConstUByte(reg1: Int, value: UByte) { val left = registers.getUB(reg1) val division = if(value==0.toUByte()) 0xffu else left / value val remainder = if(value==0.toUByte()) 0xffu else left % value - registers.setUB(0, division.toUByte()) - registers.setUB(1, remainder.toUByte()) + valueStack.push(division.toUByte()) + valueStack.push(remainder.toUByte()) } private fun divAndModUWord(reg1: Int, reg2: Int) { @@ -1392,16 +1392,20 @@ class VirtualMachine(irProgram: IRProgram) { val right = registers.getUW(reg2) val division = if(right==0.toUShort()) 0xffffu else left / right val remainder = if(right==0.toUShort()) 0xffffu else left % right - registers.setUW(0, division.toUShort()) - registers.setUW(1, remainder.toUShort()) + valueStack.push((division and 255u).toUByte()) + valueStack.push((division.toInt() ushr 8).toUByte()) + valueStack.push((remainder and 255u).toUByte()) + valueStack.push((remainder.toInt() ushr 8).toUByte()) } private fun divAndModConstUWord(reg1: Int, value: UShort) { val left = registers.getUW(reg1) val division = if(value==0.toUShort()) 0xffffu else left / value val remainder = if(value==0.toUShort()) 0xffffu else left % value - registers.setUW(0, division.toUShort()) - registers.setUW(1, remainder.toUShort()) + valueStack.push((division and 255u).toUByte()) + valueStack.push((division.toInt() ushr 8).toUByte()) + valueStack.push((remainder and 255u).toUByte()) + valueStack.push((remainder.toInt() ushr 8).toUByte()) } private fun divModByteUnsignedInplace(operator: String, reg1: Int, address: Int) {