From 5e4eb92443f5082e963f84c719d9479221c38eaa Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 19 May 2022 23:15:22 +0200 Subject: [PATCH] vm: add in-place multiply --- .../prog8/codegen/virtual/AssignmentGen.kt | 23 +++++---- .../src/prog8/codegen/virtual/CodeGen.kt | 49 +++++++++++++++++++ .../prog8/codegen/virtual/ExpressionGen.kt | 45 +++++++++++++---- virtualmachine/src/prog8/vm/Instructions.kt | 11 +++++ virtualmachine/src/prog8/vm/VirtualMachine.kt | 17 ++++++- 5 files changed, 122 insertions(+), 23 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt index e6ac38619..bb52c78bd 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt @@ -3,7 +3,6 @@ package prog8.codegen.virtual import prog8.code.ast.* import prog8.code.core.AssemblyError import prog8.code.core.DataType -import prog8.code.core.Position import prog8.code.core.SignedDatatypes import prog8.vm.Opcode import prog8.vm.VmDataType @@ -43,7 +42,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio } private fun assignSelfInMemory( - targetAddress: Int, + address: Int, value: PtExpression, origAssign: PtAssignment ): VmCodeChunk { @@ -52,15 +51,15 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio when(value) { is PtIdentifier -> return code // do nothing, x=x null assignment. is PtMachineRegister -> return code // do nothing, reg=reg null assignment - is PtPrefix -> return inplacePrefix(value.operator, vmDt, targetAddress) - is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, targetAddress, origAssign) + is PtPrefix -> return inplacePrefix(value.operator, vmDt, address) + is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, origAssign) is PtMemoryByte -> { - return if (!codeGen.options.compTarget.machine.isIOAddress(targetAddress.toUInt())) + return if (!codeGen.options.compTarget.machine.isIOAddress(address.toUInt())) code // do nothing, mem=mem null assignment. else { // read and write a (i/o) memory location to itself. - code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = 0, value = targetAddress) - code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = targetAddress) + code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = 0, value = address) + code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = address) code } } @@ -77,16 +76,16 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio private fun inplaceBinexpr( operator: String, - right: PtExpression, + operand: PtExpression, vmDt: VmDataType, signed: Boolean, - targetAddress: Int, + address: Int, origAssign: PtAssignment ): VmCodeChunk { when(operator) { - "+" -> return expressionEval.operatorPlusInplace(targetAddress, vmDt, right) - "-" -> return expressionEval.operatorMinusInplace(targetAddress, vmDt, right) - "*" -> { /* TODO */ } + "+" -> return expressionEval.operatorPlusInplace(address, vmDt, operand) + "-" -> return expressionEval.operatorMinusInplace(address, vmDt, operand) + "*" -> return expressionEval.operatorMultiplyInplace(address, vmDt, operand) "/" -> { /* TODO */ } "|" -> { /* TODO */ } "&" -> { /* TODO */ } diff --git a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt index 5d03a5457..adc70f896 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt @@ -395,6 +395,20 @@ class CodeGen(internal val program: PtProgram, return code } + internal fun multiplyByConstFloatInplace(address: Int, factor: Float): VmCodeChunk { + val code = VmCodeChunk() + if(factor==1f) + return code + if(factor==0f) { + code += VmCodeInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = address) + } else { + val factorReg = vmRegisters.nextFreeFloat() + code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor) + code += VmCodeInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = address) + } + return code + } + internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() } internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk { @@ -424,6 +438,41 @@ class CodeGen(internal val program: PtProgram, return code } + internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int): VmCodeChunk { + val code = VmCodeChunk() + if(factor==1) + return code + val pow2 = powersOfTwo.indexOf(factor) + if(pow2==1) { + // just shift 1 bit + // TODO use a memory shift instruction? + val reg = vmRegisters.nextFree() + code += VmCodeInstruction(Opcode.LOADM, dt, reg1=reg, value=address) + code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg) + code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address) + } + else if(pow2>=1) { + // just shift multiple bits + // TODO use a memory shift instruction? + val reg = vmRegisters.nextFree() + val pow2reg = vmRegisters.nextFree() + code += VmCodeInstruction(Opcode.LOADM, dt, reg1=reg, value=address) + code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2) + code += VmCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg) + code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address) + } else { + if (factor == 0) { + code += VmCodeInstruction(Opcode.STOREZM, dt, value=address) + } + else { + val factorReg = vmRegisters.nextFree() + code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor) + code += VmCodeInstruction(Opcode.MULM, dt, reg1=factorReg, value = address) + } + } + return code + } + internal fun divideByConstFloat(fpReg: Int, factor: Float): VmCodeChunk { val code = VmCodeChunk() if(factor==1f) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index ca348e5b4..882eeabe4 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -583,6 +583,31 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return code } + internal fun operatorMultiplyInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { + val code = VmCodeChunk() + val constFactorRight = operand as? PtNumber + if(vmDt==VmDataType.FLOAT) { + if(constFactorRight!=null) { + val factor = constFactorRight.number.toFloat() + code += codeGen.multiplyByConstFloatInplace(address, factor) + } else { + val operandFpReg = codeGen.vmRegisters.nextFreeFloat() + code += translateExpression(operand, -1, operandFpReg) + code += VmCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = address) + } + } else { + if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) { + val factor = constFactorRight.number.toInt() + code += codeGen.multiplyByConstInplace(vmDt, address, factor) + } else { + val operandReg = codeGen.vmRegisters.nextFree() + code += translateExpression(operand, operandReg, -1) + code += VmCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = address) + } + } + return code + } + private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk { val code = VmCodeChunk() if(vmDt==VmDataType.FLOAT) { @@ -611,25 +636,25 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return code } - internal fun operatorMinusInplace(targetAddress: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { + internal fun operatorMinusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { val code = VmCodeChunk() if(vmDt==VmDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { - code += VmCodeInstruction(Opcode.DECM, vmDt, value=targetAddress) + code += VmCodeInstruction(Opcode.DECM, vmDt, value=address) } else { val operandFpReg = codeGen.vmRegisters.nextFreeFloat() code += translateExpression(operand, -1, operandFpReg) - code += VmCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=targetAddress) + code += VmCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=address) } } else { if((operand as? PtNumber)?.number==1.0) { - code += VmCodeInstruction(Opcode.DECM, vmDt, value=targetAddress) + code += VmCodeInstruction(Opcode.DECM, vmDt, value=address) } else { val operandReg = codeGen.vmRegisters.nextFree() code += translateExpression(operand, operandReg, -1) - code += VmCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = targetAddress) + code += VmCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = address) } } return code @@ -671,25 +696,25 @@ internal class ExpressionGen(private val codeGen: CodeGen) { return code } - internal fun operatorPlusInplace(targetAddress: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { + internal fun operatorPlusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk { val code = VmCodeChunk() if(vmDt==VmDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { - code += VmCodeInstruction(Opcode.INCM, vmDt, value = targetAddress) + code += VmCodeInstruction(Opcode.INCM, vmDt, value = address) } else { val operandFpReg = codeGen.vmRegisters.nextFreeFloat() code += translateExpression(operand, -1, operandFpReg) - code += VmCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value=targetAddress) + code += VmCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value=address) } } else { if((operand as? PtNumber)?.number==1.0) { - code += VmCodeInstruction(Opcode.INCM, vmDt, value = targetAddress) + code += VmCodeInstruction(Opcode.INCM, vmDt, value = address) } else { val operandReg = codeGen.vmRegisters.nextFree() code += translateExpression(operand, operandReg, -1) - code += VmCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=targetAddress) + code += VmCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=address) } } return code diff --git a/virtualmachine/src/prog8/vm/Instructions.kt b/virtualmachine/src/prog8/vm/Instructions.kt index b499d950e..7846e8a3f 100644 --- a/virtualmachine/src/prog8/vm/Instructions.kt +++ b/virtualmachine/src/prog8/vm/Instructions.kt @@ -98,9 +98,13 @@ negm address - sign negate memory at address add reg1, reg2 - reg1 += reg2 (unsigned + signed) addm reg1, address - memory at address += reg1 (unsigned + signed) sub reg1, reg2 - reg1 -= reg2 (unsigned + signed) +subm reg1, address - memory at address -= reg2 (unsigned + signed) mul reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word! +mulm reg1, address - memory at address *= reg2 note: byte*byte->byte, no type extension to word! div reg1, reg2 - unsigned division reg1 /= reg2 note: division by zero yields max int $ff/$ffff +divm reg1, address - memory at address /= reg2 note: division by zero yields max int $ff/$ffff divs reg1, reg2 - signed division reg1 /= reg2 note: division by zero yields max signed int 127 / 32767 +divsm reg1, address - signed memory at address /= reg2 note: division by zero yields max signed int 127 / 32767 mod reg1, reg2 - remainder (modulo) of unsigned division reg1 %= reg2 note: division by zero yields max signed int $ff/$ffff sqrt reg1, reg2 - reg1 is the square root of reg2 sgn reg1, reg2 - reg1 is the sign of reg2 (0, 1 or -1) @@ -131,6 +135,8 @@ roxr reg1 - rotate reg1 right by 1 bits, usin rol reg1 - rotate reg1 left by 1 bits, not using carry + set Carry to shifted bit roxl reg1 - rotate reg1 left by 1 bits, using carry, + set Carry to shifted bit +TODO: add memory-shift instructions? + FLOATING POINT CONVERSIONS AND FUNCTIONS ---------------------------------------- @@ -291,6 +297,11 @@ val OpcodesWithAddress = setOf( Opcode.INCM, Opcode.DECM, Opcode.NEGM, + Opcode.ADDM, + Opcode.SUBM, + Opcode.MULM, + Opcode.DIVM, + Opcode.DIVSM, Opcode.NOTM, Opcode.XORM ) diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 123c701b3..309535b26 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -142,7 +142,7 @@ class VirtualMachine(val memory: Memory, program: List) { Opcode.SUB -> InsSUB(ins) Opcode.SUBM -> InsSUBM(ins) Opcode.MUL -> InsMUL(ins) - Opcode.MULM -> TODO() + Opcode.MULM -> InsMULM(ins) Opcode.DIV -> InsDIV(ins) Opcode.DIVM -> TODO() Opcode.DIVS -> InsDIVS(ins) @@ -735,6 +735,21 @@ class VirtualMachine(val memory: Memory, program: List) { pc++ } + private fun InsMULM(i: Instruction) { + val address = i.value!! + when(i.type!!) { + VmDataType.BYTE -> plusMinusMultAnyByteInplace("*", i.reg1!!, address) + VmDataType.WORD -> plusMinusMultAnyWordInplace("*", i.reg1!!, address) + VmDataType.FLOAT -> { + val left = memory.getFloat(address) + val right = registers.getFloat(i.fpReg1!!) + val result = arithFloat(left, "*", right) + memory.setFloat(address, result) + } + } + pc++ + } + private fun InsDIV(i: Instruction) { when(i.type!!) { VmDataType.BYTE -> divModByteUnsigned("/", i.reg1!!, i.reg2!!)