rename IR classes

This commit is contained in:
Irmen de Jong 2022-08-25 22:38:53 +02:00
parent b0704e86f0
commit 97f4316653
8 changed files with 778 additions and 761 deletions

View File

@ -7,7 +7,7 @@ import prog8.vm.VmDataType
internal class AssignmentGen(private val codeGen: CodeGen, private val expressionEval: ExpressionGen) {
internal fun translate(assignment: PtAssignment): VmCodeChunk {
internal fun translate(assignment: PtAssignment): IRCodeChunk {
if(assignment.target.children.single() is PtMachineRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
@ -17,7 +17,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
translateRegularAssign(assignment)
}
private fun translateInplaceAssign(assignment: PtAssignment): VmCodeChunk {
private fun translateInplaceAssign(assignment: PtAssignment): IRCodeChunk {
val ident = assignment.target.identifier
val memory = assignment.target.memory
val array = assignment.target.array
@ -44,9 +44,9 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
address: Int,
value: PtExpression,
origAssign: PtAssignment
): VmCodeChunk {
): IRCodeChunk {
val vmDt = codeGen.vmType(value.type)
val code = VmCodeChunk(origAssign.position)
val code = IRCodeChunk(origAssign.position)
when(value) {
is PtIdentifier -> return code // do nothing, x=x null assignment.
is PtMachineRegister -> return code // do nothing, reg=reg null assignment
@ -58,8 +58,8 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
else {
// read and write a (i/o) memory location to itself.
val tempReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
code
}
}
@ -68,7 +68,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
}
private fun fallbackAssign(origAssign: PtAssignment): VmCodeChunk {
private fun fallbackAssign(origAssign: PtAssignment): IRCodeChunk {
if (codeGen.options.slowCodegenWarnings)
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
return translateRegularAssign(origAssign)
@ -81,7 +81,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
signed: Boolean,
address: Int,
origAssign: PtAssignment
): VmCodeChunk {
): IRCodeChunk {
when(operator) {
"+" -> return expressionEval.operatorPlusInplace(address, vmDt, operand)
"-" -> return expressionEval.operatorMinusInplace(address, vmDt, operand)
@ -97,32 +97,32 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
return fallbackAssign(origAssign)
}
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int, position: Position): VmCodeChunk {
val code= VmCodeChunk(position)
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int, position: Position): IRCodeChunk {
val code= IRCodeChunk(position)
when(operator) {
"+" -> { }
"-" -> {
code += VmCodeInstruction(Opcode.NEGM, vmDt, value = address)
code += IRCodeInstruction(Opcode.NEGM, vmDt, value = address)
}
"~" -> {
val regMask = codeGen.vmRegisters.nextFree()
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = address)
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
code += IRCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = address)
}
else -> throw AssemblyError("weird prefix operator")
}
return code
}
private fun translateRegularAssign(assignment: PtAssignment): VmCodeChunk {
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunk {
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
val ident = assignment.target.identifier
val memory = assignment.target.memory
val array = assignment.target.array
val vmDt = codeGen.vmType(assignment.value.type)
val code = VmCodeChunk(assignment.position)
val code = IRCodeChunk(assignment.position)
var resultRegister = -1
var resultFpRegister = -1
val zero = codeGen.isZero(assignment.value)
@ -144,12 +144,12 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
if(ident!=null) {
val address = codeGen.allocations.get(ident.targetName)
code += if(zero) {
VmCodeInstruction(Opcode.STOREZM, vmDt, value = address)
IRCodeInstruction(Opcode.STOREZM, vmDt, value = address)
} else {
if (vmDt == VmDataType.FLOAT)
VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value = address)
IRCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value = address)
else
VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value = address)
IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value = address)
}
}
else if(array!=null) {
@ -168,9 +168,9 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
if(zero) {
// there's no STOREZIX instruction
resultRegister = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
}
code += VmCodeInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, value = variableAddr)
code += IRCodeInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, value = variableAddr)
return code
}
@ -178,30 +178,30 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
if(zero) {
if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=variableAddr)
code += IRCodeInstruction(Opcode.STOREZM, vmDt, value=variableAddr)
} else {
val indexReg = codeGen.vmRegisters.nextFree()
code += loadIndexReg(array, itemsize, indexReg, array.position)
code += VmCodeInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, value=variableAddr)
code += IRCodeInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, value=variableAddr)
}
} else {
if(vmDt== VmDataType.FLOAT) {
if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value=variableAddr)
code += IRCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value=variableAddr)
} else {
val indexReg = codeGen.vmRegisters.nextFree()
code += loadIndexReg(array, itemsize, indexReg, array.position)
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
}
} else {
if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value=variableAddr)
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value=variableAddr)
} else {
val indexReg = codeGen.vmRegisters.nextFree()
code += loadIndexReg(array, itemsize, indexReg, array.position)
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
}
}
}
@ -210,19 +210,19 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
require(vmDt== VmDataType.BYTE)
if(zero) {
if(memory.address is PtNumber) {
code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg, -1)
code += VmCodeInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
code += IRCodeInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
}
} else {
if(memory.address is PtNumber) {
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg, -1)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
code += IRCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
}
}
}
@ -231,8 +231,8 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
return code
}
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(itemsize==1) {
code += expressionEval.translateExpression(array.index, indexReg, -1)
}

View File

@ -11,7 +11,7 @@ import prog8.vm.VmDataType
internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: ExpressionGen) {
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
return when(call.name) {
"any" -> funcAny(call, resultRegister)
"all" -> funcAll(call, resultRegister)
@ -26,7 +26,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
"rsave",
"rsavex",
"rrestore",
"rrestorex" -> VmCodeChunk(call.position) // vm doesn't have registers to save/restore
"rrestorex" -> IRCodeChunk(call.position) // vm doesn't have registers to save/restore
"rnd" -> funcRnd(resultRegister, call.position)
"rndw" -> funcRndw(resultRegister, call.position)
"callfar" -> throw AssemblyError("callfar() is for cx16 target only")
@ -38,7 +38,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
"peekw" -> funcPeekW(call, resultRegister)
"poke" -> funcPoke(call)
"pokew" -> funcPokeW(call)
"pokemon" -> VmCodeChunk(call.position)
"pokemon" -> IRCodeChunk(call.position)
"mkword" -> funcMkword(call, resultRegister)
"sort" -> funcSort(call)
"reverse" -> funcReverse(call)
@ -50,20 +50,20 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
}
private fun funcCmp(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunk {
val code = IRCodeChunk(call.position)
val leftRegister = codeGen.vmRegisters.nextFree()
val rightRegister = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
code += exprGen.translateExpression(call.args[1], rightRegister, -1)
code += VmCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
code += IRCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
return code
}
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val code = VmCodeChunk(call.position)
val code = IRCodeChunk(call.position)
val syscall =
when (array.dt) {
DataType.ARRAY_UB,
@ -74,14 +74,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
else -> throw IllegalArgumentException("weird type")
}
code += exprGen.translateExpression(call.args[0], 0, -1)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value = syscall.ordinal)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
code += IRCodeInstruction(Opcode.SYSCALL, value = syscall.ordinal)
if (resultRegister != 0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
return code
}
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val syscall =
@ -93,42 +93,42 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
DataType.ARRAY_F -> Syscall.ALL_FLOAT
else -> throw IllegalArgumentException("weird type")
}
val code = VmCodeChunk(call.position)
val code = IRCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], 0, -1)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += IRCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
if(resultRegister!=0)
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
return code
}
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(call.position)
val sourceDt = call.args.single().type
if(sourceDt!=DataType.UWORD) {
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
when (sourceDt) {
DataType.UBYTE -> {
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
code += IRCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
}
DataType.BYTE -> {
val notNegativeLabel = codeGen.createLabelName()
val compareReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
code += VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
code += VmCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
code += VmCodeLabel(notNegativeLabel)
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
code += IRCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
code += IRCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
code += IRCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
code += IRCodeLabel(notNegativeLabel)
}
DataType.WORD -> {
val notNegativeLabel = codeGen.createLabelName()
val compareReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
code += VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
code += VmCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
code += VmCodeLabel(notNegativeLabel)
code += IRCodeInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
code += IRCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
code += IRCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
code += IRCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
code += IRCodeLabel(notNegativeLabel)
}
else -> throw AssemblyError("weird type")
}
@ -136,55 +136,55 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
return code
}
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
code += IRCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
return code
}
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
code += IRCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
return code
}
private fun funcPop(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk {
val code = IRCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
code += IRCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
code += assignRegisterTo(call.args.single(), reg)
return code
}
private fun funcPopw(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk {
val code = IRCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
code += IRCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
code += assignRegisterTo(call.args.single(), reg)
return code
}
private fun funcPush(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunk {
val code = IRCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
code += IRCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
return code
}
private fun funcPushw(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunk {
val code = IRCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
code += IRCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
return code
}
private fun funcReverse(call: PtBuiltinFunctionCall): VmCodeChunk {
private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
@ -194,14 +194,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
DataType.ARRAY_F -> Syscall.REVERSE_FLOATS
else -> throw IllegalArgumentException("weird type to reverse")
}
val code = VmCodeChunk(call.position)
val code = IRCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], 0, -1)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += IRCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
return code
}
private fun funcSort(call: PtBuiltinFunctionCall): VmCodeChunk {
private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val sortSyscall =
@ -214,150 +214,150 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported")
else -> throw IllegalArgumentException("weird type to sort")
}
val code = VmCodeChunk(call.position)
val code = IRCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], 0, -1)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += IRCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
return code
}
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val msbReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk(call.position)
val code = IRCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], msbReg, -1)
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
code += IRCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
return code
}
private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPokeW(call: PtBuiltinFunctionCall): IRCodeChunk {
val code = IRCodeChunk(call.position)
if(codeGen.isZero(call.args[1])) {
if (call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
code += IRCodeInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
code += IRCodeInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
}
} else {
val valueReg = codeGen.vmRegisters.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 += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
code += IRCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += exprGen.translateExpression(call.args[1], valueReg, -1)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
code += IRCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
}
}
return code
}
private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPoke(call: PtBuiltinFunctionCall): IRCodeChunk {
val code = IRCodeChunk(call.position)
if(codeGen.isZero(call.args[1])) {
if (call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
code += IRCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
code += IRCodeInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
}
} else {
val valueReg = codeGen.vmRegisters.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 += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
code += IRCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], addressReg, -1)
code += exprGen.translateExpression(call.args[1], valueReg, -1)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
code += IRCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
}
}
return code
}
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(call.position)
if(call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
code += IRCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
code += IRCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
}
return code
}
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(call.position)
if(call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
code += IRCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
} else {
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
code += IRCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
}
return code
}
private fun funcRnd(resultRegister: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
code += VmCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
code += IRCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
return code
}
private fun funcRndw(resultRegister: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
code += VmCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
code += IRCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
return code
}
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val name = (call.args[0] as PtString).value
val size = (call.args[1] as PtNumber).number.toUInt()
val align = (call.args[2] as PtNumber).number.toUInt()
val label = codeGen.addMemorySlab(name, size, align, call.position)
val code = VmCodeChunk(call.position)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = listOf(label))
val code = IRCodeChunk(call.position)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = listOf(label))
return code
}
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(call.position)
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
// 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 funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(call.position)
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(call.position)
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
code += IRCodeInstruction(Opcode.MSIG, VmDataType.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): VmCodeChunk {
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val vmDt = codeGen.vmType(call.args[0].type)
val code = VmCodeChunk(call.position)
val code = IRCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
code += IRCodeInstruction(opcode, vmDt, reg1=resultRegister)
code += assignRegisterTo(call.args[0], resultRegister)
return code
}
private fun assignRegisterTo(target: PtExpression, register: Int): VmCodeChunk {
val code = VmCodeChunk(target.position)
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunk {
val code = IRCodeChunk(target.position)
val assignment = PtAssignment(target.position)
val assignTarget = PtAssignTarget(target.position)
assignTarget.children.add(target)

View File

@ -48,12 +48,12 @@ class CodeGen(internal val program: PtProgram,
internal val vmRegisters = VmRegisterPool()
override fun compileToAssembly(): IAssemblyProgram? {
val irProg = IRProgram(program.name, options, program.encoding, symbolTable)
val irProg = IRProgram(program.name, symbolTable, options, program.encoding)
if(!options.dontReinitGlobals) {
// collect global variables initializers
program.allBlocks().forEach {
val code = VmCodeChunk(it.position)
val code = IRCodeChunk(it.position)
it.children.filterIsInstance<PtAssignment>().forEach { assign -> code += assignmentGen.translate(assign) }
irProg.addGlobalInits(code)
}
@ -64,6 +64,8 @@ class CodeGen(internal val program: PtProgram,
if(options.evalStackBaseAddress!=null)
throw AssemblyError("virtual target doesn't use eval-stack")
// TODO flatten nested subroutines
for (block in program.allBlocks()) {
irProg.addBlock(translate(block))
}
@ -74,25 +76,23 @@ class CodeGen(internal val program: PtProgram,
}
println("IR codegen: virtual registers=${vmRegisters.peekNext()}")
irProg.writeFile()
IRFileWriter(irProg).writeFile()
return DummyAssemblyProgram(irProg.name)
}
internal fun translateNode(node: PtNode): VmCodeChunk {
internal fun translateNode(node: PtNode): IRCodeChunk {
val code = when(node) {
is PtSub -> translate(node)
is PtAsmSub -> translate(node)
is PtScopeVarsDecls -> VmCodeChunk(node.position) // vars should be looked up via symbol table
is PtVariable -> VmCodeChunk(node.position) // var should be looked up via symbol table
is PtMemMapped -> VmCodeChunk(node.position) // memmapped var should be looked up via symbol table
is PtConstant -> VmCodeChunk(node.position) // constants have all been folded into the code
is PtScopeVarsDecls -> IRCodeChunk(node.position) // vars should be looked up via symbol table
is PtVariable -> IRCodeChunk(node.position) // var should be looked up via symbol table
is PtMemMapped -> IRCodeChunk(node.position) // memmapped var should be looked up via symbol table
is PtConstant -> IRCodeChunk(node.position) // constants have all been folded into the code
is PtAssignment -> assignmentGen.translate(node)
is PtNodeGroup -> translateGroup(node.children, node.position)
is PtBuiltinFunctionCall -> translateBuiltinFunc(node, 0)
is PtFunctionCall -> expressionEval.translate(node, 0, 0)
is PtNop -> VmCodeChunk(node.position)
is PtNop -> IRCodeChunk(node.position)
is PtReturn -> translate(node)
is PtJump -> translate(node)
is PtWhen -> translate(node)
@ -100,11 +100,23 @@ class CodeGen(internal val program: PtProgram,
is PtIfElse -> translate(node)
is PtPostIncrDecr -> translate(node)
is PtRepeatLoop -> translate(node)
is PtLabel -> VmCodeChunk(node.position, VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(node.position, VmCodeInstruction(Opcode.BREAKPOINT))
is PtLabel -> {
val chunk = IRCodeChunk(node.position)
chunk += IRCodeLabel(node.scopedName)
return chunk
}
is PtBreakpoint -> {
val chunk = IRCodeChunk(node.position)
chunk += IRCodeInstruction(Opcode.BREAKPOINT)
return chunk
}
is PtConditionalBranch -> translate(node)
is PtInlineAssembly -> VmInlineAsmChunk(node.assembly, node.position)
is PtIncludeBinary -> VmCodeChunk(node.position, VmCodeInlineBinary(node.file, node.offset, node.length))
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.position)
is PtIncludeBinary -> {
val chunk = IRCodeChunk(node.position)
chunk += IRCodeInlineBinary(node.file, node.offset, node.length)
return chunk
}
is PtAddressOf,
is PtContainmentCheck,
is PtMemoryByte,
@ -122,40 +134,41 @@ class CodeGen(internal val program: PtProgram,
is PtArray,
is PtBlock,
is PtString -> throw AssemblyError("should not occur as separate statement node ${node.position}")
is PtSub -> throw AssemblyError("nested subroutines should have been flattened ${node.position}")
else -> TODO("missing codegen for $node")
}
return code
}
private fun translate(branch: PtConditionalBranch): VmCodeChunk {
val code = VmCodeChunk(branch.position)
private fun translate(branch: PtConditionalBranch): IRCodeChunk {
val code = IRCodeChunk(branch.position)
val elseLabel = createLabelName()
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
code += when(branch.condition) {
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
BranchCondition.CS -> IRCodeInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
BranchCondition.CC -> IRCodeInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
BranchCondition.EQ, BranchCondition.Z -> IRCodeInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
BranchCondition.NE, BranchCondition.NZ -> IRCodeInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
BranchCondition.MI, BranchCondition.NEG -> IRCodeInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
BranchCondition.PL, BranchCondition.POS -> IRCodeInstruction(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}")
}
code += translateNode(branch.trueScope)
if(branch.falseScope.children.isNotEmpty()) {
val endLabel = createLabelName()
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
code += VmCodeLabel(elseLabel)
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
code += IRCodeLabel(elseLabel)
code += translateNode(branch.falseScope)
code += VmCodeLabel(endLabel)
code += IRCodeLabel(endLabel)
} else {
code += VmCodeLabel(elseLabel)
code += IRCodeLabel(elseLabel)
}
return code
}
private fun translate(whenStmt: PtWhen): VmCodeChunk {
val code = VmCodeChunk(whenStmt.position)
private fun translate(whenStmt: PtWhen): IRCodeChunk {
val code = IRCodeChunk(whenStmt.position)
if(whenStmt.choices.children.isEmpty())
return code
val valueReg = vmRegisters.nextFree()
@ -171,34 +184,34 @@ class CodeGen(internal val program: PtProgram,
val skipLabel = createLabelName()
val values = choice.values.children.map {it as PtNumber}
if(values.size==1) {
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
code += IRCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
code += IRCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
code += translateNode(choice.statements)
if(choice.statements.children.last() !is PtReturn)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
} else {
val matchLabel = createLabelName()
for (value in values) {
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
code += IRCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
code += IRCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
}
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = skipLabel)
code += VmCodeLabel(matchLabel)
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = skipLabel)
code += IRCodeLabel(matchLabel)
code += translateNode(choice.statements)
if(choice.statements.children.last() !is PtReturn)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
}
code += VmCodeLabel(skipLabel)
code += IRCodeLabel(skipLabel)
}
}
code += VmCodeLabel(endLabel)
code += IRCodeLabel(endLabel)
return code
}
private fun translate(forLoop: PtForLoop): VmCodeChunk {
private fun translate(forLoop: PtForLoop): IRCodeChunk {
val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable
val iterable = forLoop.iterable
val code = VmCodeChunk(forLoop.position)
val code = IRCodeChunk(forLoop.position)
when(iterable) {
is PtRange -> {
if(iterable.from is PtNumber && iterable.to is PtNumber)
@ -216,15 +229,15 @@ class CodeGen(internal val program: PtProgram,
val endLabel = createLabelName()
if(iterableVar.dt==DataType.STR) {
// iterate over a zero-terminated string
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += VmCodeLabel(loopLabel)
code += VmCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=tmpReg, reg2=indexReg, value = arrayAddress)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=tmpReg, value = loopvarAddress)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += IRCodeLabel(loopLabel)
code += IRCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=tmpReg, reg2=indexReg, value = arrayAddress)
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
code += IRCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=tmpReg, value = loopvarAddress)
code += translateNode(forLoop.statements)
code += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
code += VmCodeLabel(endLabel)
code += IRCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
code += IRCodeLabel(endLabel)
} else {
// iterate over array
val elementDt = ArrayToElementTypes.getValue(iterable.type)
@ -232,22 +245,22 @@ class CodeGen(internal val program: PtProgram,
val lengthBytes = iterableVar.length!! * elementSize
if(lengthBytes<256) {
val lengthReg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
code += VmCodeLabel(loopLabel)
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
code += IRCodeLabel(loopLabel)
code += IRCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
code += IRCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
code += translateNode(forLoop.statements)
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
code += VmCodeInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
code += IRCodeInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
} else if(lengthBytes==256) {
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += VmCodeLabel(loopLabel)
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
code += IRCodeLabel(loopLabel)
code += IRCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
code += IRCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
code += translateNode(forLoop.statements)
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
code += VmCodeInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
code += IRCodeInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
} else {
throw AssemblyError("iterator length should never exceed 256")
}
@ -258,7 +271,7 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): VmCodeChunk {
private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunk {
val iterable = forLoop.iterable as PtRange
val step = iterable.step.number.toInt()
if (step==0)
@ -268,21 +281,21 @@ class CodeGen(internal val program: PtProgram,
val loopvarAddress = allocations.get(loopvar.scopedName)
val loopvarDt = vmType(loopvar.dt)
val loopLabel = createLabelName()
val code = VmCodeChunk(forLoop.position)
val code = IRCodeChunk(forLoop.position)
code += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
code += expressionEval.translateExpression(iterable.from, indexReg, -1)
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
code += VmCodeLabel(loopLabel)
code += IRCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
code += IRCodeLabel(loopLabel)
code += translateNode(forLoop.statements)
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step, iterable.position)
code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
code += IRCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
code += IRCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
return code
}
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): VmCodeChunk {
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunk {
val loopLabel = createLabelName()
val loopvarAddress = allocations.get(loopvar.scopedName)
val indexReg = vmRegisters.nextFree()
@ -296,269 +309,269 @@ class CodeGen(internal val program: PtProgram,
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 code = VmCodeChunk(forLoop.position)
val code = IRCodeChunk(forLoop.position)
val endvalueReg: Int
if(rangeEndWrapped!=0) {
endvalueReg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
code += IRCodeInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
} else {
endvalueReg = -1 // not used
}
code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart)
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
code += VmCodeLabel(loopLabel)
code += IRCodeInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart)
code += IRCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
code += IRCodeLabel(loopLabel)
code += translateNode(forLoop.statements)
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step, iterable.position)
code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
code += IRCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
code += if(rangeEndWrapped==0) {
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
IRCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
} else {
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
IRCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
}
return code
}
private fun addConstReg(dt: VmDataType, reg: Int, value: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
private fun addConstReg(dt: VmDataType, reg: Int, value: Int, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
when(value) {
0 -> { /* do nothing */ }
1 -> {
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
code += IRCodeInstruction(Opcode.INC, dt, reg1=reg)
}
2 -> {
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
code += IRCodeInstruction(Opcode.INC, dt, reg1=reg)
code += IRCodeInstruction(Opcode.INC, dt, reg1=reg)
}
-1 -> {
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
code += IRCodeInstruction(Opcode.DEC, dt, reg1=reg)
}
-2 -> {
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
code += IRCodeInstruction(Opcode.DEC, dt, reg1=reg)
code += IRCodeInstruction(Opcode.DEC, dt, reg1=reg)
}
else -> {
code += if(value>0) {
VmCodeInstruction(Opcode.ADD, dt, reg1 = reg, value=value)
IRCodeInstruction(Opcode.ADD, dt, reg1 = reg, value=value)
} else {
VmCodeInstruction(Opcode.SUB, dt, reg1 = reg, value=-value)
IRCodeInstruction(Opcode.SUB, dt, reg1 = reg, value=-value)
}
}
}
return code
}
private fun addConstMem(dt: VmDataType, address: UInt, value: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
private fun addConstMem(dt: VmDataType, address: UInt, value: Int, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
when(value) {
0 -> { /* do nothing */ }
1 -> {
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
code += IRCodeInstruction(Opcode.INCM, dt, value=address.toInt())
}
2 -> {
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
code += IRCodeInstruction(Opcode.INCM, dt, value=address.toInt())
code += IRCodeInstruction(Opcode.INCM, dt, value=address.toInt())
}
-1 -> {
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
code += IRCodeInstruction(Opcode.DECM, dt, value=address.toInt())
}
-2 -> {
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
code += IRCodeInstruction(Opcode.DECM, dt, value=address.toInt())
code += IRCodeInstruction(Opcode.DECM, dt, value=address.toInt())
}
else -> {
val valueReg = vmRegisters.nextFree()
if(value>0) {
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value)
code += VmCodeInstruction(Opcode.ADDM, dt, reg1=valueReg, value=address.toInt())
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value)
code += IRCodeInstruction(Opcode.ADDM, dt, reg1=valueReg, value=address.toInt())
}
else {
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=-value)
code += VmCodeInstruction(Opcode.SUBM, dt, reg1=valueReg, value=address.toInt())
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=-value)
code += IRCodeInstruction(Opcode.SUBM, dt, reg1=valueReg, value=address.toInt())
}
}
}
return code
}
internal fun multiplyByConstFloat(fpReg: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun multiplyByConstFloat(fpReg: Int, factor: Float, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1f)
return code
code += if(factor==0f) {
VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
} else {
VmCodeInstruction(Opcode.MUL, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
IRCodeInstruction(Opcode.MUL, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
}
return code
}
internal fun multiplyByConstFloatInplace(address: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun multiplyByConstFloatInplace(address: Int, factor: Float, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1f)
return code
if(factor==0f) {
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = address)
code += IRCodeInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = address)
} else {
val factorReg = vmRegisters.nextFreeFloat()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
code += VmCodeInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = address)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
code += IRCodeInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = address)
}
return code
}
internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
if(pow2==1) {
// just shift 1 bit
code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg)
code += IRCodeInstruction(Opcode.LSL, dt, reg1=reg)
}
else if(pow2>=1) {
// just shift multiple bits
val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += VmCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += IRCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
} else {
code += if (factor == 0) {
VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
IRCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
} else {
VmCodeInstruction(Opcode.MUL, dt, reg1=reg, value=factor)
IRCodeInstruction(Opcode.MUL, dt, reg1=reg, value=factor)
}
}
return code
}
internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
if(pow2==1) {
// just shift 1 bit
code += VmCodeInstruction(Opcode.LSLM, dt, value = address)
code += IRCodeInstruction(Opcode.LSLM, dt, value = address)
}
else if(pow2>=1) {
// just shift multiple bits
val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += VmCodeInstruction(Opcode.LSLNM, dt, reg1=pow2reg, value=address)
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += IRCodeInstruction(Opcode.LSLNM, dt, reg1=pow2reg, value=address)
} else {
if (factor == 0) {
code += VmCodeInstruction(Opcode.STOREZM, dt, value=address)
code += IRCodeInstruction(Opcode.STOREZM, dt, value=address)
}
else {
val factorReg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor)
code += VmCodeInstruction(Opcode.MULM, dt, reg1=factorReg, value = address)
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor)
code += IRCodeInstruction(Opcode.MULM, dt, reg1=factorReg, value = address)
}
}
return code
}
internal fun divideByConstFloat(fpReg: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun divideByConstFloat(fpReg: Int, factor: Float, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1f)
return code
code += if(factor==0f) {
VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = Float.MAX_VALUE)
IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = Float.MAX_VALUE)
} else {
VmCodeInstruction(Opcode.DIVS, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
IRCodeInstruction(Opcode.DIVS, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
}
return code
}
internal fun divideByConstFloatInplace(address: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun divideByConstFloatInplace(address: Int, factor: Float, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1f)
return code
if(factor==0f) {
val maxvalueReg = vmRegisters.nextFreeFloat()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
code += VmCodeInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, value=address)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
code += IRCodeInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, value=address)
} else {
val factorReg = vmRegisters.nextFreeFloat()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
code += VmCodeInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, value=address)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
code += IRCodeInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, value=address)
}
return code
}
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
if(pow2==1 && !signed) {
code += VmCodeInstruction(Opcode.LSR, dt, reg1=reg) // simple single bit shift
code += IRCodeInstruction(Opcode.LSR, dt, reg1=reg) // simple single bit shift
}
else if(pow2>=1 &&!signed) {
// just shift multiple bits
val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += if(signed)
VmCodeInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
IRCodeInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
else
VmCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
IRCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
} else {
code += if (factor == 0) {
VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
IRCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
} else {
if(signed)
VmCodeInstruction(Opcode.DIVS, dt, reg1=reg, value=factor)
IRCodeInstruction(Opcode.DIVS, dt, reg1=reg, value=factor)
else
VmCodeInstruction(Opcode.DIV, dt, reg1=reg, value=factor)
IRCodeInstruction(Opcode.DIV, dt, reg1=reg, value=factor)
}
}
return code
}
internal fun divideByConstInplace(dt: VmDataType, address: Int, factor: Int, signed: Boolean, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
internal fun divideByConstInplace(dt: VmDataType, address: Int, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
if(pow2==1 && !signed) {
code += VmCodeInstruction(Opcode.LSRM, dt, value=address) // just simple bit shift
code += IRCodeInstruction(Opcode.LSRM, dt, value=address) // just simple bit shift
}
else if(pow2>=1 && !signed) {
// just shift multiple bits
val pow2reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
code += if(signed)
VmCodeInstruction(Opcode.ASRNM, dt, reg1=pow2reg, value=address)
IRCodeInstruction(Opcode.ASRNM, dt, reg1=pow2reg, value=address)
else
VmCodeInstruction(Opcode.LSRNM, dt, reg1=pow2reg, value=address)
IRCodeInstruction(Opcode.LSRNM, dt, reg1=pow2reg, value=address)
} else {
if (factor == 0) {
val reg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
code += IRCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
}
else {
val factorReg = vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
code += IRCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
code += if(signed)
VmCodeInstruction(Opcode.DIVSM, dt, reg1=factorReg, value=address)
IRCodeInstruction(Opcode.DIVSM, dt, reg1=factorReg, value=address)
else
VmCodeInstruction(Opcode.DIVM, dt, reg1=factorReg, value=address)
IRCodeInstruction(Opcode.DIVM, dt, reg1=factorReg, value=address)
}
}
return code
}
private fun translate(ifElse: PtIfElse): VmCodeChunk {
private fun translate(ifElse: PtIfElse): IRCodeChunk {
if(ifElse.condition.operator !in ComparisonOperators)
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 code = VmCodeChunk(ifElse.position)
val code = IRCodeChunk(ifElse.position)
fun translateNonZeroComparison(): VmCodeChunk {
fun translateNonZeroComparison(): IRCodeChunk {
val elseBranch = when(ifElse.condition.operator) {
"==" -> Opcode.BNE
"!=" -> Opcode.BEQ
@ -577,42 +590,42 @@ class CodeGen(internal val program: PtProgram,
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
code += VmCodeLabel(elseLabel)
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
code += IRCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope)
code += VmCodeLabel(afterIfLabel)
code += IRCodeLabel(afterIfLabel)
} else {
// only if part
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
code += IRCodeLabel(afterIfLabel)
}
return code
}
fun translateZeroComparison(): VmCodeChunk {
fun equalOrNotEqualZero(elseBranch: Opcode): VmCodeChunk {
fun translateZeroComparison(): IRCodeChunk {
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunk {
val leftReg = vmRegisters.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 += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
code += VmCodeLabel(elseLabel)
code += IRCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
code += IRCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope)
code += VmCodeLabel(afterIfLabel)
code += IRCodeLabel(afterIfLabel)
} else {
// only if part
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
code += IRCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
code += IRCodeLabel(afterIfLabel)
}
return code
}
@ -640,8 +653,8 @@ class CodeGen(internal val program: PtProgram,
}
private fun translate(postIncrDecr: PtPostIncrDecr): VmCodeChunk {
val code = VmCodeChunk(postIncrDecr.position)
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk {
val code = IRCodeChunk(postIncrDecr.position)
val operationMem: Opcode
val operationRegister: Opcode
when(postIncrDecr.operator) {
@ -661,18 +674,18 @@ class CodeGen(internal val program: PtProgram,
val vmDt = vmType(postIncrDecr.target.type)
if(ident!=null) {
val address = allocations.get(ident.targetName)
code += VmCodeInstruction(operationMem, vmDt, value = address)
code += IRCodeInstruction(operationMem, vmDt, value = address)
} else if(memory!=null) {
if(memory.address is PtNumber) {
val address = (memory.address as PtNumber).number.toInt()
code += VmCodeInstruction(operationMem, vmDt, value = address)
code += IRCodeInstruction(operationMem, vmDt, value = address)
} else {
val incReg = vmRegisters.nextFree()
val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg, -1)
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1 = incReg, reg2 = addressReg)
code += VmCodeInstruction(operationRegister, vmDt, reg1 = incReg)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1 = incReg, reg2 = addressReg)
code += IRCodeInstruction(Opcode.LOADI, vmDt, reg1 = incReg, reg2 = addressReg)
code += IRCodeInstruction(operationRegister, vmDt, reg1 = incReg)
code += IRCodeInstruction(Opcode.STOREI, vmDt, reg1 = incReg, reg2 = addressReg)
}
} else if (array!=null) {
val variable = array.variable.targetName
@ -681,14 +694,14 @@ class CodeGen(internal val program: PtProgram,
val fixedIndex = constIntValue(array.index)
if(fixedIndex!=null) {
variableAddr += fixedIndex*itemsize
code += VmCodeInstruction(operationMem, vmDt, value=variableAddr)
code += IRCodeInstruction(operationMem, vmDt, value=variableAddr)
} else {
val incReg = vmRegisters.nextFree()
val indexReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(array.index, indexReg, -1)
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=incReg, reg2=indexReg, value=variableAddr)
code += VmCodeInstruction(operationRegister, vmDt, reg1=incReg)
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1=incReg, reg2=indexReg, value=variableAddr)
code += IRCodeInstruction(Opcode.LOADX, vmDt, reg1=incReg, reg2=indexReg, value=variableAddr)
code += IRCodeInstruction(operationRegister, vmDt, reg1=incReg)
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1=incReg, reg2=indexReg, value=variableAddr)
}
} else
throw AssemblyError("weird assigntarget")
@ -696,9 +709,9 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun translate(repeat: PtRepeatLoop): VmCodeChunk {
private fun translate(repeat: PtRepeatLoop): IRCodeChunk {
when (constIntValue(repeat.count)) {
0 -> return VmCodeChunk(repeat.position)
0 -> return IRCodeChunk(repeat.position)
1 -> return translateGroup(repeat.children, repeat.position)
256 -> {
// 256 iterations can still be done with just a byte counter if you set it to zero as starting value.
@ -706,39 +719,39 @@ class CodeGen(internal val program: PtProgram,
}
}
val code = VmCodeChunk(repeat.position)
val code = IRCodeChunk(repeat.position)
val counterReg = vmRegisters.nextFree()
val vmDt = vmType(repeat.count.type)
code += expressionEval.translateExpression(repeat.count, counterReg, -1)
val repeatLabel = createLabelName()
code += VmCodeLabel(repeatLabel)
code += IRCodeLabel(repeatLabel)
code += translateNode(repeat.statements)
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
code += IRCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
code += IRCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
return code
}
private fun translate(jump: PtJump): VmCodeChunk {
val code = VmCodeChunk(jump.position)
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)
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf(jump.generatedLabel!!))
IRCodeInstruction(Opcode.JUMP, labelSymbol = listOf(jump.generatedLabel!!))
else if(jump.identifier!=null)
VmCodeInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName)
IRCodeInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName)
else
throw AssemblyError("weird jump")
return code
}
private fun translateGroup(group: List<PtNode>, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
private fun translateGroup(group: List<PtNode>, position: Position): IRCodeChunk {
val code = IRCodeChunk(position)
group.forEach { code += translateNode(it) }
return code
}
private fun translate(ret: PtReturn): VmCodeChunk {
val code = VmCodeChunk(ret.position)
private fun translate(ret: PtReturn): IRCodeChunk {
val code = IRCodeChunk(ret.position)
val value = ret.value
if(value!=null) {
// Call Convention: return value is always returned in r0 (or fr0 if float)
@ -747,42 +760,32 @@ class CodeGen(internal val program: PtProgram,
else
expressionEval.translateExpression(value, 0, -1)
}
code += VmCodeInstruction(Opcode.RETURN)
code += IRCodeInstruction(Opcode.RETURN)
return code
}
private fun translate(sub: PtSub): VmSubroutine {
val vmsub = VmSubroutine(sub.scopedName, sub.returntype, sub.position)
vmsub += VmCodeLabel(sub.scopedName)
for (child in sub.children) {
vmsub += translateNode(child)
}
return vmsub
}
private fun translate(sub: PtAsmSub): VmAsmSubroutine {
val vmsub = VmAsmSubroutine(sub.scopedName, sub.position)
vmsub += VmCodeLabel(sub.scopedName)
for (child in sub.children) {
vmsub += translateNode(child)
}
return vmsub
}
private fun translate(block: PtBlock): VmBlock {
val vmblock = VmBlock(block.name, block.address, block.alignment, block.position) // no use for other attributes yet?
private fun translate(block: PtBlock): IRBlock {
val vmblock = IRBlock(block.name, block.address, 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 -> vmblock += translateNode(child)
is PtAsmSub -> vmblock += translateNode(child)
is PtInlineAssembly -> vmblock += translateNode(child)
else -> {
println("BLOCK: TRANSLATING WEIRD THING $child")
vmblock += translateNode(child)
is PtSub -> {
val vmsub = IRSubroutine(child.scopedName, child.returntype, child.position)
for (child in child.children) {
vmsub += translateNode(child)
}
vmblock += vmsub
}
is PtAsmSub -> {
val assembly = if(child.children.isEmpty()) "" else (child.children.single() as PtInlineAssembly).assembly
vmblock += IRAsmSubroutine(child.scopedName, child.position, child.address, assembly)
}
is PtInlineAssembly -> {
vmblock += IRInlineAsmChunk(child.assembly, child.position)
}
else -> TODO("BLOCK HAS WEIRD CHILD NODE $child")
}
}
return vmblock
@ -808,7 +811,7 @@ class CodeGen(internal val program: PtProgram,
return listOf("prog8_label_gen_$labelSequenceNumber")
}
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk =
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk =
builtinFuncGen.translate(call, resultRegister)
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0

View File

@ -10,51 +10,51 @@ import prog8.vm.VmDataType
internal class ExpressionGen(private val codeGen: CodeGen) {
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
require(codeGen.vmRegisters.peekNext() > resultRegister)
val code = VmCodeChunk(expr.position)
val code = IRCodeChunk(expr.position)
when (expr) {
is PtMachineRegister -> {
if(resultRegister!=expr.register) {
val vmDt = codeGen.vmType(expr.type)
code += VmCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
code += IRCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
}
}
is PtNumber -> {
val vmDt = codeGen.vmType(expr.type)
code += if(vmDt==VmDataType.FLOAT)
VmCodeInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, fpValue = expr.number.toFloat())
IRCodeInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, fpValue = expr.number.toFloat())
else
VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
}
is PtIdentifier -> {
val vmDt = codeGen.vmType(expr.type)
val mem = codeGen.allocations.get(expr.targetName)
code += if (expr.type in PassByValueDatatypes) {
if(vmDt==VmDataType.FLOAT)
VmCodeInstruction(Opcode.LOADM, vmDt, fpReg1 = resultFpRegister, value = mem)
IRCodeInstruction(Opcode.LOADM, vmDt, fpReg1 = resultFpRegister, value = mem)
else
VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem)
IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem)
} else {
// for strings and arrays etc., load the *address* of the value instead
VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem)
IRCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem)
}
}
is PtAddressOf -> {
val vmDt = codeGen.vmType(expr.type)
val mem = codeGen.allocations.get(expr.identifier.targetName)
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem)
}
is PtMemoryByte -> {
if(expr.address is PtNumber) {
val address = (expr.address as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
code += IRCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
} else {
val addressRegister = codeGen.vmRegisters.nextFree()
code += translateExpression(expr.address, addressRegister, -1)
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
code += IRCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
}
}
is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister)
@ -72,8 +72,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
return code
}
private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk(check.position)
private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
val code = IRCodeChunk(check.position)
code += translateExpression(check.element, resultRegister, -1) // load the element to check in resultRegister
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
when(iterable.dt) {
@ -103,10 +103,10 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
return code
}
private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
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 code = VmCodeChunk(arrayIx.position)
val code = IRCodeChunk(arrayIx.position)
val idxReg = codeGen.vmRegisters.nextFree()
val arrayLocation = codeGen.allocations.get(arrayIx.variable.targetName)
@ -117,7 +117,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
if(arrayIx.index.type!=DataType.UBYTE)
throw AssemblyError("non-array var indexing requires bytes index")
code += translateExpression(arrayIx.index, idxReg, -1)
code += VmCodeInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
code += IRCodeInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
return code
}
@ -125,41 +125,41 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
// optimized code when index is known - just calculate the memory address here
val memOffset = (arrayIx.index as PtNumber).number.toInt() * eltSize
if(vmDt==VmDataType.FLOAT)
code += VmCodeInstruction(Opcode.LOADM, VmDataType.FLOAT, fpReg1=resultFpRegister, value=arrayLocation+memOffset)
code += IRCodeInstruction(Opcode.LOADM, VmDataType.FLOAT, fpReg1=resultFpRegister, value=arrayLocation+memOffset)
else
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=arrayLocation+memOffset)
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=arrayLocation+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 += VmCodeInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, value = arrayLocation)
code += IRCodeInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, value = arrayLocation)
else
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
code += IRCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation)
}
return code
}
private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(expr.position)
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)
when(expr.operator) {
"+" -> { }
"-" -> {
code += VmCodeInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
code += IRCodeInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
}
"~" -> {
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, value=mask)
code += IRCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, value=mask)
}
else -> throw AssemblyError("weird prefix operator")
}
return code
}
private fun translate(cast: PtTypeCast, predefinedResultRegister: Int, predefinedResultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk(cast.position)
private fun translate(cast: PtTypeCast, predefinedResultRegister: Int, predefinedResultFpRegister: Int): IRCodeChunk {
val code = IRCodeChunk(cast.position)
if(cast.type==cast.value.type)
return code
val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.vmRegisters.nextFreeFloat()
@ -174,14 +174,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
DataType.UBYTE -> {
when(cast.value.type) {
DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
DataType.FLOAT -> code += VmCodeInstruction(Opcode.FTOUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
DataType.FLOAT -> code += IRCodeInstruction(Opcode.FTOUB, VmDataType.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 += VmCodeInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
DataType.FLOAT -> code += IRCodeInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
else -> throw AssemblyError("weird cast value type")
}
}
@ -189,15 +189,15 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
when(cast.value.type) {
DataType.BYTE -> {
// byte -> uword: sign extend
code += VmCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
code += IRCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
}
DataType.UBYTE -> {
// ubyte -> uword: sign extend
code += VmCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
code += IRCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
}
DataType.WORD -> { }
DataType.FLOAT -> {
code += VmCodeInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
code += IRCodeInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
}
else -> throw AssemblyError("weird cast value type")
}
@ -206,15 +206,15 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
when(cast.value.type) {
DataType.BYTE -> {
// byte -> word: sign extend
code += VmCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
code += IRCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
}
DataType.UBYTE -> {
// byte -> word: sign extend
code += VmCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
code += IRCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
}
DataType.UWORD -> { }
DataType.FLOAT -> {
code += VmCodeInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
code += IRCodeInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
}
else -> throw AssemblyError("weird cast value type")
}
@ -222,16 +222,16 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
DataType.FLOAT -> {
code += when(cast.value.type) {
DataType.UBYTE -> {
VmCodeInstruction(Opcode.FFROMUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
IRCodeInstruction(Opcode.FFROMUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
}
DataType.BYTE -> {
VmCodeInstruction(Opcode.FFROMSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
IRCodeInstruction(Opcode.FFROMSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
}
DataType.UWORD -> {
VmCodeInstruction(Opcode.FFROMUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
IRCodeInstruction(Opcode.FFROMUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
}
DataType.WORD -> {
VmCodeInstruction(Opcode.FFROMSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
IRCodeInstruction(Opcode.FFROMSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
}
else -> throw AssemblyError("weird cast value type")
}
@ -241,7 +241,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
return code
}
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
val vmDt = codeGen.vmType(binExpr.left.type)
val signed = binExpr.left.type in SignedDatatypes
return when(binExpr.operator) {
@ -271,22 +271,22 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
resultRegister: Int,
signed: Boolean,
greaterEquals: Boolean
): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
): 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()
code += translateExpression(binExpr.left, -1, leftFpReg)
code += translateExpression(binExpr.right, -1, rightFpReg)
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.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 += VmCodeInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
code += IRCodeInstruction(ins, VmDataType.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)
@ -294,11 +294,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
comparisonCall.children.add(binExpr.right)
code += translate(comparisonCall, resultRegister, -1)
val zeroRegister = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
code += if(greaterEquals)
VmCodeInstruction(Opcode.SGES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
IRCodeInstruction(Opcode.SGES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
else
VmCodeInstruction(Opcode.SGTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
IRCodeInstruction(Opcode.SGTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
@ -308,7 +308,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} else {
if (greaterEquals) Opcode.SGE else Opcode.SGT
}
code += VmCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
}
return code
@ -320,22 +320,22 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
resultRegister: Int,
signed: Boolean,
lessEquals: Boolean
): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
): 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()
code += translateExpression(binExpr.left, -1, leftFpReg)
code += translateExpression(binExpr.right, -1, rightFpReg)
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.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 += VmCodeInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
code += IRCodeInstruction(ins, VmDataType.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)
@ -343,11 +343,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
comparisonCall.children.add(binExpr.right)
code += translate(comparisonCall, resultRegister, -1)
val zeroRegister = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
code += if(lessEquals)
VmCodeInstruction(Opcode.SLES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
IRCodeInstruction(Opcode.SLES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
else
VmCodeInstruction(Opcode.SLTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
IRCodeInstruction(Opcode.SLTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
@ -357,29 +357,29 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} else {
if (lessEquals) Opcode.SLE else Opcode.SLT
}
code += VmCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
}
return code
}
private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, notEquals: Boolean): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, notEquals: Boolean): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, leftFpReg)
code += translateExpression(binExpr.right, -1, rightFpReg)
if (notEquals) {
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
} else {
val label = codeGen.createLabelName()
val valueReg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
code += VmCodeLabel(label)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
code += IRCodeLabel(label)
}
} else {
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
@ -388,153 +388,153 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
comparisonCall.children.add(binExpr.right)
code += translate(comparisonCall, resultRegister, -1)
if(!notEquals)
code += VmCodeInstruction(Opcode.INV, vmDt, reg1=resultRegister)
code += VmCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
code += IRCodeInstruction(Opcode.INV, vmDt, reg1=resultRegister)
code += IRCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
val opcode = if (notEquals) Opcode.SNE else Opcode.SEQ
code += VmCodeInstruction(opcode, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(opcode, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
}
return code
}
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, 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 += VmCodeInstruction(opc, vmDt, reg1 = resultRegister)
code += IRCodeInstruction(opc, vmDt, reg1 = resultRegister)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
val opc = if (signed) Opcode.ASRN else Opcode.LSRN
code += VmCodeInstruction(opc, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(opc, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
return code
}
internal fun operatorShiftRightInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorShiftRightInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
if(codeGen.isOne(operand)) {
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
code += VmCodeInstruction(opc, vmDt, value=address)
code += IRCodeInstruction(opc, vmDt, value=address)
} else {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
code += VmCodeInstruction(opc, vmDt, reg1 = operandReg, value=address)
code += IRCodeInstruction(opc, vmDt, reg1 = operandReg, value=address)
}
return code
}
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
if(codeGen.isOne(binExpr.right)){
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister)
code += IRCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg)
code += IRCodeInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg)
}
return code
}
internal fun operatorShiftLeftInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorShiftLeftInplace(address: Int, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
if(codeGen.isOne(operand)){
code += VmCodeInstruction(Opcode.LSLM, vmDt, value=address)
code += IRCodeInstruction(Opcode.LSLM, vmDt, value=address)
} else {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, value=address)
code += IRCodeInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, value=address)
}
return code
}
private fun operatorXor(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorXor(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
return code
}
internal fun operatorXorInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorXorInplace(address: Int, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = address)
code += IRCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = address)
return code
}
private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
return code
}
internal fun operatorAndInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorAndInplace(address: Int, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=address)
code += IRCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=address)
return code
}
private fun operatorOr(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorOr(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
return code
}
internal fun operatorOrInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorOrInplace(address: Int, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = address)
code += IRCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = address)
return code
}
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
if(vmDt==VmDataType.FLOAT)
throw IllegalArgumentException("floating-point modulo not supported")
val code = VmCodeChunk(binExpr.position)
val code = IRCodeChunk(binExpr.position)
val rightResultReg = codeGen.vmRegisters.nextFree()
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
} else {
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.MODR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(Opcode.MODR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
return code
}
@ -543,8 +543,8 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
vmDt: VmDataType,
resultRegister: Int,
resultFpRegister: Int,
signed: Boolean): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
signed: Boolean): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
val constFactorRight = binExpr.right as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
@ -556,9 +556,9 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += translateExpression(binExpr.right, -1, rightResultFpReg)
code += if(signed)
VmCodeInstruction(Opcode.DIVSR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
IRCodeInstruction(Opcode.DIVSR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
else
VmCodeInstruction(Opcode.DIVR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
IRCodeInstruction(Opcode.DIVR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
}
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
@ -570,24 +570,24 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += if (signed)
VmCodeInstruction(Opcode.DIVS, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
IRCodeInstruction(Opcode.DIVS, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
else
VmCodeInstruction(Opcode.DIV, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
IRCodeInstruction(Opcode.DIV, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
} else {
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += if (signed)
VmCodeInstruction(Opcode.DIVSR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
IRCodeInstruction(Opcode.DIVSR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
else
VmCodeInstruction(Opcode.DIVR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
IRCodeInstruction(Opcode.DIVR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
}
}
return code
}
internal fun operatorDivideInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorDivideInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
val constFactorRight = operand as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
@ -597,9 +597,9 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(operand, -1, operandFpReg)
code += if(signed)
VmCodeInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, value=address)
IRCodeInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, value=address)
else
VmCodeInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, value=address)
IRCodeInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, value=address)
}
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
@ -609,16 +609,16 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += if(signed)
VmCodeInstruction(Opcode.DIVSM, vmDt, reg1=operandReg, value = address)
IRCodeInstruction(Opcode.DIVSM, vmDt, reg1=operandReg, value = address)
else
VmCodeInstruction(Opcode.DIVM, vmDt, reg1=operandReg, value = address)
IRCodeInstruction(Opcode.DIVM, vmDt, reg1=operandReg, value = address)
}
}
return code
}
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, 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) {
@ -634,7 +634,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += translateExpression(binExpr.right, -1, rightResultFpReg)
code += VmCodeInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
code += IRCodeInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
}
} else {
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
@ -649,14 +649,14 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
}
return code
}
internal fun operatorMultiplyInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorMultiplyInplace(address: Int, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
val constFactorRight = operand as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorRight!=null) {
@ -665,7 +665,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} else {
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(operand, -1, operandFpReg)
code += VmCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = address)
code += IRCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = address)
}
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
@ -674,182 +674,182 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} else {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = address)
code += IRCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = address)
}
}
return code
}
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
if((binExpr.right as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += VmCodeInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister)
code += IRCodeInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister)
}
else {
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += VmCodeInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
code += IRCodeInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
} else {
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += translateExpression(binExpr.right, -1, rightResultFpReg)
code += VmCodeInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
code += IRCodeInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
}
}
} else {
if((binExpr.right as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
code += IRCodeInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
}
else {
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt())
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
}
}
return code
}
internal fun operatorMinusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorMinusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
if(vmDt==VmDataType.FLOAT) {
if((operand as? PtNumber)?.number==1.0) {
code += VmCodeInstruction(Opcode.DECM, vmDt, value=address)
code += IRCodeInstruction(Opcode.DECM, vmDt, value=address)
}
else {
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(operand, -1, operandFpReg)
code += VmCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=address)
code += IRCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=address)
}
} else {
if((operand as? PtNumber)?.number==1.0) {
code += VmCodeInstruction(Opcode.DECM, vmDt, value=address)
code += IRCodeInstruction(Opcode.DECM, vmDt, value=address)
}
else {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = address)
code += IRCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = address)
}
}
return code
}
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk(binExpr.position)
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
val code = IRCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
if((binExpr.left as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.right, -1, resultFpRegister)
code += VmCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
code += IRCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
}
else if((binExpr.right as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += VmCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
code += IRCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
}
else {
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += VmCodeInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
code += IRCodeInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
} else {
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, resultFpRegister)
code += translateExpression(binExpr.right, -1, rightResultFpReg)
code += VmCodeInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
code += IRCodeInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
}
}
} else {
if((binExpr.left as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.right, resultRegister, -1)
code += VmCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
code += IRCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
}
else if((binExpr.right as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
code += IRCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
}
else {
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
code += IRCodeInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
code += translateExpression(binExpr.right, rightResultReg, -1)
code += VmCodeInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
code += IRCodeInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
}
}
}
return code
}
internal fun operatorPlusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk(operand.position)
internal fun operatorPlusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
val code = IRCodeChunk(operand.position)
if(vmDt==VmDataType.FLOAT) {
if((operand as? PtNumber)?.number==1.0) {
code += VmCodeInstruction(Opcode.INCM, vmDt, value = address)
code += IRCodeInstruction(Opcode.INCM, vmDt, value = address)
}
else {
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(operand, -1, operandFpReg)
code += VmCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value=address)
code += IRCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value=address)
}
} else {
if((operand as? PtNumber)?.number==1.0) {
code += VmCodeInstruction(Opcode.INCM, vmDt, value = address)
code += IRCodeInstruction(Opcode.INCM, vmDt, value = address)
}
else {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=address)
code += IRCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=address)
}
}
return code
}
fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.functionName)) {
is StSub -> {
val code = VmCodeChunk(fcall.position)
val code = IRCodeChunk(fcall.position)
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
val paramDt = codeGen.vmType(parameter.type)
if(codeGen.isZero(arg)) {
if (paramDt == VmDataType.FLOAT) {
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
code += IRCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
} else {
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
code += IRCodeInstruction(Opcode.STOREZM, paramDt, value = mem)
}
} else {
if (paramDt == VmDataType.FLOAT) {
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(arg, -1, argFpReg)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, value = mem)
code += IRCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, value = mem)
} else {
val argReg = codeGen.vmRegisters.nextFree()
code += translateExpression(arg, argReg, -1)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
code += VmCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, value = mem)
code += IRCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, value = mem)
}
}
}
code += VmCodeInstruction(Opcode.CALL, labelSymbol=fcall.functionName)
code += IRCodeInstruction(Opcode.CALL, labelSymbol=fcall.functionName)
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 += VmCodeInstruction(Opcode.LOADR, VmDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0)
code += IRCodeInstruction(Opcode.LOADR, VmDataType.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 += VmCodeInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1 = resultRegister, reg2 = 0)
code += IRCodeInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1 = resultRegister, reg2 = 0)
}
}
return code

View File

@ -0,0 +1,143 @@
package prog8.codegen.experimental
import prog8.code.core.*
import java.io.BufferedWriter
import kotlin.io.path.bufferedWriter
import kotlin.io.path.div
class IRFileWriter(private val irProgram: IRProgram) {
private val outfile = irProgram.options.outputDir / ("${irProgram.name}.p8ir")
private val out = outfile.bufferedWriter()
fun writeFile() {
println("Writing intermediate representation to $outfile")
out.write("<PROGRAM NAME=${irProgram.name}>\n")
writeOptions()
writeVariableAllocations()
if(!irProgram.options.dontReinitGlobals) {
// note: this a block of code that loads values and stores them into the global variables to reset their values.
out.write("\n<INITGLOBALS>\n")
irProgram.globalInits.forEach { out.writeLine(it) }
out.write("</INITGLOBALS>\n")
}
writeBlocks()
out.write("</PROGRAM>\n")
out.close()
}
private fun writeBlocks() {
irProgram.blocks.forEach { block ->
out.write("\n<BLOCK NAME=${block.name} ADDRESS=${block.address} ALIGN=${block.alignment} POS=${block.position}>\n")
block.inlineAssembly.forEach {
out.write("<INLINEASM POS=${it.position}>\n")
out.write(it.asm)
if(!it.asm.endsWith('\n'))
out.write("\n")
out.write("</INLINEASM>\n")
}
block.subroutines.forEach {
out.write("<SUB SCOPEDNAME=${it.scopedName.joinToString(".")} RETURNTYPE=${it.returnType} POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</SUB>\n")
}
block.asmSubroutines.forEach {
out.write("<ASMSUB SCOPEDNAME=${it.scopedName.joinToString(".")} ADDRESS=${it.address} POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</ASMSUB>\n")
}
out.write("</BLOCK>\n")
}
}
private fun writeOptions() {
out.write("<OPTIONS>\n")
out.write("compTarget = ${irProgram.options.compTarget.name}\n")
out.write("output = ${irProgram.options.output}\n")
out.write("launcher = ${irProgram.options.launcher}\n")
out.write("zeropage = ${irProgram.options.zeropage}\n")
out.write("zpReserved = ${irProgram.options.zpReserved}\n")
out.write("loadAddress = ${irProgram.options.loadAddress}\n")
out.write("dontReinitGlobals = ${irProgram.options.dontReinitGlobals}\n")
out.write("evalStackBaseAddress = ${irProgram.options.evalStackBaseAddress}\n")
// other options not yet useful here?
out.write("</OPTIONS>\n")
}
private fun writeVariableAllocations() {
out.write("\n<VARIABLES>\n")
for (variable in irProgram.st.allVariables) {
val typeStr = when(variable.dt) {
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
DataType.BYTE, DataType.ARRAY_B -> "byte"
DataType.UWORD, DataType.ARRAY_UW -> "uword"
DataType.WORD, DataType.ARRAY_W -> "word"
DataType.FLOAT, DataType.ARRAY_F -> "float"
else -> throw InternalCompilerException("weird dt")
}
val value = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toHex() }
}
DataType.ARRAY_F -> {
if(variable.onetimeInitializationArrayValue!=null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
} else {
(1..variable.length!!).joinToString(",") { "0" }
}
}
in ArrayDatatypes -> {
if(variable.onetimeInitializationArrayValue!==null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toHex() }
} else {
(1..variable.length!!).joinToString(",") { "0" }
}
}
else -> throw InternalCompilerException("weird dt")
}
// TODO have uninitialized variables? (BSS SECTION)
out.write("VAR ${variable.scopedName.joinToString(".")} $typeStr = $value\n")
}
out.write("</VARIABLES>\n")
out.write("\n<MEMORYMAPPEDVARIABLES>\n")
for (variable in irProgram.st.allMemMappedVariables) {
val typeStr = when(variable.dt) {
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
DataType.BYTE, DataType.ARRAY_B -> "byte"
DataType.UWORD, DataType.ARRAY_UW -> "uword"
DataType.WORD, DataType.ARRAY_W -> "word"
DataType.FLOAT, DataType.ARRAY_F -> "float"
else -> throw InternalCompilerException("weird dt")
}
out.write("MAP ${variable.scopedName.joinToString(".")} $typeStr ${variable.address}\n")
}
out.write("</MEMORYMAPPEDVARIABLES>\n")
out.write("\n<MEMORYSLABS>\n")
irProgram.st.allMemorySlabs.forEach{ slab -> out.write("SLAB _${slab.name} ${slab.size} ${slab.align}\n") }
out.write("</MEMORYSLABS>\n")
}
private fun BufferedWriter.writeLine(line: IRCodeLine) {
when(line) {
is IRCodeComment -> write("; ${line.comment}\n")
is IRCodeInstruction -> {
write(line.ins.toString() + "\n")
}
is IRCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
is IRCodeInlineBinary -> {
write("incbin \"${line.file}\"")
if(line.offset!=null)
write(",${line.offset}")
if(line.length!=null)
write(",${line.length}")
write("\n")
}
else -> throw AssemblyError("invalid vm code line")
}
}
}

View File

@ -8,44 +8,52 @@ import prog8.vm.VmDataType
class IRPeepholeOptimizer(private val vmprog: IRProgram) {
fun optimize() {
vmprog.blocks.forEach { block ->
block.children.forEach { child ->
when(child) {
is VmCodeChunk -> {
do {
val indexedInstructions = child.lines.withIndex()
.filter { it.value is VmCodeInstruction }
.map { IndexedValue(it.index, (it.value as VmCodeInstruction).ins) }
val changed = removeNops(child, indexedInstructions)
|| removeDoubleLoadsAndStores(child, indexedInstructions) // TODO not yet implemented
|| removeUselessArithmetic(child, indexedInstructions)
|| removeWeirdBranches(child, indexedInstructions)
|| removeDoubleSecClc(child, indexedInstructions)
|| cleanupPushPop(child, indexedInstructions)
// TODO other optimizations:
// more complex optimizations such as unused registers
} while (changed)
}
else -> {
TODO("block child $child")
block.subroutines.forEach { sub ->
/*
sub.forEach { child ->
when (child) {
is IRCodeChunk -> {
do {
val indexedInstructions = child.lines.withIndex()
.filter { it.value is IRCodeInstruction }
.map { IndexedValue(it.index, (it.value as IRCodeInstruction).ins) }
val changed = removeNops(child, indexedInstructions)
|| removeDoubleLoadsAndStores(
child,
indexedInstructions
) // TODO not yet implemented
|| removeUselessArithmetic(child, indexedInstructions)
|| removeWeirdBranches(child, indexedInstructions)
|| removeDoubleSecClc(child, indexedInstructions)
|| cleanupPushPop(child, indexedInstructions)
// TODO other optimizations:
// more complex optimizations such as unused registers
} while (changed)
}
else -> {
TODO("block child $child")
}
}
}
*/
}
}
}
private fun cleanupPushPop(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// push followed by pop to same target, or different target->replace with load
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode==Opcode.PUSH) {
if(idx < chunk.lines.size-1) {
val insAfter = chunk.lines[idx+1] as? VmCodeInstruction
val insAfter = chunk.lines[idx+1] as? IRCodeInstruction
if(insAfter!=null && insAfter.ins.opcode ==Opcode.POP) {
if(ins.reg1==insAfter.ins.reg1) {
chunk.lines.removeAt(idx)
chunk.lines.removeAt(idx)
} else {
chunk.lines[idx] = VmCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1)
chunk.lines[idx] = IRCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1)
chunk.lines.removeAt(idx+1)
}
changed = true
@ -56,14 +64,14 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeDoubleSecClc(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeDoubleSecClc(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// double sec, clc
// sec+clc or clc+sec
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode==Opcode.SEC || ins.opcode==Opcode.CLC) {
if(idx < chunk.lines.size-1) {
val insAfter = chunk.lines[idx+1] as? VmCodeInstruction
val insAfter = chunk.lines[idx+1] as? IRCodeInstruction
if(insAfter?.ins?.opcode == ins.opcode) {
chunk.lines.removeAt(idx)
changed = true
@ -82,14 +90,14 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeWeirdBranches(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeWeirdBranches(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// jump/branch to label immediately below
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode==Opcode.JUMP && ins.labelSymbol!=null) {
// if jumping to label immediately following this
if(idx < chunk.lines.size-1) {
val label = chunk.lines[idx+1] as? VmCodeLabel
val label = chunk.lines[idx+1] as? IRCodeLabel
if(label?.name == ins.labelSymbol) {
chunk.lines.removeAt(idx)
changed = true
@ -100,7 +108,7 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeUselessArithmetic(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
@ -113,7 +121,7 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
}
Opcode.ADD, Opcode.SUB -> {
if (ins.value == 1) {
chunk.lines[idx] = VmCodeInstruction(
chunk.lines[idx] = IRCodeInstruction(
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
ins.type,
ins.reg1
@ -126,7 +134,7 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
}
Opcode.AND -> {
if (ins.value == 0) {
chunk.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
chunk.lines[idx] = IRCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
changed = true
} else if (ins.value == 255 && ins.type == VmDataType.BYTE) {
chunk.lines.removeAt(idx)
@ -141,7 +149,7 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
chunk.lines.removeAt(idx)
changed = true
} else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) {
chunk.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
chunk.lines[idx] = IRCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
changed = true
}
}
@ -157,7 +165,7 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeNops(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeNops(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if (ins.opcode == Opcode.NOP) {
@ -168,7 +176,7 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeDoubleLoadsAndStores(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeDoubleLoadsAndStores(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
var changed = false
indexedInstructions.forEach { (idx, ins) ->
@ -186,10 +194,10 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
}
private interface ICodeChange { // TODO not used? remove?
fun perform(block: VmCodeChunk)
fun perform(block: IRCodeChunk)
class Remove(val idx: Int): ICodeChange {
override fun perform(block: VmCodeChunk) {
override fun perform(block: IRCodeChunk) {
block.lines.removeAt(idx)
}
}

View File

@ -2,184 +2,72 @@ package prog8.codegen.experimental
import prog8.code.SymbolTable
import prog8.code.ast.PtBlock
import prog8.code.core.*
import prog8.code.core.CompilationOptions
import prog8.code.core.DataType
import prog8.code.core.IStringEncoding
import prog8.code.core.Position
import prog8.vm.Instruction
import prog8.vm.Opcode
import prog8.vm.OpcodesWithAddress
import prog8.vm.VmDataType
import java.io.BufferedWriter
import java.io.Writer
import java.nio.file.Path
import kotlin.io.path.bufferedWriter
import kotlin.io.path.div
// TODO: move this Intermedate Representation into the actual compiler core, code gen modules can receive it as input rather than an Ast.
class IRProgram(val name: String,
private val options: CompilationOptions,
private val encoding: IStringEncoding,
private val st: SymbolTable) {
val st: SymbolTable,
val options: CompilationOptions,
val encoding: IStringEncoding) {
val globalInits = mutableListOf<VmCodeLine>()
val blocks = mutableListOf<VmBlock>()
val globalInits = mutableListOf<IRCodeLine>()
val blocks = mutableListOf<IRBlock>()
fun writeFile() {
val outfile = options.outputDir / ("$name.p8ir")
println("Writing intermediate representation to $outfile")
outfile.bufferedWriter().use { out ->
out.write("; PROGRAM '$name'\n")
writeOptions(out)
writeVariableAllocations(out)
if(!options.dontReinitGlobals) {
// note: this a block of code that loads values and stores them into the global variables to reset their values.
out.write("\n<INITGLOBALS>\n")
globalInits.forEach { out.writeLine(it) }
out.write("</INITGLOBALS>\n")
}
out.write("\n<PROGRAM>\n")
writeBlocks(out)
out.write("</PROGRAM>\n")
}
}
private fun writeBlocks(out: BufferedWriter) {
blocks.forEach { block ->
out.write("\n<BLOCK NAME=${block.name} ADDRESS=${block.address} ALIGN=${block.alignment} POS=${block.position}>\n")
block.children.forEach {
when(it) {
is VmSubroutine -> {
out.write("<SUB ${it.scopedName.joinToString(".")} returntype=${it.returnType} POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</SUB>\n")
}
is VmAsmSubroutine -> {
out.write("<ASMSUB ${it.scopedName.joinToString(".")} POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</ASMSUB>\n")
}
is VmInlineAsmChunk -> {
out.write("<INLINEASM POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</INLINEASM>\n")
}
is VmCodeChunk -> {
println("GENERIC CHUNK IN BLOCK $it ${it.position}") // TODO must all be VmSubroutine
it.lines.forEach { line -> out.writeLine(line) }
}
else -> {
TODO("BLOCK CHILD $it")
}
}
}
out.write("</BLOCK>\n")
}
}
private fun writeOptions(out: BufferedWriter) {
out.write("<OPTIONS>\n")
out.write("compTarget = ${options.compTarget.name}\n")
out.write("output = ${options.output}\n")
out.write("launcher = ${options.launcher}\n")
out.write("zeropage = ${options.zeropage}\n")
out.write("zpReserved = ${options.zpReserved}\n")
out.write("loadAddress = ${options.loadAddress}\n")
out.write("dontReinitGlobals = ${options.dontReinitGlobals}\n")
out.write("evalStackBaseAddress = ${options.evalStackBaseAddress}\n")
// other options not yet useful here?
out.write("</OPTIONS>\n")
}
private fun writeVariableAllocations(out: Writer) {
out.write("\n<VARIABLES>\n")
for (variable in st.allVariables) {
val typeStr = when(variable.dt) {
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
DataType.BYTE, DataType.ARRAY_B -> "byte"
DataType.UWORD, DataType.ARRAY_UW -> "uword"
DataType.WORD, DataType.ARRAY_W -> "word"
DataType.FLOAT, DataType.ARRAY_F -> "float"
else -> throw InternalCompilerException("weird dt")
}
val value = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
DataType.STR -> {
val encoded = encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toHex() }
}
DataType.ARRAY_F -> {
if(variable.onetimeInitializationArrayValue!=null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
} else {
(1..variable.length!!).joinToString(",") { "0" }
}
}
in ArrayDatatypes -> {
if(variable.onetimeInitializationArrayValue!==null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toHex() }
} else {
(1..variable.length!!).joinToString(",") { "0" }
}
}
else -> throw InternalCompilerException("weird dt")
}
// TODO have uninitialized variables? (BSS SECTION)
out.write("VAR ${variable.scopedName.joinToString(".")} $typeStr = $value\n")
}
out.write("</VARIABLES>\n")
out.write("\n<MEMORYMAPPEDVARIABLES>\n")
for (variable in st.allMemMappedVariables) {
val typeStr = when(variable.dt) {
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
DataType.BYTE, DataType.ARRAY_B -> "byte"
DataType.UWORD, DataType.ARRAY_UW -> "uword"
DataType.WORD, DataType.ARRAY_W -> "word"
DataType.FLOAT, DataType.ARRAY_F -> "float"
else -> throw InternalCompilerException("weird dt")
}
out.write("MAP ${variable.scopedName.joinToString(".")} $typeStr ${variable.address}\n")
}
out.write("</MEMORYMAPPEDVARIABLES>\n")
out.write("\n<MEMORYSLABS>\n")
st.allMemorySlabs.forEach{ slab -> out.write("SLAB _${slab.name} ${slab.size} ${slab.align}\n") }
out.write("</MEMORYSLABS>\n")
}
private fun BufferedWriter.writeLine(line: VmCodeLine) {
when(line) {
is VmCodeComment -> write("; ${line.comment}\n")
is VmCodeInstruction -> {
write(line.ins.toString() + "\n")
}
is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
is VmInlineAsm -> {
// TODO FIXUP ASM SYMBOLS???
write(line.assembly+"\n")
}
is VmCodeInlineBinary -> {
write("incbin \"${line.file}\"")
if(line.offset!=null)
write(",${line.offset}")
if(line.length!=null)
write(",${line.length}")
write("\n")
}
else -> throw AssemblyError("invalid vm code line")
}
}
fun addGlobalInits(chunk: VmCodeChunk) = globalInits.addAll(chunk.lines)
fun addBlock(block: VmBlock) = blocks.add(block)
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.lines)
fun addBlock(block: IRBlock) = blocks.add(block)
}
sealed class VmCodeLine
class IRBlock(
val name: String,
val address: UInt?,
val alignment: PtBlock.BlockAlignment,
val position: Position
) {
val subroutines = mutableListOf<IRSubroutine>()
val asmSubroutines = mutableListOf<IRAsmSubroutine>()
val inlineAssembly = mutableListOf<IRInlineAsmChunk>()
class VmCodeInstruction(
operator fun plusAssign(sub: IRSubroutine) {
subroutines += sub
}
operator fun plusAssign(sub: IRAsmSubroutine) {
asmSubroutines += sub
}
operator fun plusAssign(asm: IRInlineAsmChunk) {
inlineAssembly += asm
}
}
class IRSubroutine(val scopedName: List<String>,
val returnType: DataType?,
val position: Position) {
val lines = mutableListOf<IRCodeLine>()
operator fun plusAssign(chunk: IRCodeChunk) {
lines += chunk.lines
}
}
class IRAsmSubroutine(val scopedName: List<String>,
val position: Position,
val address: UInt?,
val assembly: String) {
val lines = mutableListOf<IRCodeLine>()
}
sealed class IRCodeLine
class IRCodeInstruction(
opcode: Opcode,
type: VmDataType?=null,
reg1: Int?=null, // 0-$ffff
@ -189,7 +77,7 @@ class VmCodeInstruction(
value: Int?=null, // 0-$ffff
fpValue: Float?=null,
labelSymbol: List<String>?=null // alternative to value for branch/call/jump labels
): VmCodeLine() {
): IRCodeLine() {
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, labelSymbol)
init {
@ -218,55 +106,23 @@ class VmCodeInstruction(
}
}
class VmCodeLabel(val name: List<String>): VmCodeLine()
class VmCodeComment(val comment: String): VmCodeLine()
class IRCodeLabel(val name: List<String>): IRCodeLine()
class IRCodeComment(val comment: String): IRCodeLine()
class VmBlock(
val name: String,
val address: UInt?,
val alignment: PtBlock.BlockAlignment,
val position: Position
) {
val children = mutableListOf<VmCodeChunk>()
class IRCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): IRCodeLine()
operator fun plusAssign(child: VmCodeChunk) {
children += child
}
}
open class IRCodeChunk(val position: Position) {
val lines = mutableListOf<IRCodeLine>()
class VmSubroutine(val scopedName: List<String>,
val returnType: DataType?,
position: Position,
initial: VmCodeLine? = null): VmCodeChunk(position, initial)
class VmAsmSubroutine(val scopedName: List<String>,
position: Position,
initial: VmCodeLine? = null): VmCodeChunk(position, initial)
open class VmCodeChunk(val position: Position, initial: VmCodeLine? = null) {
val lines = mutableListOf<VmCodeLine>()
init {
if(initial!=null)
lines.add(initial)
}
operator fun plusAssign(line: VmCodeLine) {
operator fun plusAssign(line: IRCodeLine) {
lines.add(line)
}
operator fun plusAssign(chunk: VmCodeChunk) {
operator fun plusAssign(chunk: IRCodeChunk) {
lines.addAll(chunk.lines)
}
}
class VmInlineAsmChunk(asm: String, position: Position): VmCodeChunk(position, VmInlineAsm(asm))
class IRInlineAsmChunk(val asm: String, position: Position): IRCodeChunk(position) // note: no lines, asm is in the property
class VmInlineAsm(asm: String): VmCodeLine() {
// TODO INLINE ASSEMBLY IN IL CODE
val assembly: String = "; TODO INLINE ASSEMBLY IN IL CODE" // was: asm.trimIndent()
}
class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine()

View File

@ -8,6 +8,7 @@ main {
uword @shared slab1 = memory("slab 1", 2000, 0)
uword @shared slab2 = memory("slab 1", 2000, 0)
uword @shared slab3 = memory("other # slab", 2000, 64)
&uword mapped = $c000
uword @shared zz = slab1+slab2+slab3
@ -15,10 +16,16 @@ main {
uword @shared qq2 = &zz
qq=4242 ; TODO should generate symbol not allocated address
c64.EXTCOL = 42 ; TODO wrong VMASM code generated... should generate mapped memory address
mapped = 42 ; TODO wrong VMASM code generated... should generate mapped memory address
qq=global1
qq=other.global2
; nested()
; TODO flatten nested subroutines in codegen
sub nested() {
qq++
}
}
}