vm: fix signed divide

This commit is contained in:
Irmen de Jong
2022-05-19 22:08:22 +02:00
parent 181b98ef9e
commit c769920b6e
6 changed files with 187 additions and 50 deletions
@@ -4,6 +4,7 @@ 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
@@ -26,10 +27,10 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
return if(ident!=null) {
val address = codeGen.allocations.get(ident.targetName)
assignSelfInMemory(address, assignment.value, assignment.position, assignment)
assignSelfInMemory(address, assignment.value, assignment)
} else if(memory != null) {
if(memory.address is PtNumber) {
assignSelfInMemory((memory.address as PtNumber).number.toInt(), assignment.value, assignment.position, assignment)
assignSelfInMemory((memory.address as PtNumber).number.toInt(), assignment.value, assignment)
} else {
fallbackAssign(assignment)
}
@@ -44,7 +45,6 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
private fun assignSelfInMemory(
targetAddress: Int,
value: PtExpression,
position: Position,
origAssign: PtAssignment
): VmCodeChunk {
val vmDt = codeGen.vmType(value.type)
@@ -53,14 +53,14 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
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, targetAddress, origAssign)
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, targetAddress, origAssign)
is PtMemoryByte -> {
return if (!codeGen.options.compTarget.machine.isIOAddress(targetAddress.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.toInt())
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = targetAddress.toInt())
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = 0, value = targetAddress)
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = targetAddress)
code
}
}
@@ -79,6 +79,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
operator: String,
right: PtExpression,
vmDt: VmDataType,
signed: Boolean,
targetAddress: Int,
origAssign: PtAssignment
): VmCodeChunk {
@@ -433,25 +433,31 @@ class CodeGen(internal val program: PtProgram,
} else {
val factorReg = vmRegisters.nextFreeFloat()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
code += VmCodeInstruction(Opcode.DIV, VmDataType.FLOAT, fpReg1 = fpReg, fpReg2 = factorReg)
code += VmCodeInstruction(Opcode.DIVS, VmDataType.FLOAT, fpReg1 = fpReg, fpReg2 = factorReg)
}
return code
}
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk {
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean): VmCodeChunk {
val code = VmCodeChunk()
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
if(pow2==1) {
// just shift 1 bit
code += VmCodeInstruction(Opcode.LSR, dt, reg1=reg)
code += if(signed)
VmCodeInstruction(Opcode.ASR, dt, reg1=reg)
else
VmCodeInstruction(Opcode.LSR, dt, reg1=reg)
}
else if(pow2>=1) {
// just shift multiple bits
val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += VmCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
code += if(signed)
VmCodeInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
else
VmCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
} else {
if (factor == 0) {
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
@@ -459,7 +465,10 @@ class CodeGen(internal val program: PtProgram,
else {
val factorReg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
code += VmCodeInstruction(Opcode.DIV, dt, reg1=reg, reg2=factorReg)
code += if(signed)
VmCodeInstruction(Opcode.DIVS, dt, reg1=reg, reg2=factorReg)
else
VmCodeInstruction(Opcode.DIV, dt, reg1=reg, reg2=factorReg)
}
}
return code
@@ -281,7 +281,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
"+" -> operatorPlus(binExpr, vmDt, resultRegister, resultFpRegister)
"-" -> operatorMinus(binExpr, vmDt, resultRegister, resultFpRegister)
"*" -> operatorMultiply(binExpr, vmDt, resultRegister, resultFpRegister)
"/" -> operatorDivide(binExpr, vmDt, resultRegister, resultFpRegister)
"/" -> operatorDivide(binExpr, vmDt, resultRegister, resultFpRegister, signed)
"%" -> operatorModulo(binExpr, vmDt, resultRegister)
"|", "or" -> operatorOr(binExpr, vmDt, resultRegister)
"&", "and" -> operatorAnd(binExpr, vmDt, resultRegister)
@@ -506,7 +506,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
return code
}
private fun operatorDivide(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
private fun operatorDivide(binExpr: PtBinaryExpression,
vmDt: VmDataType,
resultRegister: Int,
resultFpRegister: Int,
signed: Boolean): VmCodeChunk {
val code = VmCodeChunk()
val constFactorRight = binExpr.right as? PtNumber
if(vmDt==VmDataType.FLOAT) {
@@ -518,18 +522,24 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += translateExpression(binExpr.right, -1, rightResultFpReg)
code += VmCodeInstruction(Opcode.DIV, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
code += if(signed)
VmCodeInstruction(Opcode.DIVS, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
else
VmCodeInstruction(Opcode.DIV, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
}
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
code += translateExpression(binExpr.left, resultRegister, -1)
val factor = constFactorRight.number.toInt()
code += codeGen.divideByConst(vmDt, resultRegister, factor)
code += codeGen.divideByConst(vmDt, resultRegister, factor, signed)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=rightResultReg)
code += if(signed)
VmCodeInstruction(Opcode.DIVS, vmDt, reg1=resultRegister, reg2=rightResultReg)
else
VmCodeInstruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=rightResultReg)
}
}
return code