vm: add in-place multiply

This commit is contained in:
Irmen de Jong
2022-05-19 23:15:22 +02:00
parent 461b6499ef
commit 5e4eb92443
5 changed files with 122 additions and 23 deletions
@@ -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 */ }
@@ -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)
@@ -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