mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
vm: add in-place division
This commit is contained in:
parent
5e4eb92443
commit
c9e8c7a290
@ -86,7 +86,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
|||||||
"+" -> return expressionEval.operatorPlusInplace(address, vmDt, operand)
|
"+" -> return expressionEval.operatorPlusInplace(address, vmDt, operand)
|
||||||
"-" -> return expressionEval.operatorMinusInplace(address, vmDt, operand)
|
"-" -> return expressionEval.operatorMinusInplace(address, vmDt, operand)
|
||||||
"*" -> return expressionEval.operatorMultiplyInplace(address, vmDt, operand)
|
"*" -> return expressionEval.operatorMultiplyInplace(address, vmDt, operand)
|
||||||
"/" -> { /* TODO */ }
|
"/" -> return expressionEval.operatorDivideInplace(address, vmDt, signed, operand)
|
||||||
"|" -> { /* TODO */ }
|
"|" -> { /* TODO */ }
|
||||||
"&" -> { /* TODO */ }
|
"&" -> { /* TODO */ }
|
||||||
"^" -> { /* TODO */ }
|
"^" -> { /* TODO */ }
|
||||||
|
@ -487,6 +487,22 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun divideByConstFloatInplace(address: Int, factor: Float): VmCodeChunk {
|
||||||
|
val code = VmCodeChunk()
|
||||||
|
if(factor==1f)
|
||||||
|
return code
|
||||||
|
if(factor==0f) {
|
||||||
|
val maxvalueReg = vmRegisters.nextFreeFloat()
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, value=address)
|
||||||
|
} else {
|
||||||
|
val factorReg = vmRegisters.nextFreeFloat()
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||||
|
code += VmCodeInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, value=address)
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean): VmCodeChunk {
|
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
if(factor==1)
|
if(factor==1)
|
||||||
@ -523,6 +539,52 @@ class CodeGen(internal val program: PtProgram,
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun divideByConstInplace(dt: VmDataType, address: 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
|
||||||
|
// TODO use memory-shift instruction?
|
||||||
|
val reg = vmRegisters.nextFree()
|
||||||
|
code += VmCodeInstruction(Opcode.LOADM, dt, reg1=reg, value=address)
|
||||||
|
code += if(signed)
|
||||||
|
VmCodeInstruction(Opcode.ASR, dt, reg1=reg)
|
||||||
|
else
|
||||||
|
VmCodeInstruction(Opcode.LSR, dt, reg1=reg)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
|
||||||
|
}
|
||||||
|
else if(pow2>=1) {
|
||||||
|
// just shift multiple bits
|
||||||
|
// TODO use 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 += if(signed)
|
||||||
|
VmCodeInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
|
||||||
|
else
|
||||||
|
VmCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
|
||||||
|
} else {
|
||||||
|
if (factor == 0) {
|
||||||
|
val reg = vmRegisters.nextFree()
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
||||||
|
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val factorReg = vmRegisters.nextFree()
|
||||||
|
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
|
||||||
|
code += if(signed)
|
||||||
|
VmCodeInstruction(Opcode.DIVSM, dt, reg1=factorReg, value=address)
|
||||||
|
else
|
||||||
|
VmCodeInstruction(Opcode.DIVM, dt, reg1=factorReg, value=address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
private fun translate(ifElse: PtIfElse): VmCodeChunk {
|
private fun translate(ifElse: PtIfElse): VmCodeChunk {
|
||||||
if(ifElse.condition.operator !in ComparisonOperators)
|
if(ifElse.condition.operator !in ComparisonOperators)
|
||||||
throw AssemblyError("if condition should only be a binary comparison expression")
|
throw AssemblyError("if condition should only be a binary comparison expression")
|
||||||
|
@ -545,6 +545,37 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun operatorDivideInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): VmCodeChunk {
|
||||||
|
val code = VmCodeChunk()
|
||||||
|
val constFactorRight = operand as? PtNumber
|
||||||
|
if(vmDt==VmDataType.FLOAT) {
|
||||||
|
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||||
|
val factor = constFactorRight.number.toFloat()
|
||||||
|
code += codeGen.divideByConstFloatInplace(address, factor)
|
||||||
|
} else {
|
||||||
|
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||||
|
code += translateExpression(operand, -1, operandFpReg)
|
||||||
|
code += if(signed)
|
||||||
|
VmCodeInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, value=address)
|
||||||
|
else
|
||||||
|
VmCodeInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, value=address)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||||
|
val factor = constFactorRight.number.toInt()
|
||||||
|
code += codeGen.divideByConstInplace(vmDt, address, factor, signed)
|
||||||
|
} else {
|
||||||
|
val operandReg = codeGen.vmRegisters.nextFree()
|
||||||
|
code += translateExpression(operand, operandReg, -1)
|
||||||
|
code += if(signed)
|
||||||
|
VmCodeInstruction(Opcode.DIVSM, vmDt, reg1=operandReg, value = address)
|
||||||
|
else
|
||||||
|
VmCodeInstruction(Opcode.DIVM, vmDt, reg1=operandReg, value = address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
|
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
|
||||||
val code = VmCodeChunk()
|
val code = VmCodeChunk()
|
||||||
val constFactorLeft = binExpr.left as? PtNumber
|
val constFactorLeft = binExpr.left as? PtNumber
|
||||||
|
@ -4,7 +4,6 @@ TODO
|
|||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- vm: implement the missing in-place operators in inplaceBinexpr()
|
- vm: implement the missing in-place operators in inplaceBinexpr()
|
||||||
- vm: implement the new in-memory instructions in the VirtualMachine eval loop itself.
|
|
||||||
- complete the Inliner
|
- complete the Inliner
|
||||||
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
||||||
|
|
||||||
|
@ -144,9 +144,9 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
Opcode.MUL -> InsMUL(ins)
|
Opcode.MUL -> InsMUL(ins)
|
||||||
Opcode.MULM -> InsMULM(ins)
|
Opcode.MULM -> InsMULM(ins)
|
||||||
Opcode.DIV -> InsDIV(ins)
|
Opcode.DIV -> InsDIV(ins)
|
||||||
Opcode.DIVM -> TODO()
|
Opcode.DIVM -> InsDIVM(ins)
|
||||||
Opcode.DIVS -> InsDIVS(ins)
|
Opcode.DIVS -> InsDIVS(ins)
|
||||||
Opcode.DIVSM -> TODO()
|
Opcode.DIVSM -> InsDIVSM(ins)
|
||||||
Opcode.MOD -> InsMOD(ins)
|
Opcode.MOD -> InsMOD(ins)
|
||||||
Opcode.SGN -> InsSGN(ins)
|
Opcode.SGN -> InsSGN(ins)
|
||||||
Opcode.CMP -> InsCMP(ins)
|
Opcode.CMP -> InsCMP(ins)
|
||||||
@ -759,6 +759,16 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun InsDIVM(i: Instruction) {
|
||||||
|
val address = i.value!!
|
||||||
|
when(i.type!!) {
|
||||||
|
VmDataType.BYTE -> divModByteUnsignedInplace("/", i.reg1!!, address)
|
||||||
|
VmDataType.WORD -> divModWordUnsignedInplace("/", i.reg1!!, address)
|
||||||
|
VmDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||||
|
}
|
||||||
|
pc++
|
||||||
|
}
|
||||||
|
|
||||||
private fun InsDIVS(i: Instruction) {
|
private fun InsDIVS(i: Instruction) {
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
VmDataType.BYTE -> divModByteSigned("/", i.reg1!!, i.reg2!!)
|
VmDataType.BYTE -> divModByteSigned("/", i.reg1!!, i.reg2!!)
|
||||||
@ -773,6 +783,21 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun InsDIVSM(i: Instruction) {
|
||||||
|
val address = i.value!!
|
||||||
|
when(i.type!!) {
|
||||||
|
VmDataType.BYTE -> divModByteSignedInplace("/", i.reg1!!, address)
|
||||||
|
VmDataType.WORD -> divModWordSignedInplace("/", 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 InsMOD(i: Instruction) {
|
private fun InsMOD(i: Instruction) {
|
||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
VmDataType.BYTE -> divModByteUnsigned("%", i.reg1!!, i.reg2!!)
|
VmDataType.BYTE -> divModByteUnsigned("%", i.reg1!!, i.reg2!!)
|
||||||
@ -880,6 +905,23 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
registers.setSB(reg1, result.toByte())
|
registers.setSB(reg1, result.toByte())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun divModByteSignedInplace(operator: String, reg1: Int, address: Int) {
|
||||||
|
val left = memory.getSB(address)
|
||||||
|
val right = registers.getSB(reg1)
|
||||||
|
val result = when(operator) {
|
||||||
|
"/" -> {
|
||||||
|
if(right==0.toByte()) 127
|
||||||
|
else left / right
|
||||||
|
}
|
||||||
|
"%" -> {
|
||||||
|
if(right==0.toByte()) 127
|
||||||
|
else left % right
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("operator byte $operator")
|
||||||
|
}
|
||||||
|
memory.setSB(address, result.toByte())
|
||||||
|
}
|
||||||
|
|
||||||
private fun divModByteUnsigned(operator: String, reg1: Int, reg2: Int) {
|
private fun divModByteUnsigned(operator: String, reg1: Int, reg2: Int) {
|
||||||
val left = registers.getUB(reg1)
|
val left = registers.getUB(reg1)
|
||||||
val right = registers.getUB(reg2)
|
val right = registers.getUB(reg2)
|
||||||
@ -897,6 +939,23 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
registers.setUB(reg1, result.toUByte())
|
registers.setUB(reg1, result.toUByte())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun divModByteUnsignedInplace(operator: String, reg1: Int, address: Int) {
|
||||||
|
val left = memory.getUB(address)
|
||||||
|
val right = registers.getUB(reg1)
|
||||||
|
val result = when(operator) {
|
||||||
|
"/" -> {
|
||||||
|
if(right==0.toUByte()) 0xffu
|
||||||
|
else left / right
|
||||||
|
}
|
||||||
|
"%" -> {
|
||||||
|
if(right==0.toUByte()) 0xffu
|
||||||
|
else left % right
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("operator byte $operator")
|
||||||
|
}
|
||||||
|
memory.setUB(address, result.toUByte())
|
||||||
|
}
|
||||||
|
|
||||||
private fun plusMinusMultAnyWord(operator: String, reg1: Int, reg2: Int) {
|
private fun plusMinusMultAnyWord(operator: String, reg1: Int, reg2: Int) {
|
||||||
val left = registers.getUW(reg1)
|
val left = registers.getUW(reg1)
|
||||||
val right = registers.getUW(reg2)
|
val right = registers.getUW(reg2)
|
||||||
@ -938,6 +997,23 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
registers.setUW(reg1, result.toUShort())
|
registers.setUW(reg1, result.toUShort())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun divModWordUnsignedInplace(operator: String, reg1: Int, address: Int) {
|
||||||
|
val left = memory.getUW(address)
|
||||||
|
val right = registers.getUW(reg1)
|
||||||
|
val result = when(operator) {
|
||||||
|
"/" -> {
|
||||||
|
if(right==0.toUShort()) 0xffffu
|
||||||
|
else left / right
|
||||||
|
}
|
||||||
|
"%" -> {
|
||||||
|
if(right==0.toUShort()) 0xffffu
|
||||||
|
else left % right
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("operator word $operator")
|
||||||
|
}
|
||||||
|
memory.setUW(address, result.toUShort())
|
||||||
|
}
|
||||||
|
|
||||||
private fun divModWordSigned(operator: String, reg1: Int, reg2: Int) {
|
private fun divModWordSigned(operator: String, reg1: Int, reg2: Int) {
|
||||||
val left = registers.getSW(reg1)
|
val left = registers.getSW(reg1)
|
||||||
val right = registers.getSW(reg2)
|
val right = registers.getSW(reg2)
|
||||||
@ -955,6 +1031,23 @@ class VirtualMachine(val memory: Memory, program: List<Instruction>) {
|
|||||||
registers.setSW(reg1, result.toShort())
|
registers.setSW(reg1, result.toShort())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun divModWordSignedInplace(operator: String, reg1: Int, address: Int) {
|
||||||
|
val left = memory.getSW(address)
|
||||||
|
val right = registers.getSW(reg1)
|
||||||
|
val result = when(operator) {
|
||||||
|
"/" -> {
|
||||||
|
if(right==0.toShort()) 32767
|
||||||
|
else left / right
|
||||||
|
}
|
||||||
|
"%" -> {
|
||||||
|
if(right==0.toShort()) 32767
|
||||||
|
else left % right
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("operator word $operator")
|
||||||
|
}
|
||||||
|
memory.setSW(address, result.toShort())
|
||||||
|
}
|
||||||
|
|
||||||
private fun arithFloat(left: Float, operator: String, right: Float): Float = when(operator) {
|
private fun arithFloat(left: Float, operator: String, right: Float): Float = when(operator) {
|
||||||
"+" -> left + right
|
"+" -> left + right
|
||||||
"-" -> left - right
|
"-" -> left - right
|
||||||
|
Loading…
Reference in New Issue
Block a user