mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +00:00
ir: adding last missing features to be able to encode all of Prog8
This commit is contained in:
parent
0d4dd385b8
commit
5a8f97a0b6
@ -8,7 +8,7 @@ import prog8.code.core.SignedDatatypes
|
||||
import prog8.intermediate.IRCodeChunk
|
||||
import prog8.intermediate.IRInstruction
|
||||
import prog8.intermediate.Opcode
|
||||
import prog8.intermediate.VmDataType
|
||||
import prog8.intermediate.IRDataType
|
||||
|
||||
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
|
||||
|
||||
@ -49,7 +49,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(value.type)
|
||||
val vmDt = codeGen.irType(value.type)
|
||||
val code = IRCodeChunk(origAssign.position)
|
||||
when(value) {
|
||||
is PtIdentifier -> return code // do nothing, x=x null assignment.
|
||||
@ -61,7 +61,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
code // do nothing, mem=mem null assignment.
|
||||
else {
|
||||
// read and write a (i/o) memory location to itself.
|
||||
val tempReg = codeGen.vmRegisters.nextFree()
|
||||
val tempReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
|
||||
code
|
||||
@ -76,7 +76,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(value.type)
|
||||
val vmDt = codeGen.irType(value.type)
|
||||
val code = IRCodeChunk(origAssign.position)
|
||||
when(value) {
|
||||
is PtIdentifier -> return code // do nothing, x=x null assignment.
|
||||
@ -84,7 +84,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, null, symbol, value.position)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
val tempReg = codeGen.vmRegisters.nextFree()
|
||||
val tempReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
return code
|
||||
@ -102,7 +102,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
private fun inplaceBinexpr(
|
||||
operator: String,
|
||||
operand: PtExpression,
|
||||
vmDt: VmDataType,
|
||||
vmDt: IRDataType,
|
||||
signed: Boolean,
|
||||
knownAddress: Int?,
|
||||
symbol: String?,
|
||||
@ -139,7 +139,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
return fallbackAssign(origAssign)
|
||||
}
|
||||
|
||||
private fun inplacePrefix(operator: String, vmDt: VmDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunk {
|
||||
private fun inplacePrefix(operator: String, vmDt: IRDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunk {
|
||||
val code= IRCodeChunk(position)
|
||||
when(operator) {
|
||||
"+" -> { }
|
||||
@ -150,8 +150,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
IRInstruction(Opcode.NEGM, vmDt, labelSymbol = addressSymbol)
|
||||
}
|
||||
"~" -> {
|
||||
val regMask = codeGen.vmRegisters.nextFree()
|
||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||
val regMask = codeGen.registers.nextFree()
|
||||
val mask = if(vmDt==IRDataType.BYTE) 0x00ff else 0xffff
|
||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=regMask, value = knownAddress)
|
||||
@ -168,7 +168,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
val vmDt = codeGen.vmType(assignment.value.type)
|
||||
val vmDt = codeGen.irType(assignment.value.type)
|
||||
|
||||
val code = IRCodeChunk(assignment.position)
|
||||
var resultRegister = -1
|
||||
@ -176,14 +176,14 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val zero = codeGen.isZero(assignment.value)
|
||||
if(!zero) {
|
||||
// calculate the assignment value
|
||||
if (vmDt == VmDataType.FLOAT) {
|
||||
resultFpRegister = codeGen.vmRegisters.nextFreeFloat()
|
||||
if (vmDt == IRDataType.FLOAT) {
|
||||
resultFpRegister = codeGen.registers.nextFreeFloat()
|
||||
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
||||
} else {
|
||||
resultRegister = if (assignment.value is PtMachineRegister) {
|
||||
(assignment.value as PtMachineRegister).register
|
||||
} else {
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, reg, -1)
|
||||
reg
|
||||
}
|
||||
@ -194,7 +194,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
code += if(zero) {
|
||||
IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
if (vmDt == VmDataType.FLOAT)
|
||||
if (vmDt == IRDataType.FLOAT)
|
||||
IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
||||
else
|
||||
IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
@ -210,11 +210,11 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
||||
if(array.index.type!=DataType.UBYTE)
|
||||
throw AssemblyError("non-array var indexing requires bytes index")
|
||||
val idxReg = codeGen.vmRegisters.nextFree()
|
||||
val idxReg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, idxReg, -1)
|
||||
if(zero) {
|
||||
// there's no STOREZIX instruction
|
||||
resultRegister = codeGen.vmRegisters.nextFree()
|
||||
resultRegister = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
|
||||
}
|
||||
code += IRInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = variable)
|
||||
@ -227,17 +227,17 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
val indexReg = codeGen.registers.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable)
|
||||
}
|
||||
} else {
|
||||
if(vmDt== VmDataType.FLOAT) {
|
||||
if(vmDt== IRDataType.FLOAT) {
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
val indexReg = codeGen.registers.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
}
|
||||
@ -246,7 +246,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
val indexReg = codeGen.registers.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
}
|
||||
@ -254,12 +254,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
}
|
||||
}
|
||||
else if(memory!=null) {
|
||||
require(vmDt== VmDataType.BYTE)
|
||||
require(vmDt== IRDataType.BYTE)
|
||||
if(zero) {
|
||||
if(memory.address is PtNumber) {
|
||||
code += IRInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
||||
}
|
||||
@ -267,7 +267,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
if(memory.address is PtNumber) {
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
}
|
||||
|
@ -51,11 +51,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
|
||||
private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val leftRegister = codeGen.vmRegisters.nextFree()
|
||||
val rightRegister = codeGen.vmRegisters.nextFree()
|
||||
val leftRegister = codeGen.registers.nextFree()
|
||||
val rightRegister = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
|
||||
code += exprGen.translateExpression(call.args[1], rightRegister, -1)
|
||||
code += IRInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
code += IRInstruction(Opcode.CMP, codeGen.irType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -73,10 +73,10 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if (resultRegister != 0)
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -94,10 +94,10 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -108,25 +108,25 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
when (sourceDt) {
|
||||
DataType.UBYTE -> {
|
||||
code += IRInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
|
||||
code += IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
val compareReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=compareReg, value=0x80)
|
||||
code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
|
||||
code += IRInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
||||
val compareReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, IRDataType.WORD, reg1=compareReg, value=0x8000)
|
||||
code += IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, IRDataType.WORD, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
@ -137,49 +137,49 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
|
||||
code += IRInstruction(Opcode.SGN, codeGen.irType(call.type), reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||
code += IRInstruction(Opcode.SQRT, IRDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
|
||||
code += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
|
||||
code += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -195,7 +195,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
return code
|
||||
}
|
||||
@ -215,17 +215,17 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val msbReg = codeGen.vmRegisters.nextFree()
|
||||
val msbReg = codeGen.registers.nextFree()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], msbReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
|
||||
code += IRInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||
code += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -234,23 +234,23 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
|
||||
code += IRInstruction(Opcode.STOREZM, IRDataType.WORD, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg2 = addressReg)
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
val valueReg = codeGen.registers.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1 = valueReg, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREI, IRDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
@ -261,23 +261,23 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
|
||||
code += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg2 = addressReg)
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
val valueReg = codeGen.registers.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueReg, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREI, IRDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
@ -287,11 +287,11 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
|
||||
code += IRInstruction(Opcode.LOADM, IRDataType.WORD, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += IRInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
@ -300,31 +300,31 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
code += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += IRInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
code += IRInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.RND, IRDataType.BYTE, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
code += IRInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.RND, IRDataType.WORD, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val name = (call.args[0] as PtString).value
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = "prog8_slabs.prog8_memoryslab_$name")
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultRegister, labelSymbol = "prog8_slabs.prog8_memoryslab_$name")
|
||||
return code
|
||||
}
|
||||
|
||||
@ -338,13 +338,13 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
code += IRInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(call.args[0].type)
|
||||
val vmDt = codeGen.irType(call.args[0].type)
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
code += IRInstruction(opcode, vmDt, reg1=resultRegister)
|
||||
|
@ -10,29 +10,29 @@ import prog8.intermediate.*
|
||||
|
||||
internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
require(codeGen.vmRegisters.peekNext() > resultRegister)
|
||||
require(codeGen.registers.peekNext() > resultRegister)
|
||||
|
||||
val code = IRCodeChunk(expr.position)
|
||||
|
||||
when (expr) {
|
||||
is PtMachineRegister -> {
|
||||
if(resultRegister!=expr.register) {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
val vmDt = codeGen.irType(expr.type)
|
||||
code += IRInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
|
||||
}
|
||||
}
|
||||
is PtNumber -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
code += if(vmDt==VmDataType.FLOAT)
|
||||
val vmDt = codeGen.irType(expr.type)
|
||||
code += if(vmDt==IRDataType.FLOAT)
|
||||
IRInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, fpValue = expr.number.toFloat())
|
||||
else
|
||||
IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
val vmDt = codeGen.irType(expr.type)
|
||||
val symbol = expr.targetName.joinToString(".")
|
||||
code += if (expr.type in PassByValueDatatypes) {
|
||||
if(vmDt==VmDataType.FLOAT)
|
||||
if(vmDt==IRDataType.FLOAT)
|
||||
IRInstruction(Opcode.LOADM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
||||
else
|
||||
IRInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
@ -42,7 +42,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
val vmDt = codeGen.irType(expr.type)
|
||||
val symbol = expr.identifier.targetName.joinToString(".")
|
||||
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
|
||||
@ -50,11 +50,11 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
is PtMemoryByte -> {
|
||||
if(expr.address is PtNumber) {
|
||||
val address = (expr.address as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
|
||||
code += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, value = address)
|
||||
} else {
|
||||
val addressRegister = codeGen.vmRegisters.nextFree()
|
||||
val addressRegister = codeGen.registers.nextFree()
|
||||
code += translateExpression(expr.address, addressRegister, -1)
|
||||
code += IRInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
|
||||
code += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
|
||||
}
|
||||
}
|
||||
is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister)
|
||||
@ -105,9 +105,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type)
|
||||
val vmDt = codeGen.vmType(arrayIx.type)
|
||||
val vmDt = codeGen.irType(arrayIx.type)
|
||||
val code = IRCodeChunk(arrayIx.position)
|
||||
val idxReg = codeGen.vmRegisters.nextFree()
|
||||
val idxReg = codeGen.registers.nextFree()
|
||||
val arrayVarSymbol = arrayIx.variable.targetName.joinToString(".")
|
||||
|
||||
if(arrayIx.variable.type==DataType.UWORD) {
|
||||
@ -123,16 +123,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
if(arrayIx.index is PtNumber) {
|
||||
val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString()
|
||||
if(vmDt==VmDataType.FLOAT)
|
||||
code += IRInstruction(Opcode.LOADM, VmDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
||||
if(vmDt==IRDataType.FLOAT)
|
||||
code += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
||||
else
|
||||
code += IRInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
||||
} else {
|
||||
code += translateExpression(arrayIx.index, idxReg, -1)
|
||||
if(eltSize>1)
|
||||
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize, arrayIx.position)
|
||||
if(vmDt==VmDataType.FLOAT)
|
||||
code += IRInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, labelSymbol = arrayVarSymbol)
|
||||
code += codeGen.multiplyByConst(IRDataType.BYTE, idxReg, eltSize, arrayIx.position)
|
||||
if(vmDt==IRDataType.FLOAT)
|
||||
code += IRInstruction(Opcode.LOADX, IRDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, labelSymbol = arrayVarSymbol)
|
||||
else
|
||||
code += IRInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol)
|
||||
}
|
||||
@ -142,14 +142,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
private fun translate(expr: PtPrefix, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(expr.position)
|
||||
code += translateExpression(expr.value, resultRegister, -1)
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
val vmDt = codeGen.irType(expr.type)
|
||||
when(expr.operator) {
|
||||
"+" -> { }
|
||||
"-" -> {
|
||||
code += IRInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
|
||||
}
|
||||
"~" -> {
|
||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||
val mask = if(vmDt==IRDataType.BYTE) 0x00ff else 0xffff
|
||||
code += IRInstruction(Opcode.XOR, vmDt, reg1=resultRegister, value=mask)
|
||||
}
|
||||
else -> throw AssemblyError("weird prefix operator")
|
||||
@ -161,8 +161,8 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val code = IRCodeChunk(cast.position)
|
||||
if(cast.type==cast.value.type)
|
||||
return code
|
||||
val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.vmRegisters.nextFreeFloat()
|
||||
val actualResultReg = if(predefinedResultRegister>=0) predefinedResultRegister else codeGen.vmRegisters.nextFree()
|
||||
val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.registers.nextFreeFloat()
|
||||
val actualResultReg = if(predefinedResultRegister>=0) predefinedResultRegister else codeGen.registers.nextFree()
|
||||
if(cast.value.type==DataType.FLOAT) {
|
||||
// a cast from float to integer, so evaluate the value into a float register first
|
||||
code += translateExpression(cast.value, -1, actualResultFpReg)
|
||||
@ -173,14 +173,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
DataType.UBYTE -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
||||
DataType.FLOAT -> code += IRInstruction(Opcode.FTOUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
DataType.FLOAT -> code += IRInstruction(Opcode.FTOUB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
when(cast.value.type) {
|
||||
DataType.UBYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
||||
DataType.FLOAT -> code += IRInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
DataType.FLOAT -> code += IRInstruction(Opcode.FTOSB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
@ -188,15 +188,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
// byte -> uword: sign extend
|
||||
code += IRInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
code += IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// ubyte -> uword: sign extend
|
||||
code += IRInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
code += IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.WORD -> { }
|
||||
DataType.FLOAT -> {
|
||||
code += IRInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
code += IRInstruction(Opcode.FTOUW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
@ -205,15 +205,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
// byte -> word: sign extend
|
||||
code += IRInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
code += IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// byte -> word: sign extend
|
||||
code += IRInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
code += IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.UWORD -> { }
|
||||
DataType.FLOAT -> {
|
||||
code += IRInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
code += IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
@ -221,16 +221,16 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
DataType.FLOAT -> {
|
||||
code += when(cast.value.type) {
|
||||
DataType.UBYTE -> {
|
||||
IRInstruction(Opcode.FFROMUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
IRInstruction(Opcode.FFROMSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
IRInstruction(Opcode.FFROMSB, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
IRInstruction(Opcode.FFROMUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
IRInstruction(Opcode.FFROMUW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
IRInstruction(Opcode.FFROMSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
IRInstruction(Opcode.FFROMSW, IRDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
@ -241,7 +241,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
|
||||
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(binExpr.left.type)
|
||||
val vmDt = codeGen.irType(binExpr.left.type)
|
||||
val signed = binExpr.left.type in SignedDatatypes
|
||||
return when(binExpr.operator) {
|
||||
"+" -> operatorPlus(binExpr, vmDt, resultRegister, resultFpRegister)
|
||||
@ -266,40 +266,40 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
private fun operatorGreaterThan(
|
||||
binExpr: PtBinaryExpression,
|
||||
vmDt: VmDataType,
|
||||
vmDt: IRDataType,
|
||||
resultRegister: Int,
|
||||
signed: Boolean,
|
||||
greaterEquals: Boolean
|
||||
): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.registers.nextFreeFloat()
|
||||
val rightFpReg = codeGen.registers.nextFreeFloat()
|
||||
val zeroRegister = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
val ins = if (signed) {
|
||||
if (greaterEquals) Opcode.SGES else Opcode.SGTS
|
||||
} else {
|
||||
if (greaterEquals) Opcode.SGE else Opcode.SGT
|
||||
}
|
||||
code += IRInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||
code += IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
||||
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
||||
comparisonCall.children.add(binExpr.left)
|
||||
comparisonCall.children.add(binExpr.right)
|
||||
code += translate(comparisonCall, resultRegister, -1)
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
val zeroRegister = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
code += if(greaterEquals)
|
||||
IRInstruction(Opcode.SGES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
IRInstruction(Opcode.SGES, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
else
|
||||
IRInstruction(Opcode.SGTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
IRInstruction(Opcode.SGTS, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val ins = if (signed) {
|
||||
@ -315,40 +315,40 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
private fun operatorLessThan(
|
||||
binExpr: PtBinaryExpression,
|
||||
vmDt: VmDataType,
|
||||
vmDt: IRDataType,
|
||||
resultRegister: Int,
|
||||
signed: Boolean,
|
||||
lessEquals: Boolean
|
||||
): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.registers.nextFreeFloat()
|
||||
val rightFpReg = codeGen.registers.nextFreeFloat()
|
||||
val zeroRegister = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
val ins = if (signed) {
|
||||
if (lessEquals) Opcode.SLES else Opcode.SLTS
|
||||
} else {
|
||||
if (lessEquals) Opcode.SLE else Opcode.SLT
|
||||
}
|
||||
code += IRInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||
code += IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
||||
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
||||
comparisonCall.children.add(binExpr.left)
|
||||
comparisonCall.children.add(binExpr.right)
|
||||
code += translate(comparisonCall, resultRegister, -1)
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
val zeroRegister = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
code += if(lessEquals)
|
||||
IRInstruction(Opcode.SLES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
IRInstruction(Opcode.SLES, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
else
|
||||
IRInstruction(Opcode.SLTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
IRInstruction(Opcode.SLTS, IRDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val ins = if (signed) {
|
||||
@ -362,22 +362,22 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, notEquals: Boolean): IRCodeChunk {
|
||||
private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, notEquals: Boolean): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.registers.nextFreeFloat()
|
||||
val rightFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||
if (notEquals) {
|
||||
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
} else {
|
||||
val label = codeGen.createLabelName()
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
|
||||
code += IRInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
|
||||
val valueReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=1)
|
||||
code += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=valueReg, labelSymbol = label)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=0)
|
||||
code += IRCodeLabel(label)
|
||||
}
|
||||
} else {
|
||||
@ -390,7 +390,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
code += IRInstruction(Opcode.INV, vmDt, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val opcode = if (notEquals) Opcode.SNE else Opcode.SEQ
|
||||
@ -400,14 +400,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): IRCodeChunk {
|
||||
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, signed: Boolean): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(codeGen.isOne(binExpr.right)) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
val opc = if (signed) Opcode.ASR else Opcode.LSR
|
||||
code += IRInstruction(opc, vmDt, reg1 = resultRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val opc = if (signed) Opcode.ASRN else Opcode.LSRN
|
||||
@ -416,7 +416,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(codeGen.isOne(operand)) {
|
||||
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
|
||||
@ -425,7 +425,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
else
|
||||
IRInstruction(opc, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
||||
code += if(knownAddress!=null)
|
||||
@ -436,13 +436,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(codeGen.isOne(binExpr.right)){
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRInstruction(Opcode.LSL, vmDt, reg1=resultRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg)
|
||||
@ -450,7 +450,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(codeGen.isOne(operand)){
|
||||
code += if(knownAddress!=null)
|
||||
@ -458,7 +458,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
else
|
||||
IRInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, value=knownAddress)
|
||||
@ -468,13 +468,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorXor(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
private fun operatorXor(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
@ -482,9 +482,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
@ -493,13 +493,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
@ -507,9 +507,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=knownAddress)
|
||||
@ -518,13 +518,13 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorOr(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
private fun operatorOr(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
@ -532,9 +532,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
@ -543,10 +543,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
require(vmDt!=VmDataType.FLOAT) {"floating-point modulo not supported"}
|
||||
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int): IRCodeChunk {
|
||||
require(vmDt!=IRDataType.FLOAT) {"floating-point modulo not supported"}
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
@ -559,19 +559,19 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
}
|
||||
|
||||
private fun operatorDivide(binExpr: PtBinaryExpression,
|
||||
vmDt: VmDataType,
|
||||
vmDt: IRDataType,
|
||||
resultRegister: Int,
|
||||
resultFpRegister: Int,
|
||||
signed: Boolean): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
val constFactorRight = binExpr.right as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.divideByConstFloat(resultFpRegister, factor, binExpr.position)
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightResultFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += if(signed)
|
||||
@ -585,7 +585,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.divideByConst(vmDt, resultRegister, factor, signed, binExpr.position)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += if (signed)
|
||||
@ -605,15 +605,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor, operand.position)
|
||||
} else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val operandFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(signed) {
|
||||
if(knownAddress!=null)
|
||||
@ -633,7 +633,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.divideByConstInplace(vmDt, knownAddress, symbol, factor, signed, operand.position)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(signed) {
|
||||
if(knownAddress!=null)
|
||||
@ -652,11 +652,11 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
val constFactorLeft = binExpr.left as? PtNumber
|
||||
val constFactorRight = binExpr.right as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorLeft!=null) {
|
||||
code += translateExpression(binExpr.right, -1, resultFpRegister)
|
||||
val factor = constFactorLeft.number.toFloat()
|
||||
@ -666,7 +666,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorRight.position)
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightResultFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += IRInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||
@ -681,7 +681,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorRight.position)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
@ -690,15 +690,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if(constFactorRight!=null) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor, constFactorRight.position)
|
||||
} else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val operandFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
||||
@ -710,7 +710,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.multiplyByConstInplace(vmDt, knownAddress, symbol, factor, constFactorRight.position)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
@ -721,9 +721,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += IRInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister)
|
||||
@ -733,7 +733,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += IRInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightResultFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += IRInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||
@ -749,7 +749,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
@ -759,9 +759,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||
@ -769,7 +769,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val operandFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=knownAddress)
|
||||
@ -784,7 +784,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
IRInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
@ -795,9 +795,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: IRDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((binExpr.left as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.right, -1, resultFpRegister)
|
||||
code += IRInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
|
||||
@ -811,7 +811,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += IRInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightResultFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += IRInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||
@ -831,7 +831,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
val rightResultReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
@ -841,9 +841,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(vmDt==IRDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.INCM, vmDt, value = knownAddress)
|
||||
@ -851,7 +851,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val operandFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value = knownAddress)
|
||||
@ -866,7 +866,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
IRInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
val operandReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=knownAddress)
|
||||
@ -882,17 +882,17 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
is StSub -> {
|
||||
val code = IRCodeChunk(fcall.position)
|
||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||
val paramDt = codeGen.vmType(parameter.type)
|
||||
val paramDt = codeGen.irType(parameter.type)
|
||||
val symbol = (fcall.functionName + parameter.name).joinToString(".")
|
||||
if(codeGen.isZero(arg)) {
|
||||
code += IRInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol)
|
||||
} else {
|
||||
if (paramDt == VmDataType.FLOAT) {
|
||||
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
if (paramDt == IRDataType.FLOAT) {
|
||||
val argFpReg = codeGen.registers.nextFreeFloat()
|
||||
code += translateExpression(arg, -1, argFpReg)
|
||||
code += IRInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, labelSymbol = symbol)
|
||||
} else {
|
||||
val argReg = codeGen.vmRegisters.nextFree()
|
||||
val argReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(arg, argReg, -1)
|
||||
code += IRInstruction(Opcode.STOREM, paramDt, reg1 = argReg, labelSymbol = symbol)
|
||||
}
|
||||
@ -902,12 +902,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
if(fcall.type==DataType.FLOAT) {
|
||||
if (!fcall.void && resultFpRegister != 0) {
|
||||
// Call convention: result value is in fr0, so put it in the required register instead.
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0)
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0)
|
||||
}
|
||||
} else {
|
||||
if (!fcall.void && resultRegister != 0) {
|
||||
// Call convention: result value is in r0, so put it in the required register instead.
|
||||
code += IRInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1 = resultRegister, reg2 = 0)
|
||||
code += IRInstruction(Opcode.LOADR, codeGen.irType(fcall.type), reg1 = resultRegister, reg2 = 0)
|
||||
}
|
||||
}
|
||||
return code
|
||||
@ -915,14 +915,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
is StRomSub -> {
|
||||
val code = IRCodeChunk(fcall.position)
|
||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||
val paramDt = codeGen.vmType(parameter.type)
|
||||
val paramDt = codeGen.irType(parameter.type)
|
||||
val paramRegStr = if(parameter.register.registerOrPair!=null) parameter.register.registerOrPair.toString() else parameter.register.statusflag.toString()
|
||||
if(codeGen.isZero(arg)) {
|
||||
code += IRInstruction(Opcode.STOREZCPU, paramDt, labelSymbol = paramRegStr)
|
||||
} else {
|
||||
if (paramDt == VmDataType.FLOAT)
|
||||
if (paramDt == IRDataType.FLOAT)
|
||||
throw AssemblyError("doesn't support float register argument in asm romsub")
|
||||
val argReg = codeGen.vmRegisters.nextFree()
|
||||
val argReg = codeGen.registers.nextFree()
|
||||
code += translateExpression(arg, argReg, -1)
|
||||
code += IRInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr)
|
||||
}
|
||||
@ -935,7 +935,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
throw AssemblyError("doesn't support float register result in asm romsub")
|
||||
val returns = callTarget.returns.single()
|
||||
val regStr = if(returns.registerOrPair!=null) returns.registerOrPair.toString() else returns.statusflag.toString()
|
||||
code += IRInstruction(Opcode.LOADCPU, codeGen.vmType(fcall.type), reg1=resultRegister, labelSymbol = regStr)
|
||||
code += IRInstruction(Opcode.LOADCPU, codeGen.irType(fcall.type), reg1=resultRegister, labelSymbol = regStr)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class IRCodeGen(
|
||||
private val expressionEval = ExpressionGen(this)
|
||||
private val builtinFuncGen = BuiltinFuncGen(this, expressionEval)
|
||||
private val assignmentGen = AssignmentGen(this, expressionEval)
|
||||
internal val vmRegisters = RegisterPool()
|
||||
internal val registers = RegisterPool()
|
||||
|
||||
fun generate(): IRProgram {
|
||||
flattenLabelNames()
|
||||
@ -28,6 +28,9 @@ class IRCodeGen(
|
||||
|
||||
val irProg = IRProgram(program.name, IRSymbolTable(symbolTable), options, program.encoding)
|
||||
|
||||
if(options.evalStackBaseAddress!=null)
|
||||
throw AssemblyError("IR doesn't use eval-stack")
|
||||
|
||||
if(!options.dontReinitGlobals) {
|
||||
// collect global variables initializers
|
||||
program.allBlocks().forEach {
|
||||
@ -37,14 +40,10 @@ class IRCodeGen(
|
||||
}
|
||||
}
|
||||
|
||||
if(options.symbolDefs.isNotEmpty())
|
||||
throw AssemblyError("virtual target doesn't support symbols defined on the commandline")
|
||||
if(options.evalStackBaseAddress!=null)
|
||||
throw AssemblyError("virtual target doesn't use eval-stack")
|
||||
irProg.addAsmSymbols(options.symbolDefs)
|
||||
|
||||
for (block in program.allBlocks()) {
|
||||
for (block in program.allBlocks())
|
||||
irProg.addBlock(translate(block))
|
||||
}
|
||||
|
||||
replaceMemoryMappedVars(irProg)
|
||||
|
||||
@ -280,8 +279,8 @@ class IRCodeGen(
|
||||
BranchCondition.NE, BranchCondition.NZ -> IRInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
||||
BranchCondition.MI, BranchCondition.NEG -> IRInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
||||
BranchCondition.PL, BranchCondition.POS -> IRInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
||||
BranchCondition.VC,
|
||||
BranchCondition.VS -> throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu V flag ${branch.position}")
|
||||
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, labelSymbol = elseLabel)
|
||||
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel)
|
||||
}
|
||||
code += translateNode(branch.trueScope)
|
||||
if(branch.falseScope.children.isNotEmpty()) {
|
||||
@ -300,9 +299,9 @@ class IRCodeGen(
|
||||
val code = IRCodeChunk(whenStmt.position)
|
||||
if(whenStmt.choices.children.isEmpty())
|
||||
return code
|
||||
val valueReg = vmRegisters.nextFree()
|
||||
val choiceReg = vmRegisters.nextFree()
|
||||
val valueDt = vmType(whenStmt.value.type)
|
||||
val valueReg = registers.nextFree()
|
||||
val choiceReg = registers.nextFree()
|
||||
val valueDt = irType(whenStmt.value.type)
|
||||
code += expressionEval.translateExpression(whenStmt.value, valueReg, -1)
|
||||
val choices = whenStmt.choices.children.map {it as PtWhenChoice }
|
||||
val endLabel = createLabelName()
|
||||
@ -352,19 +351,19 @@ class IRCodeGen(
|
||||
val symbol = iterable.targetName.joinToString(".")
|
||||
val iterableVar = symbolTable.lookup(iterable.targetName) as StStaticVariable
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
val tmpReg = vmRegisters.nextFree()
|
||||
val indexReg = registers.nextFree()
|
||||
val tmpReg = registers.nextFree()
|
||||
val loopLabel = createLabelName()
|
||||
val endLabel = createLabelName()
|
||||
if(iterableVar.dt==DataType.STR) {
|
||||
// iterate over a zero-terminated string
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += IRInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol)
|
||||
code += IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
||||
code += IRInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol)
|
||||
code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += IRInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
||||
code += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
code += IRCodeLabel(endLabel)
|
||||
} else {
|
||||
@ -373,23 +372,23 @@ class IRCodeGen(
|
||||
val elementSize = program.memsizer.memorySize(elementDt)
|
||||
val lengthBytes = iterableVar.length!! * elementSize
|
||||
if(lengthBytes<256) {
|
||||
val lengthReg = vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||
val lengthReg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += IRInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
code += IRInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
code += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
code += IRInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
|
||||
code += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
code += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
|
||||
} else if(lengthBytes==256) {
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += IRInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
code += IRInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
code += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
code += IRInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
|
||||
code += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
code += IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
|
||||
} else {
|
||||
throw AssemblyError("iterator length should never exceed 256")
|
||||
}
|
||||
@ -405,10 +404,10 @@ class IRCodeGen(
|
||||
val step = iterable.step.number.toInt()
|
||||
if (step==0)
|
||||
throw AssemblyError("step 0")
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
val endvalueReg = vmRegisters.nextFree()
|
||||
val indexReg = registers.nextFree()
|
||||
val endvalueReg = registers.nextFree()
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val loopvarDt = vmType(loopvar.dt)
|
||||
val loopvarDt = irType(loopvar.dt)
|
||||
val loopLabel = createLabelName()
|
||||
val code = IRCodeChunk(forLoop.position)
|
||||
|
||||
@ -427,8 +426,8 @@ class IRCodeGen(
|
||||
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunk {
|
||||
val loopLabel = createLabelName()
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
val loopvarDt = vmType(loopvar.dt)
|
||||
val indexReg = registers.nextFree()
|
||||
val loopvarDt = irType(loopvar.dt)
|
||||
val iterable = forLoop.iterable as PtRange
|
||||
val step = iterable.step.number.toInt()
|
||||
val rangeStart = (iterable.from as PtNumber).number.toInt()
|
||||
@ -437,11 +436,11 @@ class IRCodeGen(
|
||||
throw AssemblyError("step 0")
|
||||
if(step>0 && rangeEndUntyped<rangeStart || step<0 && rangeEndUntyped>rangeStart)
|
||||
throw AssemblyError("empty range")
|
||||
val rangeEndWrapped = if(loopvarDt==VmDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535
|
||||
val rangeEndWrapped = if(loopvarDt==IRDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535
|
||||
val code = IRCodeChunk(forLoop.position)
|
||||
val endvalueReg: Int
|
||||
if(rangeEndWrapped!=0) {
|
||||
endvalueReg = vmRegisters.nextFree()
|
||||
endvalueReg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
|
||||
} else {
|
||||
endvalueReg = -1 // not used
|
||||
@ -460,7 +459,7 @@ class IRCodeGen(
|
||||
return code
|
||||
}
|
||||
|
||||
private fun addConstReg(dt: VmDataType, reg: Int, value: Int, position: Position): IRCodeChunk {
|
||||
private fun addConstReg(dt: IRDataType, reg: Int, value: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
when(value) {
|
||||
0 -> { /* do nothing */ }
|
||||
@ -489,7 +488,7 @@ class IRCodeGen(
|
||||
return code
|
||||
}
|
||||
|
||||
private fun addConstMem(dt: VmDataType, knownAddress: UInt?, symbol: String?, value: Int, position: Position): IRCodeChunk {
|
||||
private fun addConstMem(dt: IRDataType, knownAddress: UInt?, symbol: String?, value: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
when(value) {
|
||||
0 -> { /* do nothing */ }
|
||||
@ -524,7 +523,7 @@ class IRCodeGen(
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val valueReg = vmRegisters.nextFree()
|
||||
val valueReg = registers.nextFree()
|
||||
if(value>0) {
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value)
|
||||
code += if(knownAddress!=null)
|
||||
@ -549,9 +548,9 @@ class IRCodeGen(
|
||||
if(factor==1f)
|
||||
return code
|
||||
code += if(factor==0f) {
|
||||
IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
|
||||
IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
|
||||
} else {
|
||||
IRInstruction(Opcode.MUL, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||
IRInstruction(Opcode.MUL, IRDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||
}
|
||||
return code
|
||||
}
|
||||
@ -562,23 +561,23 @@ class IRCodeGen(
|
||||
return code
|
||||
if(factor==0f) {
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = knownAddress)
|
||||
IRInstruction(Opcode.STOREZM, IRDataType.FLOAT, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.STOREZM, VmDataType.FLOAT, labelSymbol = symbol)
|
||||
IRInstruction(Opcode.STOREZM, IRDataType.FLOAT, labelSymbol = symbol)
|
||||
} else {
|
||||
val factorReg = vmRegisters.nextFreeFloat()
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||
val factorReg = registers.nextFreeFloat()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = knownAddress)
|
||||
IRInstruction(Opcode.MULM, IRDataType.FLOAT, fpReg1 = factorReg, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
||||
IRInstruction(Opcode.MULM, IRDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
|
||||
|
||||
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int, position: Position): IRCodeChunk {
|
||||
internal fun multiplyByConst(dt: IRDataType, reg: Int, factor: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
if(factor==1)
|
||||
return code
|
||||
@ -589,7 +588,7 @@ class IRCodeGen(
|
||||
}
|
||||
else if(pow2>=1) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
val pow2reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += IRInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
|
||||
} else {
|
||||
@ -602,7 +601,7 @@ class IRCodeGen(
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun multiplyByConstInplace(dt: VmDataType, knownAddress: Int?, symbol: String?, factor: Int, position: Position): IRCodeChunk {
|
||||
internal fun multiplyByConstInplace(dt: IRDataType, knownAddress: Int?, symbol: String?, factor: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
if(factor==1)
|
||||
return code
|
||||
@ -616,7 +615,7 @@ class IRCodeGen(
|
||||
}
|
||||
else if(pow2>=1) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
val pow2reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.LSLNM, dt, reg1=pow2reg, value=knownAddress)
|
||||
@ -630,7 +629,7 @@ class IRCodeGen(
|
||||
IRInstruction(Opcode.STOREZM, dt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val factorReg = vmRegisters.nextFree()
|
||||
val factorReg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.MULM, dt, reg1=factorReg, value = knownAddress)
|
||||
@ -646,9 +645,9 @@ class IRCodeGen(
|
||||
if(factor==1f)
|
||||
return code
|
||||
code += if(factor==0f) {
|
||||
IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = Float.MAX_VALUE)
|
||||
IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = fpReg, fpValue = Float.MAX_VALUE)
|
||||
} else {
|
||||
IRInstruction(Opcode.DIVS, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||
IRInstruction(Opcode.DIVS, IRDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||
}
|
||||
return code
|
||||
}
|
||||
@ -658,24 +657,24 @@ class IRCodeGen(
|
||||
if(factor==1f)
|
||||
return code
|
||||
if(factor==0f) {
|
||||
val maxvalueReg = vmRegisters.nextFreeFloat()
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
|
||||
val maxvalueReg = registers.nextFreeFloat()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, value=knownAddress)
|
||||
IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = maxvalueReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, labelSymbol = symbol)
|
||||
IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = maxvalueReg, labelSymbol = symbol)
|
||||
} else {
|
||||
val factorReg = vmRegisters.nextFreeFloat()
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||
val factorReg = registers.nextFreeFloat()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, value=knownAddress)
|
||||
IRInstruction(Opcode.DIVSM, IRDataType.FLOAT, fpReg1 = factorReg, value=knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
||||
IRInstruction(Opcode.DIVSM, IRDataType.FLOAT, fpReg1 = factorReg, labelSymbol = symbol)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
|
||||
internal fun divideByConst(dt: IRDataType, reg: Int, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
if(factor==1)
|
||||
return code
|
||||
@ -685,7 +684,7 @@ class IRCodeGen(
|
||||
}
|
||||
else if(pow2>=1 &&!signed) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
val pow2reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += if(signed)
|
||||
IRInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
|
||||
@ -704,7 +703,7 @@ class IRCodeGen(
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun divideByConstInplace(dt: VmDataType, knownAddress: Int?, symbol: String?, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
|
||||
internal fun divideByConstInplace(dt: IRDataType, knownAddress: Int?, symbol: String?, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
if(factor==1)
|
||||
return code
|
||||
@ -718,7 +717,7 @@ class IRCodeGen(
|
||||
}
|
||||
else if(pow2>=1 && !signed) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
val pow2reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += if(signed) {
|
||||
if(knownAddress!=null)
|
||||
@ -734,7 +733,7 @@ class IRCodeGen(
|
||||
}
|
||||
} else {
|
||||
if (factor == 0) {
|
||||
val reg = vmRegisters.nextFree()
|
||||
val reg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.STOREM, dt, reg1=reg, value=knownAddress)
|
||||
@ -742,7 +741,7 @@ class IRCodeGen(
|
||||
IRInstruction(Opcode.STOREM, dt, reg1=reg, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val factorReg = vmRegisters.nextFree()
|
||||
val factorReg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
|
||||
code += if(signed) {
|
||||
if(knownAddress!=null)
|
||||
@ -766,7 +765,7 @@ class IRCodeGen(
|
||||
throw AssemblyError("if condition should only be a binary comparison expression")
|
||||
|
||||
val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
||||
val vmDt = vmType(ifElse.condition.left.type)
|
||||
val irDt = irType(ifElse.condition.left.type)
|
||||
val code = IRCodeChunk(ifElse.position)
|
||||
|
||||
fun translateNonZeroComparison(): IRCodeChunk {
|
||||
@ -780,15 +779,15 @@ class IRCodeGen(
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
|
||||
val leftReg = vmRegisters.nextFree()
|
||||
val rightReg = vmRegisters.nextFree()
|
||||
val leftReg = registers.nextFree()
|
||||
val rightReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
code += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1)
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += IRCodeLabel(elseLabel)
|
||||
@ -797,7 +796,7 @@ class IRCodeGen(
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRCodeLabel(afterIfLabel)
|
||||
}
|
||||
@ -806,13 +805,13 @@ class IRCodeGen(
|
||||
|
||||
fun translateZeroComparison(): IRCodeChunk {
|
||||
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunk {
|
||||
val leftReg = vmRegisters.nextFree()
|
||||
val leftReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += IRCodeLabel(elseLabel)
|
||||
@ -821,7 +820,7 @@ class IRCodeGen(
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRCodeLabel(afterIfLabel)
|
||||
}
|
||||
@ -868,20 +867,20 @@ class IRCodeGen(
|
||||
val ident = postIncrDecr.target.identifier
|
||||
val memory = postIncrDecr.target.memory
|
||||
val array = postIncrDecr.target.array
|
||||
val vmDt = vmType(postIncrDecr.target.type)
|
||||
val irDt = irType(postIncrDecr.target.type)
|
||||
if(ident!=null) {
|
||||
code += IRInstruction(operationMem, vmDt, labelSymbol = ident.targetName.joinToString("."))
|
||||
code += IRInstruction(operationMem, irDt, labelSymbol = ident.targetName.joinToString("."))
|
||||
} else if(memory!=null) {
|
||||
if(memory.address is PtNumber) {
|
||||
val address = (memory.address as PtNumber).number.toInt()
|
||||
code += IRInstruction(operationMem, vmDt, value = address)
|
||||
code += IRInstruction(operationMem, irDt, value = address)
|
||||
} else {
|
||||
val incReg = vmRegisters.nextFree()
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
val incReg = registers.nextFree()
|
||||
val addressReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRInstruction(Opcode.LOADI, vmDt, reg1 = incReg, reg2 = addressReg)
|
||||
code += IRInstruction(operationRegister, vmDt, reg1 = incReg)
|
||||
code += IRInstruction(Opcode.STOREI, vmDt, reg1 = incReg, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = addressReg)
|
||||
code += IRInstruction(operationRegister, irDt, reg1 = incReg)
|
||||
code += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = addressReg)
|
||||
}
|
||||
} else if (array!=null) {
|
||||
val variable = array.variable.targetName.joinToString(".")
|
||||
@ -889,14 +888,14 @@ class IRCodeGen(
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(operationMem, vmDt, labelSymbol="$variable+$offset")
|
||||
code += IRInstruction(operationMem, irDt, labelSymbol="$variable+$offset")
|
||||
} else {
|
||||
val incReg = vmRegisters.nextFree()
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
val incReg = registers.nextFree()
|
||||
val indexReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
code += IRInstruction(Opcode.LOADX, vmDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
code += IRInstruction(operationRegister, vmDt, reg1=incReg)
|
||||
code += IRInstruction(Opcode.STOREX, vmDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
code += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
code += IRInstruction(operationRegister, irDt, reg1=incReg)
|
||||
code += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
}
|
||||
} else
|
||||
throw AssemblyError("weird assigntarget")
|
||||
@ -917,28 +916,30 @@ class IRCodeGen(
|
||||
val repeatLabel = createLabelName()
|
||||
val skipRepeatLabel = createLabelName()
|
||||
val code = IRCodeChunk(repeat.position)
|
||||
val counterReg = vmRegisters.nextFree()
|
||||
val vmDt = vmType(repeat.count.type)
|
||||
val counterReg = registers.nextFree()
|
||||
val irDt = irType(repeat.count.type)
|
||||
code += expressionEval.translateExpression(repeat.count, counterReg, -1)
|
||||
code += IRInstruction(Opcode.BZ, vmDt, reg1=counterReg, labelSymbol = skipRepeatLabel)
|
||||
code += IRInstruction(Opcode.BZ, irDt, reg1=counterReg, labelSymbol = skipRepeatLabel)
|
||||
code += IRCodeLabel(repeatLabel)
|
||||
code += translateNode(repeat.statements)
|
||||
code += IRInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
||||
code += IRInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||
code += IRInstruction(Opcode.DEC, irDt, reg1=counterReg)
|
||||
code += IRInstruction(Opcode.BNZ, irDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||
code += IRCodeLabel(skipRepeatLabel)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(jump: PtJump): IRCodeChunk {
|
||||
val code = IRCodeChunk(jump.position)
|
||||
if(jump.address!=null)
|
||||
throw AssemblyError("cannot jump to memory location in the vm target")
|
||||
code += if(jump.generatedLabel!=null)
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = jump.generatedLabel!!)
|
||||
else if(jump.identifier!=null)
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName.joinToString("."))
|
||||
else
|
||||
throw AssemblyError("weird jump")
|
||||
code += if(jump.address!=null) {
|
||||
IRInstruction(Opcode.JUMPA, value = jump.address!!.toInt())
|
||||
} else {
|
||||
if (jump.generatedLabel != null)
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = jump.generatedLabel!!)
|
||||
else if (jump.identifier != null)
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName.joinToString("."))
|
||||
else
|
||||
throw AssemblyError("weird jump")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
@ -963,24 +964,24 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
private fun translate(block: PtBlock): IRBlock {
|
||||
val vmblock = IRBlock(block.name, block.address, translate(block.alignment), block.position) // no use for other attributes yet?
|
||||
val irBlock = IRBlock(block.name, block.address, translate(block.alignment), block.position) // no use for other attributes yet?
|
||||
for (child in block.children) {
|
||||
when(child) {
|
||||
is PtNop -> { /* nothing */ }
|
||||
is PtAssignment -> { /* global variable initialization is done elsewhere */ }
|
||||
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
|
||||
is PtSub -> {
|
||||
val vmsub = IRSubroutine(child.name, translate(child.parameters), child.returntype, child.position)
|
||||
val sub = IRSubroutine(child.name, translate(child.parameters), child.returntype, child.position)
|
||||
for (subchild in child.children) {
|
||||
val translated = translateNode(subchild)
|
||||
if(translated.isNotEmpty())
|
||||
vmsub += translated
|
||||
sub += translated
|
||||
}
|
||||
vmblock += vmsub
|
||||
irBlock += sub
|
||||
}
|
||||
is PtAsmSub -> {
|
||||
val assemblyChild = if(child.children.isEmpty()) null else (child.children.single() as PtInlineAssembly)
|
||||
vmblock += IRAsmSubroutine(
|
||||
irBlock += IRAsmSubroutine(
|
||||
child.name, child.position, child.address,
|
||||
child.clobbers,
|
||||
child.parameters.map { Pair(it.first.type, it.second) }, // note: the name of the asmsub param is not used anymore.
|
||||
@ -990,12 +991,12 @@ class IRCodeGen(
|
||||
)
|
||||
}
|
||||
is PtInlineAssembly -> {
|
||||
vmblock += IRInlineAsmChunk(child.assembly, child.isIR, child.position)
|
||||
irBlock += IRInlineAsmChunk(child.assembly, child.isIR, child.position)
|
||||
}
|
||||
else -> TODO("BLOCK HAS WEIRD CHILD NODE $child")
|
||||
else -> TODO("weird child node $child")
|
||||
}
|
||||
}
|
||||
return vmblock
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun translate(parameters: List<PtSubroutineParameter>) =
|
||||
@ -1014,16 +1015,16 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
|
||||
internal fun vmType(type: DataType): VmDataType {
|
||||
internal fun irType(type: DataType): IRDataType {
|
||||
return when(type) {
|
||||
DataType.BOOL,
|
||||
DataType.UBYTE,
|
||||
DataType.BYTE -> VmDataType.BYTE
|
||||
DataType.BYTE -> IRDataType.BYTE
|
||||
DataType.UWORD,
|
||||
DataType.WORD -> VmDataType.WORD
|
||||
DataType.FLOAT -> VmDataType.FLOAT
|
||||
in PassByReferenceDatatypes -> VmDataType.WORD
|
||||
else -> throw AssemblyError("no vm datatype for $type")
|
||||
DataType.WORD -> IRDataType.WORD
|
||||
DataType.FLOAT -> IRDataType.FLOAT
|
||||
in PassByReferenceDatatypes -> IRDataType.WORD
|
||||
else -> throw AssemblyError("no IR datatype for $type")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,12 +111,11 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
}
|
||||
|
||||
private fun removeWeirdBranches(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
// jump/branch to label immediately below
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
val labelSymbol = ins.labelSymbol
|
||||
if(ins.opcode== Opcode.JUMP && labelSymbol!=null) {
|
||||
// if jumping to label immediately following this
|
||||
// remove jump/branch to label immediately below
|
||||
if(idx < chunk.lines.size-1) {
|
||||
val label = chunk.lines[idx+1] as? IRCodeLabel
|
||||
if(label?.name == labelSymbol) {
|
||||
@ -125,6 +124,14 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove useless RETURN
|
||||
if(ins.opcode == Opcode.RETURN && idx>0) {
|
||||
val previous = chunk.lines[idx-1] as? IRInstruction
|
||||
if(previous?.opcode in setOf(Opcode.JUMP, Opcode.JUMPA, Opcode.RETURN)) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
@ -157,10 +164,10 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
|
||||
changed = true
|
||||
} else if (ins.value == 255 && ins.type == VmDataType.BYTE) {
|
||||
} else if (ins.value == 255 && ins.type == IRDataType.BYTE) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
} else if (ins.value == 65535 && ins.type == VmDataType.WORD) {
|
||||
} else if (ins.value == 65535 && ins.type == IRDataType.WORD) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
@ -169,7 +176,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
} else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) {
|
||||
} else if ((ins.value == 255 && ins.type == IRDataType.BYTE) || (ins.value == 65535 && ins.type == IRDataType.WORD)) {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
|
||||
changed = true
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.NOP), // removed
|
||||
IRCodeLabel("label2"),
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "label3"),
|
||||
IRInstruction(Opcode.INC, VmDataType.BYTE, reg1=1),
|
||||
IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1),
|
||||
IRCodeLabel("label3")
|
||||
))
|
||||
irProg.lines().size shouldBe 8
|
||||
@ -86,10 +86,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
|
||||
test("push followed by pop") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=42),
|
||||
IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=42),
|
||||
IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=99),
|
||||
IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=222)
|
||||
IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=42),
|
||||
IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=42),
|
||||
IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=99),
|
||||
IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=222)
|
||||
))
|
||||
irProg.lines().size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
@ -103,16 +103,16 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
|
||||
test("remove useless div/mul, add/sub") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 0)
|
||||
IRInstruction(Opcode.DIV, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.DIVS, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.MUL, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.MOD, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.DIV, IRDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.DIVS, IRDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.MUL, IRDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.MOD, IRDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 0)
|
||||
))
|
||||
irProg.lines().size shouldBe 10
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
@ -123,8 +123,8 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
|
||||
test("replace add/sub 1 by inc/dec") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 1)
|
||||
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.lines().size shouldBe 2
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
@ -137,14 +137,14 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
|
||||
test("remove useless and/or/xor") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 65535),
|
||||
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 200),
|
||||
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 60000),
|
||||
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 1)
|
||||
IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.AND, IRDataType.WORD, reg1=42, value = 65535),
|
||||
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.XOR, IRDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=42, value = 200),
|
||||
IRInstruction(Opcode.AND, IRDataType.WORD, reg1=42, value = 60000),
|
||||
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.XOR, IRDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.lines().size shouldBe 8
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
@ -155,10 +155,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
|
||||
test("replace and/or/xor by constant number") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.OR, VmDataType.WORD, reg1=42, value = 65535)
|
||||
IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.AND, IRDataType.WORD, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, value = 65535)
|
||||
))
|
||||
irProg.lines().size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
|
@ -15,6 +15,9 @@ class TestLaunchEmu: FunSpec({
|
||||
<OPTIONS>
|
||||
</OPTIONS>
|
||||
|
||||
<ASMSYMBOLS>
|
||||
</ASMSYMBOLS>
|
||||
|
||||
<VARIABLES>
|
||||
</VARIABLES>
|
||||
|
||||
|
@ -1,28 +1,4 @@
|
||||
%option enable_floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
%asm {{
|
||||
lda #99
|
||||
rts
|
||||
}}
|
||||
|
||||
%ir {{
|
||||
nop
|
||||
loadr r1,r2
|
||||
return
|
||||
}}
|
||||
|
||||
ubyte @shared @zp var1 = 42
|
||||
uword @shared @zp var2 = 4242
|
||||
str @shared name = "irmen"
|
||||
ubyte[] @shared array1 = [11,22,33,44]
|
||||
uword[5] @shared array2 = 9999
|
||||
uword[5] @shared array3
|
||||
float @shared fvar = 1.234
|
||||
float @shared fvar2
|
||||
float[] @shared farray1 = [1.11,2.22,3.33]
|
||||
float[5] @shared farray2 = 999.9
|
||||
float[5] @shared farray3
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ class IRFileReader {
|
||||
val match = programPattern.matchEntire(line) ?: throw IRParseException("invalid PROGRAM")
|
||||
val programName = match.groups[1]!!.value
|
||||
val options = parseOptions(lines)
|
||||
val asmsymbols = parseAsmSymbols(lines)
|
||||
val variables = parseVariables(lines, options.dontReinitGlobals)
|
||||
val memorymapped = parseMemMapped(lines)
|
||||
val slabs = parseSlabs(lines)
|
||||
@ -34,6 +35,7 @@ class IRFileReader {
|
||||
val blocks = parseBlocksUntilProgramEnd(lines, variables)
|
||||
|
||||
val st = IRSymbolTable(null)
|
||||
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
|
||||
variables.forEach { st.add(it) }
|
||||
memorymapped.forEach { st.add(it) }
|
||||
slabs.forEach { st.add(it) }
|
||||
@ -44,6 +46,22 @@ class IRFileReader {
|
||||
return program
|
||||
}
|
||||
|
||||
private fun parseAsmSymbols(lines: Iterator<String>): Map<String, String> {
|
||||
val symbols = mutableMapOf<String, String>()
|
||||
var line = lines.next()
|
||||
while(line.isBlank())
|
||||
line = lines.next()
|
||||
if(line!="<ASMSYMBOLS>")
|
||||
throw IRParseException("invalid ASMSYMBOLS")
|
||||
while(true) {
|
||||
line = lines.next()
|
||||
if(line=="</ASMSYMBOLS>")
|
||||
return symbols
|
||||
val (name, value) = line.split('=')
|
||||
symbols[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseOptions(lines: Iterator<String>): CompilationOptions {
|
||||
var line = lines.next()
|
||||
while(line.isBlank())
|
||||
|
@ -18,6 +18,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
println("Writing intermediate representation to $outfile")
|
||||
out.write("<PROGRAM NAME=${irProgram.name}>\n")
|
||||
writeOptions()
|
||||
writeAsmSymbols()
|
||||
writeVariableAllocations()
|
||||
|
||||
out.write("\n<INITGLOBALS>\n")
|
||||
@ -36,6 +37,12 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
return outfile
|
||||
}
|
||||
|
||||
private fun writeAsmSymbols() {
|
||||
out.write("<ASMSYMBOLS>\n")
|
||||
irProgram.asmSymbols.forEach { (name, value) -> out.write("$name=$value\n" )}
|
||||
out.write("</ASMSYMBOLS>\n")
|
||||
}
|
||||
|
||||
private fun writeBlocks() {
|
||||
irProgram.blocks.forEach { block ->
|
||||
out.write("\n<BLOCK NAME=${block.name} ADDRESS=${block.address} ALIGN=${block.alignment} POS=${block.position}>\n")
|
||||
|
@ -51,6 +51,7 @@ But you can decide whatever you want because here we just care about jumping and
|
||||
Saving/restoring registers is possible with PUSH and POP instructions.
|
||||
|
||||
jump location - continue running at instruction number given by location
|
||||
jumpa address - continue running at memory address (note: only used to encode a physical cpu jump to fixed address instruction)
|
||||
call location - save current instruction location+1, continue execution at instruction nr given by location
|
||||
calli reg1 - save current instruction location+1, continue execution at instruction number in reg1
|
||||
syscall value - do a systemcall identified by call number
|
||||
@ -67,6 +68,8 @@ bsteq address - branch to location if Status bit Zero
|
||||
bstne address - branch to location if Status bit Zero is not set
|
||||
bstneg address - branch to location if Status bit Negative is not set
|
||||
bstpos address - branch to location if Status bit Negative is not set
|
||||
bstvc address - branch to location if Status bit Overflow is not set
|
||||
bstvs address - branch to location if Status bit Overflow is not set
|
||||
bz reg1, address - branch to location if reg1 is zero
|
||||
bnz reg1, address - branch to location if reg1 is not zero
|
||||
beq reg1, reg2, address - jump to location in program given by location, if reg1 == reg2
|
||||
@ -223,6 +226,7 @@ enum class Opcode {
|
||||
STOREZX,
|
||||
|
||||
JUMP,
|
||||
JUMPA,
|
||||
CALL,
|
||||
SYSCALL,
|
||||
RETURN,
|
||||
@ -233,6 +237,8 @@ enum class Opcode {
|
||||
BSTNE,
|
||||
BSTNEG,
|
||||
BSTPOS,
|
||||
BSTVC,
|
||||
BSTVS,
|
||||
BZ,
|
||||
BNZ,
|
||||
BEQ,
|
||||
@ -359,6 +365,7 @@ val OpcodesWithAddress = setOf(
|
||||
Opcode.STOREZM,
|
||||
Opcode.STOREZX,
|
||||
Opcode.JUMP,
|
||||
Opcode.JUMPA,
|
||||
Opcode.CALL,
|
||||
Opcode.INCM,
|
||||
Opcode.DECM,
|
||||
@ -404,6 +411,7 @@ val OpcodesWithAddress = setOf(
|
||||
|
||||
val OpcodesThatBranch = setOf(
|
||||
Opcode.JUMP,
|
||||
Opcode.JUMPA,
|
||||
Opcode.RETURN,
|
||||
Opcode.BSTCC,
|
||||
Opcode.BSTCS,
|
||||
@ -411,6 +419,8 @@ val OpcodesThatBranch = setOf(
|
||||
Opcode.BSTNE,
|
||||
Opcode.BSTNEG,
|
||||
Opcode.BSTPOS,
|
||||
Opcode.BSTVC,
|
||||
Opcode.BSTVS,
|
||||
Opcode.BZ,
|
||||
Opcode.BNZ,
|
||||
Opcode.BEQ,
|
||||
@ -432,7 +442,7 @@ val OpcodesForCpuRegisters = setOf(
|
||||
)
|
||||
|
||||
|
||||
enum class VmDataType {
|
||||
enum class IRDataType {
|
||||
BYTE,
|
||||
WORD,
|
||||
FLOAT
|
||||
@ -445,7 +455,7 @@ enum class OperandDirection {
|
||||
INOUT
|
||||
}
|
||||
|
||||
data class InstructionFormat(val datatype: VmDataType?,
|
||||
data class InstructionFormat(val datatype: IRDataType?,
|
||||
val reg1: Boolean, val reg1direction: OperandDirection, // reg1 can be IN/OUT/INOUT
|
||||
val reg2: Boolean, // always only IN
|
||||
val fpReg1: Boolean, val fpReg1direction: OperandDirection, // fpreg1 can be IN/OUT/INOUT
|
||||
@ -454,8 +464,8 @@ data class InstructionFormat(val datatype: VmDataType?,
|
||||
val fpValue: Boolean // always only IN
|
||||
) {
|
||||
companion object {
|
||||
fun from(spec: String): Map<VmDataType?, InstructionFormat> {
|
||||
val result = mutableMapOf<VmDataType?, InstructionFormat>()
|
||||
fun from(spec: String): Map<IRDataType?, InstructionFormat> {
|
||||
val result = mutableMapOf<IRDataType?, InstructionFormat>()
|
||||
for(part in spec.split('|').map{ it.trim() }) {
|
||||
var reg1 = false // read/write/modify possible
|
||||
var reg1Direction = OperandDirection.INPUT
|
||||
@ -485,11 +495,11 @@ data class InstructionFormat(val datatype: VmDataType?,
|
||||
if(typespec=="N")
|
||||
result[null] = InstructionFormat(null, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
|
||||
if('B' in typespec)
|
||||
result[VmDataType.BYTE] = InstructionFormat(VmDataType.BYTE, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
|
||||
result[IRDataType.BYTE] = InstructionFormat(IRDataType.BYTE, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
|
||||
if('W' in typespec)
|
||||
result[VmDataType.WORD] = InstructionFormat(VmDataType.WORD, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
|
||||
result[IRDataType.WORD] = InstructionFormat(IRDataType.WORD, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
|
||||
if('F' in typespec)
|
||||
result[VmDataType.FLOAT] = InstructionFormat(VmDataType.FLOAT, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
|
||||
result[IRDataType.FLOAT] = InstructionFormat(IRDataType.FLOAT, reg1, reg1Direction, reg2, fpreg1, fpreg1Direction, fpreg2, value, fpvalue)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -522,6 +532,7 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.STOREZI to InstructionFormat.from("BW,<r1 | F,<r1"),
|
||||
Opcode.STOREZX to InstructionFormat.from("BW,<r1,<v | F,<r1,<v"),
|
||||
Opcode.JUMP to InstructionFormat.from("N,<v"),
|
||||
Opcode.JUMPA to InstructionFormat.from("N,<v"),
|
||||
Opcode.CALL to InstructionFormat.from("N,<v"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,<v"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
@ -531,6 +542,8 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.BSTNE to InstructionFormat.from("N,<v"),
|
||||
Opcode.BSTNEG to InstructionFormat.from("N,<v"),
|
||||
Opcode.BSTPOS to InstructionFormat.from("N,<v"),
|
||||
Opcode.BSTVC to InstructionFormat.from("N,<v"),
|
||||
Opcode.BSTVS to InstructionFormat.from("N,<v"),
|
||||
Opcode.BZ to InstructionFormat.from("BW,<r1,<v"),
|
||||
Opcode.BNZ to InstructionFormat.from("BW,<r1,<v"),
|
||||
Opcode.BEQ to InstructionFormat.from("BW,<r1,<r2,<v"),
|
||||
@ -648,7 +661,7 @@ val instructionFormats = mutableMapOf(
|
||||
|
||||
data class IRInstruction(
|
||||
val opcode: Opcode,
|
||||
val type: VmDataType?=null,
|
||||
val type: IRDataType?=null,
|
||||
val reg1: Int?=null, // 0-$ffff
|
||||
val reg2: Int?=null, // 0-$ffff
|
||||
val fpReg1: Int?=null, // 0-$ffff
|
||||
@ -671,9 +684,9 @@ data class IRInstruction(
|
||||
require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
|
||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||
when (type) {
|
||||
VmDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}
|
||||
VmDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"}
|
||||
VmDataType.FLOAT, null -> {}
|
||||
IRDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}
|
||||
IRDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"}
|
||||
IRDataType.FLOAT, null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -694,7 +707,7 @@ data class IRInstruction(
|
||||
if(!format.fpReg1) require(fpReg1==null) { "invalid fpReg1" }
|
||||
if(!format.fpReg2) require(fpReg2==null) { "invalid fpReg2" }
|
||||
|
||||
if (type==VmDataType.FLOAT) {
|
||||
if (type==IRDataType.FLOAT) {
|
||||
if(format.fpValue) require(fpValue!=null || labelSymbol!=null) {"missing a fp-value or labelsymbol"}
|
||||
} else {
|
||||
if(format.value) require(value!=null || labelSymbol!=null) {"missing a value or labelsymbol"}
|
||||
@ -710,7 +723,7 @@ data class IRInstruction(
|
||||
Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS,
|
||||
Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES,
|
||||
Opcode.SGE, Opcode.SGES)) {
|
||||
if(type==VmDataType.FLOAT)
|
||||
if(type==IRDataType.FLOAT)
|
||||
require(fpReg1!=fpReg2) {"$opcode: fpReg1 and fpReg2 should be different"}
|
||||
else
|
||||
require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"}
|
||||
@ -721,9 +734,9 @@ data class IRInstruction(
|
||||
val result = mutableListOf(opcode.name.lowercase())
|
||||
|
||||
when(type) {
|
||||
VmDataType.BYTE -> result.add(".b ")
|
||||
VmDataType.WORD -> result.add(".w ")
|
||||
VmDataType.FLOAT -> result.add(".f ")
|
||||
IRDataType.BYTE -> result.add(".b ")
|
||||
IRDataType.WORD -> result.add(".w ")
|
||||
IRDataType.FLOAT -> result.add(".f ")
|
||||
else -> result.add(" ")
|
||||
}
|
||||
reg1?.let {
|
||||
|
@ -10,6 +10,7 @@ note: all symbol names are flattened so that they're a single string that is glo
|
||||
|
||||
PROGRAM:
|
||||
OPTIONS (from CompilationOptions)
|
||||
ASMSYMBOLS (from command line defined symbols)
|
||||
VARIABLES (from Symboltable)
|
||||
MEMORYMAPPEDVARIABLES (from Symboltable)
|
||||
MEMORYSLABS (from Symboltable)
|
||||
@ -50,6 +51,7 @@ class IRProgram(val name: String,
|
||||
val options: CompilationOptions,
|
||||
val encoding: IStringEncoding) {
|
||||
|
||||
val asmSymbols = mutableMapOf<String, String>()
|
||||
val globalInits = mutableListOf<IRCodeLine>()
|
||||
val blocks = mutableListOf<IRBlock>()
|
||||
|
||||
@ -58,6 +60,10 @@ class IRProgram(val name: String,
|
||||
require(blocks.all { it.name != block.name}) { "duplicate block ${block.name} ${block.position}" }
|
||||
blocks.add(block)
|
||||
}
|
||||
|
||||
fun addAsmSymbols(symbolDefs: Map<String, String>) {
|
||||
asmSymbols += symbolDefs
|
||||
}
|
||||
}
|
||||
|
||||
class IRBlock(
|
||||
|
@ -8,6 +8,7 @@ import prog8.code.*
|
||||
|
||||
class IRSymbolTable(sourceSt: SymbolTable?) {
|
||||
private val table = mutableMapOf<String, StNode>()
|
||||
private val asmSymbols = mutableMapOf<String, String>()
|
||||
|
||||
init {
|
||||
if(sourceSt!=null) {
|
||||
@ -103,4 +104,10 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
|
||||
StMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align, variable.position)
|
||||
table[varToadd.name] = varToadd
|
||||
}
|
||||
|
||||
fun addAsmSymbol(name: String, value: String) {
|
||||
asmSymbols[name] = value
|
||||
}
|
||||
|
||||
fun getAsmSymbols(): Map<String, String> = asmSymbols
|
||||
}
|
||||
|
@ -54,12 +54,12 @@ fun getTypeString(variable : StStaticVariable): String {
|
||||
}
|
||||
}
|
||||
|
||||
fun convertIRType(typestr: String): VmDataType? {
|
||||
fun convertIRType(typestr: String): IRDataType? {
|
||||
return when(typestr.lowercase()) {
|
||||
"" -> null
|
||||
".b" -> VmDataType.BYTE
|
||||
".w" -> VmDataType.WORD
|
||||
".f" -> VmDataType.FLOAT
|
||||
".b" -> IRDataType.BYTE
|
||||
".w" -> IRDataType.WORD
|
||||
".f" -> IRDataType.FLOAT
|
||||
else -> throw IRParseException("invalid type $typestr")
|
||||
}
|
||||
}
|
||||
@ -100,11 +100,11 @@ fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap<Int, String>
|
||||
} catch (ax: IllegalArgumentException) {
|
||||
throw IRParseException("invalid vmasm instruction: $instr")
|
||||
}
|
||||
var type: VmDataType? = convertIRType(typestr)
|
||||
var type: IRDataType? = convertIRType(typestr)
|
||||
val formats = instructionFormats.getValue(opcode)
|
||||
val format: InstructionFormat
|
||||
if(type !in formats) {
|
||||
type = VmDataType.BYTE
|
||||
type = IRDataType.BYTE
|
||||
format = if(type !in formats)
|
||||
formats.getValue(null)
|
||||
else
|
||||
@ -207,15 +207,15 @@ fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap<Int, String>
|
||||
throw IRParseException("invalid reg2 for $line")
|
||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||
when (type) {
|
||||
VmDataType.BYTE -> {
|
||||
IRDataType.BYTE -> {
|
||||
if (value < -128 || value > 255)
|
||||
throw IRParseException("value out of range for byte: $value")
|
||||
}
|
||||
VmDataType.WORD -> {
|
||||
IRDataType.WORD -> {
|
||||
if (value < -32768 || value > 65535)
|
||||
throw IRParseException("value out of range for word: $value")
|
||||
}
|
||||
VmDataType.FLOAT -> {}
|
||||
IRDataType.FLOAT -> {}
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ dontReinitGlobals=false
|
||||
evalStackBaseAddress=null
|
||||
</OPTIONS>
|
||||
|
||||
<ASMSYMBOLS>
|
||||
</ASMSYMBOLS>
|
||||
|
||||
<VARIABLES>
|
||||
uword sys.wait.jiffies= zp=DONTCARE
|
||||
</VARIABLES>
|
||||
|
@ -22,9 +22,9 @@ class TestInstructions: FunSpec({
|
||||
}
|
||||
|
||||
test("with value") {
|
||||
val ins = IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=42, value = 99)
|
||||
val ins = IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42, value = 99)
|
||||
ins.opcode shouldBe Opcode.BZ
|
||||
ins.type shouldBe VmDataType.BYTE
|
||||
ins.type shouldBe IRDataType.BYTE
|
||||
ins.reg1 shouldBe 42
|
||||
ins.reg2 shouldBe null
|
||||
ins.value shouldBe 99
|
||||
@ -35,9 +35,9 @@ class TestInstructions: FunSpec({
|
||||
}
|
||||
|
||||
test("with label") {
|
||||
val ins = IRInstruction(Opcode.BZ, VmDataType.WORD, reg1=11, labelSymbol = "a.b.c")
|
||||
val ins = IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=11, labelSymbol = "a.b.c")
|
||||
ins.opcode shouldBe Opcode.BZ
|
||||
ins.type shouldBe VmDataType.WORD
|
||||
ins.type shouldBe IRDataType.WORD
|
||||
ins.reg1 shouldBe 11
|
||||
ins.reg2 shouldBe null
|
||||
ins.value shouldBe null
|
||||
@ -48,9 +48,9 @@ class TestInstructions: FunSpec({
|
||||
}
|
||||
|
||||
test("with output registers") {
|
||||
val ins = IRInstruction(Opcode.ADDR, VmDataType.WORD, reg1=11, reg2=22)
|
||||
val ins = IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1=11, reg2=22)
|
||||
ins.opcode shouldBe Opcode.ADDR
|
||||
ins.type shouldBe VmDataType.WORD
|
||||
ins.type shouldBe IRDataType.WORD
|
||||
ins.reg1 shouldBe 11
|
||||
ins.reg2 shouldBe 22
|
||||
ins.value shouldBe null
|
||||
@ -59,9 +59,9 @@ class TestInstructions: FunSpec({
|
||||
ins.fpReg1direction shouldBe OperandDirection.INPUT
|
||||
ins.toString() shouldBe "addr.w r11,r22"
|
||||
|
||||
val ins2 = IRInstruction(Opcode.SQRT, VmDataType.BYTE, reg1=11, reg2=22)
|
||||
val ins2 = IRInstruction(Opcode.SQRT, IRDataType.BYTE, reg1=11, reg2=22)
|
||||
ins2.opcode shouldBe Opcode.SQRT
|
||||
ins2.type shouldBe VmDataType.BYTE
|
||||
ins2.type shouldBe IRDataType.BYTE
|
||||
ins2.reg1 shouldBe 11
|
||||
ins2.reg2 shouldBe 22
|
||||
ins2.value shouldBe null
|
||||
@ -80,13 +80,13 @@ class TestInstructions: FunSpec({
|
||||
|
||||
test("missing registers should fail") {
|
||||
shouldThrowWithMessage<IllegalArgumentException>("missing reg1") {
|
||||
IRInstruction(Opcode.BZ, VmDataType.BYTE, value=99)
|
||||
IRInstruction(Opcode.BZ, IRDataType.BYTE, value=99)
|
||||
}
|
||||
}
|
||||
|
||||
test("missing value should fail") {
|
||||
shouldThrowWithMessage<IllegalArgumentException>("missing a value or labelsymbol") {
|
||||
IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=42)
|
||||
IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=42)
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,8 +44,8 @@ class TestVm: FunSpec( {
|
||||
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
|
||||
val code = IRCodeChunk(Position.DUMMY)
|
||||
code += IRInstruction(Opcode.NOP)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.WORD, reg1=1, value=12345)
|
||||
code += IRInstruction(Opcode.STOREM, VmDataType.WORD, reg1=1, value=1000)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=1, value=12345)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1=1, value=1000)
|
||||
code += IRInstruction(Opcode.RETURN)
|
||||
startSub += code
|
||||
block += startSub
|
||||
@ -107,6 +107,9 @@ class TestVm: FunSpec( {
|
||||
<OPTIONS>
|
||||
</OPTIONS>
|
||||
|
||||
<ASMSYMBOLS>
|
||||
</ASMSYMBOLS>
|
||||
|
||||
<VARIABLES>
|
||||
</VARIABLES>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user