mirror of
https://github.com/irmen/prog8.git
synced 2025-02-25 20:29:04 +00:00
ir: moving to labeled chunks, no more IRLabel nodes
This commit is contained in:
parent
2340760f53
commit
6fc89607d3
@ -1,8 +1,7 @@
|
||||
package prog8
|
||||
package prog8.code
|
||||
|
||||
/**
|
||||
* By convention, the right side of an `Either` is used to hold successful values.
|
||||
*
|
||||
*/
|
||||
sealed class Either<out L, out R> {
|
||||
|
@ -53,7 +53,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
(sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes)
|
||||
|| (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes)
|
||||
|
||||
internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) {
|
||||
internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) { // TODO remove isExpression unused parameter
|
||||
// Output only the code to set up the parameters and perform the actual call
|
||||
// NOTE: does NOT output the code to deal with the result values!
|
||||
// NOTE: does NOT output code to save/restore the X register for this call! Every caller should deal with this in their own way!!
|
||||
|
@ -5,14 +5,11 @@ import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.core.SignedDatatypes
|
||||
import prog8.intermediate.IRCodeChunk
|
||||
import prog8.intermediate.IRDataType
|
||||
import prog8.intermediate.IRInstruction
|
||||
import prog8.intermediate.Opcode
|
||||
import prog8.intermediate.*
|
||||
|
||||
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
|
||||
|
||||
internal fun translate(assignment: PtAssignment): IRCodeChunk {
|
||||
internal fun translate(assignment: PtAssignment): IRCodeChunks {
|
||||
if(assignment.target.children.single() is PtMachineRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
|
||||
@ -22,7 +19,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
translateRegularAssign(assignment)
|
||||
}
|
||||
|
||||
private fun translateInplaceAssign(assignment: PtAssignment): IRCodeChunk {
|
||||
private fun translateInplaceAssign(assignment: PtAssignment): IRCodeChunks {
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
@ -48,23 +45,23 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
address: Int,
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
): IRCodeChunks {
|
||||
val vmDt = codeGen.irType(value.type)
|
||||
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
|
||||
is PtIdentifier -> return emptyList() // do nothing, x=x null assignment.
|
||||
is PtMachineRegister -> return emptyList() // do nothing, reg=reg null assignment
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, address, null, value.position)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, null, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
return if (!codeGen.options.compTarget.machine.isIOAddress(address.toUInt()))
|
||||
code // do nothing, mem=mem null assignment.
|
||||
emptyList() // do nothing, mem=mem null assignment.
|
||||
else {
|
||||
// read and write a (i/o) memory location to itself.
|
||||
val tempReg = codeGen.registers.nextFree()
|
||||
val code = IRCodeChunk(null, origAssign.position)
|
||||
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
|
||||
code
|
||||
listOf(code)
|
||||
}
|
||||
}
|
||||
else -> return fallbackAssign(origAssign)
|
||||
@ -75,25 +72,26 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
symbol: String,
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
): IRCodeChunks {
|
||||
val vmDt = codeGen.irType(value.type)
|
||||
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
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, null, symbol, value.position)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign)
|
||||
return when(value) {
|
||||
is PtIdentifier -> emptyList() // do nothing, x=x null assignment.
|
||||
is PtMachineRegister -> emptyList() // do nothing, reg=reg null assignment
|
||||
is PtPrefix -> inplacePrefix(value.operator, vmDt, null, symbol, value.position)
|
||||
is PtBinaryExpression -> inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
val code = IRCodeChunk(null, origAssign.position)
|
||||
val tempReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
return code
|
||||
listOf(code)
|
||||
}
|
||||
else -> return fallbackAssign(origAssign)
|
||||
|
||||
else -> fallbackAssign(origAssign)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fallbackAssign(origAssign: PtAssignment): IRCodeChunk {
|
||||
private fun fallbackAssign(origAssign: PtAssignment): IRCodeChunks {
|
||||
if (codeGen.options.slowCodegenWarnings)
|
||||
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
|
||||
return translateRegularAssign(origAssign)
|
||||
@ -107,7 +105,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
knownAddress: Int?,
|
||||
symbol: String?,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
): IRCodeChunks {
|
||||
if(knownAddress!=null) {
|
||||
when (operator) {
|
||||
"+" -> return expressionEval.operatorPlusInplace(knownAddress, null, vmDt, operand)
|
||||
@ -139,8 +137,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
return fallbackAssign(origAssign)
|
||||
}
|
||||
|
||||
private fun inplacePrefix(operator: String, vmDt: IRDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunk {
|
||||
val code= IRCodeChunk(position)
|
||||
private fun inplacePrefix(operator: String, vmDt: IRDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunks {
|
||||
val code= IRCodeChunk(null, position)
|
||||
when(operator) {
|
||||
"+" -> { }
|
||||
"-" -> {
|
||||
@ -160,17 +158,16 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
}
|
||||
else -> throw AssemblyError("weird prefix operator")
|
||||
}
|
||||
return code
|
||||
return listOf(code)
|
||||
}
|
||||
|
||||
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunk {
|
||||
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunks {
|
||||
// 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.irType(assignment.value.type)
|
||||
|
||||
val code = IRCodeChunk(assignment.position)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
var resultRegister = -1
|
||||
var resultFpRegister = -1
|
||||
val zero = codeGen.isZero(assignment.value)
|
||||
@ -178,20 +175,20 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
// calculate the assignment value
|
||||
if (vmDt == IRDataType.FLOAT) {
|
||||
resultFpRegister = codeGen.registers.nextFreeFloat()
|
||||
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
||||
result += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
||||
} else {
|
||||
resultRegister = if (assignment.value is PtMachineRegister) {
|
||||
(assignment.value as PtMachineRegister).register
|
||||
} else {
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, reg, -1)
|
||||
result += expressionEval.translateExpression(assignment.value, reg, -1)
|
||||
reg
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ident!=null) {
|
||||
val symbol = ident.targetName.joinToString(".")
|
||||
code += if(zero) {
|
||||
val instruction = if(zero) {
|
||||
IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
if (vmDt == IRDataType.FLOAT)
|
||||
@ -199,6 +196,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
else
|
||||
IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
}
|
||||
result += IRCodeChunk(null, ident.position).also { it += instruction }
|
||||
return result
|
||||
}
|
||||
else if(array!=null) {
|
||||
val variable = array.variable.targetName.joinToString(".")
|
||||
@ -211,84 +210,90 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
if(array.index.type!=DataType.UBYTE)
|
||||
throw AssemblyError("non-array var indexing requires bytes index")
|
||||
val idxReg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, idxReg, -1)
|
||||
result += expressionEval.translateExpression(array.index, idxReg, -1)
|
||||
val code = IRCodeChunk(null, assignment.position)
|
||||
if(zero) {
|
||||
// there's no STOREZIX instruction
|
||||
resultRegister = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
|
||||
}
|
||||
code += IRInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = variable)
|
||||
return code
|
||||
result += code
|
||||
return result
|
||||
}
|
||||
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
if(zero) {
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset")
|
||||
val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset") }
|
||||
result += chunk
|
||||
} else {
|
||||
val indexReg = codeGen.registers.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable)
|
||||
result += loadIndexReg(array, itemsize, indexReg)
|
||||
result += IRCodeChunk(null, array.position).also { it += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable) }
|
||||
}
|
||||
} else {
|
||||
if(vmDt== IRDataType.FLOAT) {
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset")
|
||||
val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset") }
|
||||
result += chunk
|
||||
} else {
|
||||
val indexReg = codeGen.registers.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
result += loadIndexReg(array, itemsize, indexReg)
|
||||
result += IRCodeChunk(null, array.position).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable) }
|
||||
}
|
||||
} else {
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset")
|
||||
val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset") }
|
||||
result += chunk
|
||||
} else {
|
||||
val indexReg = codeGen.registers.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
result += loadIndexReg(array, itemsize, indexReg)
|
||||
result += IRCodeChunk(null, array.position).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
else if(memory!=null) {
|
||||
require(vmDt== IRDataType.BYTE)
|
||||
if(zero) {
|
||||
if(memory.address is PtNumber) {
|
||||
code += IRInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
||||
val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt()) }
|
||||
result += chunk
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
||||
result += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
result += IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg) }
|
||||
}
|
||||
} else {
|
||||
if(memory.address is PtNumber) {
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
val chunk = IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt()) }
|
||||
result += chunk
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
result += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
result += IRCodeChunk(null, assignment.position).also { it += IRInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg) }
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
else
|
||||
throw AssemblyError("weird assigntarget")
|
||||
return code
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
else {
|
||||
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int): IRCodeChunks {
|
||||
return if(itemsize==1) {
|
||||
expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
} else {
|
||||
val mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
code += expressionEval.translateExpression(mult, indexReg, -1)
|
||||
expressionEval.translateExpression(mult, indexReg, -1)
|
||||
}
|
||||
return code
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import prog8.intermediate.*
|
||||
|
||||
internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGen: ExpressionGen) {
|
||||
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
return when(call.name) {
|
||||
"any" -> funcAny(call, resultRegister)
|
||||
"all" -> funcAll(call, resultRegister)
|
||||
@ -25,7 +25,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
"rsave",
|
||||
"rsavex",
|
||||
"rrestore",
|
||||
"rrestorex" -> IRCodeChunk(call.position) // vm doesn't have registers to save/restore
|
||||
"rrestorex" -> emptyList() // 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")
|
||||
@ -37,7 +37,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
"peekw" -> funcPeekW(call, resultRegister)
|
||||
"poke" -> funcPoke(call)
|
||||
"pokew" -> funcPokeW(call)
|
||||
"pokemon" -> IRCodeChunk(call.position)
|
||||
"pokemon" -> emptyList()
|
||||
"mkword" -> funcMkword(call, resultRegister)
|
||||
"sort" -> funcSort(call)
|
||||
"reverse" -> funcReverse(call)
|
||||
@ -49,20 +49,21 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val leftRegister = codeGen.registers.nextFree()
|
||||
val rightRegister = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
|
||||
code += exprGen.translateExpression(call.args[1], rightRegister, -1)
|
||||
code += IRInstruction(Opcode.CMP, codeGen.irType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args[0], leftRegister, -1)
|
||||
result += exprGen.translateExpression(call.args[1], rightRegister, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.CMP, codeGen.irType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val code = IRCodeChunk(call.position)
|
||||
val syscall =
|
||||
when (array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
@ -72,15 +73,18 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
DataType.ARRAY_F -> IMSyscall.ANY_FLOAT
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if (resultRegister != 0)
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
||||
if (resultRegister != 0)
|
||||
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val syscall =
|
||||
@ -92,98 +96,116 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
DataType.ARRAY_F -> IMSyscall.ALL_FLOAT
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
||||
if (resultRegister != 0)
|
||||
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val sourceDt = call.args.single().type
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(sourceDt!=DataType.UWORD) {
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
result += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
when (sourceDt) {
|
||||
DataType.UBYTE -> {
|
||||
code += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1 = resultRegister)
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=compareReg, value=0x80)
|
||||
code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||
it += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=compareReg, value=0x80)
|
||||
it += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
it += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1=resultRegister)
|
||||
it += IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=resultRegister)
|
||||
}
|
||||
result += IRCodeChunk(notNegativeLabel, call.position)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, IRDataType.WORD, reg1=compareReg, value=0x8000)
|
||||
code += IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, IRDataType.WORD, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOADR, IRDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||
it += IRInstruction(Opcode.AND, IRDataType.WORD, reg1=compareReg, value=0x8000)
|
||||
it += IRInstruction(Opcode.BZ, IRDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
it += IRInstruction(Opcode.NEG, IRDataType.WORD, reg1=resultRegister)
|
||||
}
|
||||
result += IRCodeChunk(notNegativeLabel, call.position)
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.SGN, codeGen.irType(call.type), reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.SGN, codeGen.irType(call.type), reg1 = resultRegister, reg2 = reg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.SQRT, IRDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.SQRT, IRDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val code = IRCodeChunk(null, call.position)
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>(code)
|
||||
result += assignRegisterTo(call.args.single(), reg)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val code = IRCodeChunk(null, call.position)
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>(code)
|
||||
result += assignRegisterTo(call.args.single(), reg)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=reg)
|
||||
return code
|
||||
result += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=reg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val reg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=reg)
|
||||
return code
|
||||
result += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = reg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val syscall =
|
||||
@ -193,14 +215,16 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
DataType.ARRAY_F -> IMSyscall.REVERSE_FLOATS
|
||||
else -> throw IllegalArgumentException("weird type to reverse")
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val syscall =
|
||||
@ -213,153 +237,184 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported")
|
||||
else -> throw IllegalArgumentException("weird type to sort")
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val msbReg = codeGen.registers.nextFree()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], msbReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
|
||||
code += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args[0], msbReg, -1)
|
||||
result += exprGen.translateExpression(call.args[1], resultRegister, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1 = resultRegister, reg2 = msbReg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPokeW(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPokeW(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.STOREZM, IRDataType.WORD, value = address)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREZM, IRDataType.WORD, value = address)
|
||||
}
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg2 = addressReg)
|
||||
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREZI, IRDataType.WORD, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.registers.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1 = valueReg, value = address)
|
||||
result += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1 = valueReg, value = address)
|
||||
}
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREI, IRDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
result += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREI, IRDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPoke(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPoke(call: PtBuiltinFunctionCall): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, value = address)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, value = address)
|
||||
}
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg2 = addressReg)
|
||||
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREZI, IRDataType.BYTE, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.registers.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueReg, value = address)
|
||||
result += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueReg, value = address)
|
||||
}
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRInstruction(Opcode.STOREI, IRDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
result += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
result += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.STOREI, IRDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.LOADM, IRDataType.WORD, reg1 = resultRegister, value = address)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOADM, IRDataType.WORD, reg1 = resultRegister, value = address)
|
||||
}
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
result += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
}
|
||||
} else {
|
||||
val addressReg = codeGen.registers.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
result += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunks {
|
||||
val code = IRCodeChunk(null, position)
|
||||
code += IRInstruction(Opcode.RND, IRDataType.BYTE, reg1=resultRegister)
|
||||
return code
|
||||
return listOf(code)
|
||||
}
|
||||
|
||||
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunks {
|
||||
val code = IRCodeChunk(null, position)
|
||||
code += IRInstruction(Opcode.RND, IRDataType.WORD, reg1=resultRegister)
|
||||
return code
|
||||
return listOf(code)
|
||||
}
|
||||
|
||||
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val name = (call.args[0] as PtString).value
|
||||
val code = IRCodeChunk(call.position)
|
||||
val code = IRCodeChunk(null, call.position)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultRegister, labelSymbol = "prog8_slabs.prog8_memoryslab_$name")
|
||||
return code
|
||||
return listOf(code)
|
||||
}
|
||||
|
||||
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
return 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): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
code += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
||||
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultRegister, reg2 = resultRegister)
|
||||
}
|
||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks {
|
||||
val vmDt = codeGen.irType(call.args[0].type)
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
code += IRInstruction(opcode, vmDt, reg1=resultRegister)
|
||||
code += assignRegisterTo(call.args[0], resultRegister)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
result += IRCodeChunk(null, call.position).also {
|
||||
it += IRInstruction(opcode, vmDt, reg1 = resultRegister)
|
||||
}
|
||||
result += assignRegisterTo(call.args[0], resultRegister)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(target.position)
|
||||
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunks {
|
||||
val code = IRCodeChunk(null, target.position)
|
||||
val assignment = PtAssignment(target.position)
|
||||
val assignTarget = PtAssignTarget(target.position)
|
||||
assignTarget.children.add(target)
|
||||
assignment.children.add(assignTarget)
|
||||
assignment.children.add(PtMachineRegister(register, target.type, target.position))
|
||||
code += codeGen.translateNode(assignment)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>(code)
|
||||
result += codeGen.translateNode(assignment)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -34,9 +34,12 @@ class IRCodeGen(
|
||||
if(!options.dontReinitGlobals) {
|
||||
// collect global variables initializers
|
||||
program.allBlocks().forEach {
|
||||
val code = IRCodeChunk(it.position)
|
||||
it.children.filterIsInstance<PtAssignment>().forEach { assign -> code += assignmentGen.translate(assign) }
|
||||
irProg.addGlobalInits(code)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
it.children.filterIsInstance<PtAssignment>().forEach { assign -> result += assignmentGen.translate(assign) }
|
||||
result.forEach { chunk ->
|
||||
if (chunk is IRCodeChunk) irProg.addGlobalInits(chunk)
|
||||
else throw AssemblyError("only expect code chunk for global inits")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,17 +212,17 @@ class IRCodeGen(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translateNode(node: PtNode): IRCodeChunkBase {
|
||||
val code = when(node) {
|
||||
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
|
||||
internal fun translateNode(node: PtNode): IRCodeChunks {
|
||||
return when(node) {
|
||||
is PtScopeVarsDecls -> emptyList() // vars should be looked up via symbol table
|
||||
is PtVariable -> emptyList() // var should be looked up via symbol table
|
||||
is PtMemMapped -> emptyList() // memmapped var should be looked up via symbol table
|
||||
is PtConstant -> emptyList() // constants have all been folded into the code
|
||||
is PtAssignment -> assignmentGen.translate(node)
|
||||
is PtNodeGroup -> translateGroup(node.children, node.position)
|
||||
is PtNodeGroup -> translateGroup(node.children)
|
||||
is PtBuiltinFunctionCall -> translateBuiltinFunc(node, 0)
|
||||
is PtFunctionCall -> expressionEval.translate(node, 0, 0)
|
||||
is PtNop -> IRCodeChunk(node.position)
|
||||
is PtNop -> emptyList()
|
||||
is PtReturn -> translate(node)
|
||||
is PtJump -> translate(node)
|
||||
is PtWhen -> translate(node)
|
||||
@ -227,23 +230,19 @@ class IRCodeGen(
|
||||
is PtIfElse -> translate(node)
|
||||
is PtPostIncrDecr -> translate(node)
|
||||
is PtRepeatLoop -> translate(node)
|
||||
is PtLabel -> {
|
||||
val chunk = IRCodeChunk(node.position)
|
||||
chunk += IRCodeLabel(node.name)
|
||||
return chunk
|
||||
}
|
||||
is PtLabel -> listOf(IRCodeChunk(node.name, node.position))
|
||||
is PtBreakpoint -> {
|
||||
val chunk = IRCodeChunk(node.position)
|
||||
val chunk = IRCodeChunk(null, node.position)
|
||||
chunk += IRInstruction(Opcode.BREAKPOINT)
|
||||
return chunk
|
||||
listOf(chunk)
|
||||
}
|
||||
is PtConditionalBranch -> translate(node)
|
||||
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.isIR, node.position)
|
||||
is PtInlineAssembly -> listOf(IRInlineAsmChunk(null, node.assembly, node.isIR, node.position))
|
||||
is PtIncludeBinary -> {
|
||||
val data = node.file.readBytes()
|
||||
.drop(node.offset?.toInt() ?: 0)
|
||||
.take(node.length?.toInt() ?: Int.MAX_VALUE)
|
||||
return IRInlineBinaryChunk(data.map { it.toUByte() }, node.position)
|
||||
listOf(IRInlineBinaryChunk(null, data.map { it.toUByte() }, node.position))
|
||||
}
|
||||
is PtAddressOf,
|
||||
is PtContainmentCheck,
|
||||
@ -265,14 +264,13 @@ class IRCodeGen(
|
||||
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): IRCodeChunk {
|
||||
val code = IRCodeChunk(branch.position)
|
||||
private fun translate(branch: PtConditionalBranch): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
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) {
|
||||
val branchIns = when(branch.condition) {
|
||||
BranchCondition.CS -> IRInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
|
||||
BranchCondition.CC -> IRInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
|
||||
BranchCondition.EQ, BranchCondition.Z -> IRInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
|
||||
@ -282,70 +280,97 @@ class IRCodeGen(
|
||||
BranchCondition.VC -> IRInstruction(Opcode.BSTVC, labelSymbol = elseLabel)
|
||||
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = elseLabel)
|
||||
}
|
||||
code += translateNode(branch.trueScope)
|
||||
addInstr(result, branchIns, null, branch.position)
|
||||
result += translateNode(branch.trueScope)
|
||||
if(branch.falseScope.children.isNotEmpty()) {
|
||||
val endLabel = createLabelName()
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
code += IRCodeLabel(elseLabel)
|
||||
code += translateNode(branch.falseScope)
|
||||
code += IRCodeLabel(endLabel)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null, branch.position)
|
||||
val chunks = translateNode(branch.falseScope)
|
||||
result += labelFirstChunk(chunks, elseLabel)
|
||||
result += IRCodeChunk(endLabel, branch.position)
|
||||
} else {
|
||||
code += IRCodeLabel(elseLabel)
|
||||
result += IRCodeChunk(elseLabel, branch.position)
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translate(whenStmt: PtWhen): IRCodeChunk {
|
||||
val code = IRCodeChunk(whenStmt.position)
|
||||
private fun labelFirstChunk(chunks: IRCodeChunks, label: String): IRCodeChunks {
|
||||
require(chunks.isNotEmpty() && label.isNotBlank())
|
||||
val newChunks = chunks.drop(1).toMutableList()
|
||||
val labeledFirstChunk = when(val first=chunks[0]) {
|
||||
is IRCodeChunk -> {
|
||||
val newChunk = IRCodeChunk(label, first.position)
|
||||
first.instructions.forEach { newChunk += it }
|
||||
newChunk
|
||||
}
|
||||
is IRInlineAsmChunk -> {
|
||||
IRInlineAsmChunk(label, first.assembly, first.isIR, first.position)
|
||||
}
|
||||
is IRInlineBinaryChunk -> {
|
||||
IRInlineBinaryChunk(label, first.data, first.position)
|
||||
}
|
||||
else -> {
|
||||
throw AssemblyError("invalid chunk")
|
||||
}
|
||||
}
|
||||
newChunks.add(0, labeledFirstChunk)
|
||||
return newChunks
|
||||
}
|
||||
|
||||
private fun translate(whenStmt: PtWhen): IRCodeChunks {
|
||||
if(whenStmt.choices.children.isEmpty())
|
||||
return code
|
||||
return emptyList()
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val valueReg = registers.nextFree()
|
||||
val choiceReg = registers.nextFree()
|
||||
val valueDt = irType(whenStmt.value.type)
|
||||
code += expressionEval.translateExpression(whenStmt.value, valueReg, -1)
|
||||
result += expressionEval.translateExpression(whenStmt.value, valueReg, -1)
|
||||
val choices = whenStmt.choices.children.map {it as PtWhenChoice }
|
||||
val endLabel = createLabelName()
|
||||
for (choice in choices) {
|
||||
if(choice.isElse) {
|
||||
code += translateNode(choice.statements)
|
||||
result += translateNode(choice.statements)
|
||||
} else {
|
||||
val skipLabel = createLabelName()
|
||||
val values = choice.values.children.map {it as PtNumber}
|
||||
if(values.size==1) {
|
||||
code += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
||||
code += IRInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
|
||||
code += translateNode(choice.statements)
|
||||
val chunk = IRCodeChunk(null, whenStmt.position)
|
||||
chunk += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
||||
chunk += IRInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
|
||||
result += chunk
|
||||
result += translateNode(choice.statements)
|
||||
if(choice.statements.children.last() !is PtReturn)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null, whenStmt.position)
|
||||
} else {
|
||||
val matchLabel = createLabelName()
|
||||
val chunk = IRCodeChunk(null, whenStmt.position)
|
||||
for (value in values) {
|
||||
code += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
||||
code += IRInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
|
||||
chunk += IRInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
||||
chunk += IRInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
|
||||
}
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
||||
code += IRCodeLabel(matchLabel)
|
||||
code += translateNode(choice.statements)
|
||||
chunk += IRInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
||||
result += chunk
|
||||
result += labelFirstChunk(translateNode(choice.statements), matchLabel)
|
||||
if(choice.statements.children.last() !is PtReturn)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = endLabel), null, whenStmt.position)
|
||||
}
|
||||
code += IRCodeLabel(skipLabel)
|
||||
result += IRCodeChunk(skipLabel, whenStmt.position)
|
||||
}
|
||||
}
|
||||
code += IRCodeLabel(endLabel)
|
||||
return code
|
||||
result += IRCodeChunk(endLabel, whenStmt.position)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translate(forLoop: PtForLoop): IRCodeChunk {
|
||||
private fun translate(forLoop: PtForLoop): IRCodeChunks {
|
||||
val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable
|
||||
val iterable = forLoop.iterable
|
||||
val code = IRCodeChunk(forLoop.position)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
when(iterable) {
|
||||
is PtRange -> {
|
||||
if(iterable.from is PtNumber && iterable.to is PtNumber)
|
||||
code += translateForInConstantRange(forLoop, loopvar)
|
||||
result += translateForInConstantRange(forLoop, loopvar)
|
||||
else
|
||||
code += translateForInNonConstantRange(forLoop, loopvar)
|
||||
result += translateForInNonConstantRange(forLoop, loopvar)
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val symbol = iterable.targetName.joinToString(".")
|
||||
@ -357,15 +382,18 @@ class IRCodeGen(
|
||||
val endLabel = createLabelName()
|
||||
if(iterableVar.dt==DataType.STR) {
|
||||
// iterate over a zero-terminated string
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol)
|
||||
code += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
code += IRCodeLabel(endLabel)
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0), null, forLoop.position)
|
||||
val chunk = IRCodeChunk(loopLabel, forLoop.position)
|
||||
chunk += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpReg, reg2=indexReg, labelSymbol = symbol)
|
||||
chunk += IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
||||
chunk += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
result += chunk
|
||||
result += translateNode(forLoop.statements)
|
||||
val jumpChunk = IRCodeChunk(null, forLoop.position)
|
||||
jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg)
|
||||
jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
result += jumpChunk
|
||||
result += IRCodeChunk(endLabel, forLoop.position)
|
||||
} else {
|
||||
// iterate over array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
@ -373,22 +401,26 @@ class IRCodeGen(
|
||||
val lengthBytes = iterableVar.length!! * elementSize
|
||||
if(lengthBytes<256) {
|
||||
val lengthReg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
code += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
code += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
|
||||
val chunk = IRCodeChunk(null, forLoop.position)
|
||||
chunk += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0)
|
||||
chunk += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||
result += chunk
|
||||
val chunk2 = IRCodeChunk(loopLabel, forLoop.position)
|
||||
chunk2 += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
chunk2 += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
result += chunk2
|
||||
result += translateNode(forLoop.statements)
|
||||
result += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel), null, forLoop.position)
|
||||
} else if(lengthBytes==256) {
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
code += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
code += IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, value=0), null, forLoop.position)
|
||||
val chunk = IRCodeChunk(loopLabel, forLoop.position)
|
||||
chunk += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=symbol)
|
||||
chunk += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
result += chunk
|
||||
result += translateNode(forLoop.statements)
|
||||
result += addConstReg(IRDataType.BYTE, indexReg, elementSize, iterable.position)
|
||||
addInstr(result, IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel), null, forLoop.position)
|
||||
} else {
|
||||
throw AssemblyError("iterator length should never exceed 256")
|
||||
}
|
||||
@ -396,10 +428,10 @@ class IRCodeGen(
|
||||
}
|
||||
else -> throw AssemblyError("weird for iterable")
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunk {
|
||||
private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunks {
|
||||
val iterable = forLoop.iterable as PtRange
|
||||
val step = iterable.step.number.toInt()
|
||||
if (step==0)
|
||||
@ -409,21 +441,20 @@ class IRCodeGen(
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val loopvarDt = irType(loopvar.dt)
|
||||
val loopLabel = createLabelName()
|
||||
val code = IRCodeChunk(forLoop.position)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
|
||||
code += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
|
||||
code += expressionEval.translateExpression(iterable.from, indexReg, -1)
|
||||
code += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
||||
code += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
||||
result += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
|
||||
result += expressionEval.translateExpression(iterable.from, indexReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol), null, forLoop.position)
|
||||
result += labelFirstChunk(translateNode(forLoop.statements), loopLabel)
|
||||
result += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
||||
addInstr(result, IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol), null, forLoop.position)
|
||||
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
|
||||
code += IRInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
|
||||
return code
|
||||
addInstr(result, IRInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel), null, forLoop.position)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunk {
|
||||
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): IRCodeChunks {
|
||||
val loopLabel = createLabelName()
|
||||
val loopvarSymbol = loopvar.scopedName.joinToString(".")
|
||||
val indexReg = registers.nextFree()
|
||||
@ -437,30 +468,33 @@ class IRCodeGen(
|
||||
if(step>0 && rangeEndUntyped<rangeStart || step<0 && rangeEndUntyped>rangeStart)
|
||||
throw AssemblyError("empty range")
|
||||
val rangeEndWrapped = if(loopvarDt==IRDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535
|
||||
val code = IRCodeChunk(forLoop.position)
|
||||
val endvalueReg: Int
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val chunk = IRCodeChunk(null, forLoop.position)
|
||||
if(rangeEndWrapped!=0) {
|
||||
endvalueReg = registers.nextFree()
|
||||
code += IRInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
|
||||
chunk += IRInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
|
||||
} else {
|
||||
endvalueReg = -1 // not used
|
||||
}
|
||||
code += IRInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart)
|
||||
code += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol)
|
||||
code += IRCodeLabel(loopLabel)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
||||
code += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
||||
code += if(rangeEndWrapped==0) {
|
||||
chunk += IRInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart)
|
||||
chunk += IRInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, labelSymbol=loopvarSymbol)
|
||||
result += chunk
|
||||
result += labelFirstChunk(translateNode(forLoop.statements), loopLabel)
|
||||
result += addConstMem(loopvarDt, null, loopvarSymbol, step, iterable.position)
|
||||
val chunk2 = IRCodeChunk(null, forLoop.position)
|
||||
chunk2 += IRInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, labelSymbol = loopvarSymbol)
|
||||
chunk2 += if(rangeEndWrapped==0) {
|
||||
IRInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
|
||||
} else {
|
||||
IRInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
|
||||
}
|
||||
return code
|
||||
result += chunk2
|
||||
return result
|
||||
}
|
||||
|
||||
private fun addConstReg(dt: IRDataType, reg: Int, value: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
when(value) {
|
||||
0 -> { /* do nothing */ }
|
||||
1 -> {
|
||||
@ -489,7 +523,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
private fun addConstMem(dt: IRDataType, knownAddress: UInt?, symbol: String?, value: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
when(value) {
|
||||
0 -> { /* do nothing */ }
|
||||
1 -> {
|
||||
@ -544,7 +578,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun multiplyByConstFloat(fpReg: Int, factor: Float, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1f)
|
||||
return code
|
||||
code += if(factor==0f) {
|
||||
@ -556,7 +590,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun multiplyByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Float, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1f)
|
||||
return code
|
||||
if(factor==0f) {
|
||||
@ -578,7 +612,7 @@ class IRCodeGen(
|
||||
internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
|
||||
|
||||
internal fun multiplyByConst(dt: IRDataType, reg: Int, factor: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
@ -602,7 +636,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun multiplyByConstInplace(dt: IRDataType, knownAddress: Int?, symbol: String?, factor: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
@ -641,7 +675,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun divideByConstFloat(fpReg: Int, factor: Float, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1f)
|
||||
return code
|
||||
code += if(factor==0f) {
|
||||
@ -653,7 +687,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun divideByConstFloatInplace(knownAddress: Int?, symbol: String?, factor: Float, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1f)
|
||||
return code
|
||||
if(factor==0f) {
|
||||
@ -675,7 +709,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun divideByConst(dt: IRDataType, reg: Int, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
@ -704,7 +738,7 @@ class IRCodeGen(
|
||||
}
|
||||
|
||||
internal fun divideByConstInplace(dt: IRDataType, knownAddress: Int?, symbol: String?, factor: Int, signed: Boolean, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
val code = IRCodeChunk(null, position)
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
@ -760,15 +794,15 @@ class IRCodeGen(
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(ifElse: PtIfElse): IRCodeChunk {
|
||||
private fun translate(ifElse: PtIfElse): IRCodeChunks {
|
||||
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 irDt = irType(ifElse.condition.left.type)
|
||||
val code = IRCodeChunk(ifElse.position)
|
||||
|
||||
fun translateNonZeroComparison(): IRCodeChunk {
|
||||
fun translateNonZeroComparison(): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val elseBranch = when(ifElse.condition.operator) {
|
||||
"==" -> Opcode.BNE
|
||||
"!=" -> Opcode.BEQ
|
||||
@ -781,50 +815,49 @@ class IRCodeGen(
|
||||
|
||||
val leftReg = registers.nextFree()
|
||||
val rightReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
code += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1)
|
||||
result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
result += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1)
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += IRCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope)
|
||||
code += IRCodeLabel(afterIfLabel)
|
||||
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel), null, ifElse.position)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null, ifElse.position)
|
||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||
result += IRCodeChunk(afterIfLabel, ifElse.position)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRCodeLabel(afterIfLabel)
|
||||
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel), null, ifElse.position)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
result += IRCodeChunk(afterIfLabel, ifElse.position)
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
fun translateZeroComparison(): IRCodeChunk {
|
||||
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunk {
|
||||
fun translateZeroComparison(): IRCodeChunks {
|
||||
fun equalOrNotEqualZero(elseBranch: Opcode): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val leftReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += IRCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope)
|
||||
code += IRCodeLabel(afterIfLabel)
|
||||
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = elseLabel), null, ifElse.position)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null, ifElse.position)
|
||||
result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
|
||||
result += IRCodeChunk(afterIfLabel, ifElse.position)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += IRCodeLabel(afterIfLabel)
|
||||
addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, labelSymbol = afterIfLabel), null, ifElse.position)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
result += IRCodeChunk(afterIfLabel, ifElse.position)
|
||||
}
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
return when (ifElse.condition.operator) {
|
||||
@ -849,8 +882,7 @@ class IRCodeGen(
|
||||
translateNonZeroComparison()
|
||||
}
|
||||
|
||||
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunk {
|
||||
val code = IRCodeChunk(postIncrDecr.position)
|
||||
private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks {
|
||||
val operationMem: Opcode
|
||||
val operationRegister: Opcode
|
||||
when(postIncrDecr.operator) {
|
||||
@ -868,19 +900,22 @@ class IRCodeGen(
|
||||
val memory = postIncrDecr.target.memory
|
||||
val array = postIncrDecr.target.array
|
||||
val irDt = irType(postIncrDecr.target.type)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
if(ident!=null) {
|
||||
code += IRInstruction(operationMem, irDt, labelSymbol = ident.targetName.joinToString("."))
|
||||
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.targetName.joinToString(".")), null, postIncrDecr.position)
|
||||
} else if(memory!=null) {
|
||||
if(memory.address is PtNumber) {
|
||||
val address = (memory.address as PtNumber).number.toInt()
|
||||
code += IRInstruction(operationMem, irDt, value = address)
|
||||
addInstr(result, IRInstruction(operationMem, irDt, value = address), null, postIncrDecr.position)
|
||||
} else {
|
||||
val incReg = registers.nextFree()
|
||||
val addressReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = addressReg)
|
||||
code += IRInstruction(operationRegister, irDt, reg1 = incReg)
|
||||
code += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = addressReg)
|
||||
result += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
val chunk = IRCodeChunk(null, postIncrDecr.position)
|
||||
chunk += IRInstruction(Opcode.LOADI, irDt, reg1 = incReg, reg2 = addressReg)
|
||||
chunk += IRInstruction(operationRegister, irDt, reg1 = incReg)
|
||||
chunk += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = addressReg)
|
||||
result += chunk
|
||||
}
|
||||
} else if (array!=null) {
|
||||
val variable = array.variable.targetName.joinToString(".")
|
||||
@ -888,25 +923,27 @@ class IRCodeGen(
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(operationMem, irDt, labelSymbol="$variable+$offset")
|
||||
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol="$variable+$offset"), null, postIncrDecr.position)
|
||||
} else {
|
||||
val incReg = registers.nextFree()
|
||||
val indexReg = registers.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
code += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
code += IRInstruction(operationRegister, irDt, reg1=incReg)
|
||||
code += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
result += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
val chunk = IRCodeChunk(null, postIncrDecr.position)
|
||||
chunk += IRInstruction(Opcode.LOADX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
chunk += IRInstruction(operationRegister, irDt, reg1=incReg)
|
||||
chunk += IRInstruction(Opcode.STOREX, irDt, reg1=incReg, reg2=indexReg, labelSymbol=variable)
|
||||
result += chunk
|
||||
}
|
||||
} else
|
||||
throw AssemblyError("weird assigntarget")
|
||||
|
||||
return code
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translate(repeat: PtRepeatLoop): IRCodeChunk {
|
||||
private fun translate(repeat: PtRepeatLoop): IRCodeChunks {
|
||||
when (constIntValue(repeat.count)) {
|
||||
0 -> return IRCodeChunk(repeat.position)
|
||||
1 -> return translateGroup(repeat.children, repeat.position)
|
||||
0 -> return emptyList()
|
||||
1 -> return translateGroup(repeat.children)
|
||||
256 -> {
|
||||
// 256 iterations can still be done with just a byte counter if you set it to zero as starting value.
|
||||
repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position)
|
||||
@ -915,22 +952,23 @@ class IRCodeGen(
|
||||
|
||||
val repeatLabel = createLabelName()
|
||||
val skipRepeatLabel = createLabelName()
|
||||
val code = IRCodeChunk(repeat.position)
|
||||
val counterReg = registers.nextFree()
|
||||
val irDt = irType(repeat.count.type)
|
||||
code += expressionEval.translateExpression(repeat.count, counterReg, -1)
|
||||
code += IRInstruction(Opcode.BZ, irDt, reg1=counterReg, labelSymbol = skipRepeatLabel)
|
||||
code += IRCodeLabel(repeatLabel)
|
||||
code += translateNode(repeat.statements)
|
||||
code += IRInstruction(Opcode.DEC, irDt, reg1=counterReg)
|
||||
code += IRInstruction(Opcode.BNZ, irDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||
code += IRCodeLabel(skipRepeatLabel)
|
||||
return code
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
result += expressionEval.translateExpression(repeat.count, counterReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.BZ, irDt, reg1=counterReg, labelSymbol = skipRepeatLabel), null, repeat.position)
|
||||
result += labelFirstChunk(translateNode(repeat.statements), repeatLabel)
|
||||
val chunk = IRCodeChunk(null, repeat.position)
|
||||
chunk += IRInstruction(Opcode.DEC, irDt, reg1=counterReg)
|
||||
chunk += IRInstruction(Opcode.BNZ, irDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||
result += chunk
|
||||
result += IRCodeChunk(skipRepeatLabel, repeat.position)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translate(jump: PtJump): IRCodeChunk {
|
||||
val code = IRCodeChunk(jump.position)
|
||||
code += if(jump.address!=null) {
|
||||
private fun translate(jump: PtJump): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val instr = if(jump.address!=null) {
|
||||
IRInstruction(Opcode.JUMPA, value = jump.address!!.toInt())
|
||||
} else {
|
||||
if (jump.generatedLabel != null)
|
||||
@ -940,27 +978,28 @@ class IRCodeGen(
|
||||
else
|
||||
throw AssemblyError("weird jump")
|
||||
}
|
||||
return code
|
||||
addInstr(result, instr, null, jump.position)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translateGroup(group: List<PtNode>, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
group.forEach { code += translateNode(it) }
|
||||
return code
|
||||
private fun translateGroup(group: List<PtNode>): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
group.forEach { result += translateNode(it) }
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translate(ret: PtReturn): IRCodeChunk {
|
||||
val code = IRCodeChunk(ret.position)
|
||||
private fun translate(ret: PtReturn): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val value = ret.value
|
||||
if(value!=null) {
|
||||
// Call Convention: return value is always returned in r0 (or fr0 if float)
|
||||
code += if(value.type==DataType.FLOAT)
|
||||
result += if(value.type==DataType.FLOAT)
|
||||
expressionEval.translateExpression(value, -1, 0)
|
||||
else
|
||||
expressionEval.translateExpression(value, 0, -1)
|
||||
}
|
||||
code += IRInstruction(Opcode.RETURN)
|
||||
return code
|
||||
addInstr(result, IRInstruction(Opcode.RETURN), null, ret.position)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun translate(block: PtBlock): IRBlock {
|
||||
@ -973,9 +1012,7 @@ class IRCodeGen(
|
||||
is PtSub -> {
|
||||
val sub = IRSubroutine(child.name, translate(child.parameters), child.returntype, child.position)
|
||||
for (subchild in child.children) {
|
||||
val translated = translateNode(subchild)
|
||||
if(translated.isNotEmpty())
|
||||
sub += translated
|
||||
translateNode(subchild).forEach { sub += it }
|
||||
}
|
||||
irBlock += sub
|
||||
}
|
||||
@ -991,7 +1028,7 @@ class IRCodeGen(
|
||||
)
|
||||
}
|
||||
is PtInlineAssembly -> {
|
||||
irBlock += IRInlineAsmChunk(child.assembly, child.isIR, child.position)
|
||||
irBlock += IRInlineAsmChunk(null, child.assembly, child.isIR, child.position)
|
||||
}
|
||||
else -> TODO("weird child node $child")
|
||||
}
|
||||
@ -1034,7 +1071,7 @@ class IRCodeGen(
|
||||
return "prog8_label_gen_$labelSequenceNumber"
|
||||
}
|
||||
|
||||
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk =
|
||||
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunks =
|
||||
builtinFuncGen.translate(call, resultRegister)
|
||||
|
||||
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
|
||||
|
@ -34,7 +34,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
TODO: this has to be changed later...
|
||||
*/
|
||||
|
||||
if(sub.chunks.isEmpty())
|
||||
/* if(sub.chunks.isEmpty())
|
||||
return
|
||||
|
||||
fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean {
|
||||
@ -56,7 +56,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
chunks += sub.chunks[ix]
|
||||
}
|
||||
sub.chunks.clear()
|
||||
sub.chunks += chunks
|
||||
sub.chunks += chunks*/
|
||||
}
|
||||
|
||||
private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
@ -112,15 +112,16 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
val labelSymbol = ins.labelSymbol
|
||||
|
||||
if(ins.opcode== Opcode.JUMP && labelSymbol!=null) {
|
||||
// remove jump/branch to label immediately below
|
||||
if(idx < chunk.instructions.size-1) {
|
||||
val label = chunk.instructions[idx+1] as? IRCodeLabel
|
||||
if(label?.name == labelSymbol) {
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
// TODO remove jump/branch to label immediately below (= next chunk if it has that label)
|
||||
// if(idx < chunk.instructions.size-1) {
|
||||
// val label = chunk.instructions[idx+1] as? IRCodeLabel
|
||||
// if(label?.name == labelSymbol) {
|
||||
// chunk.instructions.removeAt(idx)
|
||||
// changed = true
|
||||
// }
|
||||
// }
|
||||
}
|
||||
// remove useless RETURN
|
||||
if(ins.opcode == Opcode.RETURN && idx>0) {
|
||||
|
@ -6,13 +6,10 @@ import prog8.codegen.intermediate.IRPeepholeOptimizer
|
||||
import prog8.intermediate.*
|
||||
|
||||
class TestIRPeepholeOpt: FunSpec({
|
||||
fun makeIRProgram(instructions: List<IRCodeLine>): IRProgram {
|
||||
fun makeIRProgram(chunks: List<IRCodeChunkBase>): IRProgram {
|
||||
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||
val sub = IRSubroutine("main.start", emptyList(), null, Position.DUMMY)
|
||||
val chunk = IRCodeChunk(Position.DUMMY)
|
||||
for(instr in instructions)
|
||||
chunk += instr
|
||||
sub += chunk
|
||||
chunks.forEach { sub += it }
|
||||
block += sub
|
||||
val target = VMTarget()
|
||||
val options = CompilationOptions(
|
||||
@ -30,7 +27,13 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
return prog
|
||||
}
|
||||
|
||||
fun IRProgram.instructions(): List<IRCodeLine> = this.blocks.flatMap { it.subroutines }.flatMap { it.chunks }.flatMap { it.instructions }
|
||||
fun makeIRProgram(instructions: List<IRInstruction>): IRProgram {
|
||||
val chunk = IRCodeChunk(null, Position.DUMMY)
|
||||
instructions.forEach { chunk += it }
|
||||
return makeIRProgram(listOf(chunk))
|
||||
}
|
||||
|
||||
fun IRProgram.chunks(): List<IRCodeChunkBase> = this.blocks.flatMap { it.subroutines }.flatMap { it.chunks }
|
||||
|
||||
test("remove nops") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
@ -38,33 +41,35 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.NOP),
|
||||
IRInstruction(Opcode.NOP)
|
||||
))
|
||||
irProg.instructions().size shouldBe 3
|
||||
irProg.chunks().single().instructions.size shouldBe 3
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
irProg.instructions().size shouldBe 1
|
||||
irProg.chunks().single().instructions.size shouldBe 1
|
||||
}
|
||||
|
||||
test("remove jmp to label below") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "label"), // removed
|
||||
IRCodeLabel("label"),
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "label2"), // removed
|
||||
IRInstruction(Opcode.NOP), // removed
|
||||
IRCodeLabel("label2"),
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "label3"),
|
||||
IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1),
|
||||
IRCodeLabel("label3")
|
||||
))
|
||||
irProg.instructions().size shouldBe 8
|
||||
val c1 = IRCodeChunk(null, Position.DUMMY)
|
||||
c1 += IRInstruction(Opcode.JUMP, labelSymbol = "label") // removed
|
||||
val c2 = IRCodeChunk("label", Position.DUMMY)
|
||||
c2 += IRInstruction(Opcode.JUMP, labelSymbol = "label2") // removed
|
||||
c2 += IRInstruction(Opcode.NOP) // removed
|
||||
val c3 = IRCodeChunk("label2", Position.DUMMY)
|
||||
c3 += IRInstruction(Opcode.JUMP, labelSymbol = "label3")
|
||||
c3 += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=1)
|
||||
val c4 = IRCodeChunk("label3", Position.DUMMY)
|
||||
val irProg = makeIRProgram(listOf(c1, c2, c3, c4))
|
||||
|
||||
irProg.chunks().size shouldBe 4
|
||||
irProg.chunks().flatMap { it.instructions }.size shouldBe 5
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 5
|
||||
(lines[0] as IRCodeLabel).name shouldBe "label"
|
||||
(lines[1] as IRCodeLabel).name shouldBe "label2"
|
||||
(lines[2] as IRInstruction).opcode shouldBe Opcode.JUMP
|
||||
(lines[3] as IRInstruction).opcode shouldBe Opcode.INC
|
||||
(lines[4] as IRCodeLabel).name shouldBe "label3"
|
||||
irProg.chunks().size shouldBe 2
|
||||
irProg.chunks()[0].label shouldBe "label2"
|
||||
irProg.chunks()[1].label shouldBe "label3"
|
||||
val instr = irProg.chunks().flatMap { it.instructions }
|
||||
instr.size shouldBe 2
|
||||
instr[0].opcode shouldBe Opcode.JUMP
|
||||
instr[1].opcode shouldBe Opcode.INC
|
||||
}
|
||||
|
||||
test("remove double sec/clc") {
|
||||
@ -76,12 +81,12 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.CLC),
|
||||
IRInstruction(Opcode.CLC)
|
||||
))
|
||||
irProg.instructions().size shouldBe 6
|
||||
irProg.chunks().single().instructions.size shouldBe 6
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.CLC
|
||||
val instr = irProg.chunks().single().instructions
|
||||
instr.size shouldBe 1
|
||||
instr[0].opcode shouldBe Opcode.CLC
|
||||
}
|
||||
|
||||
test("push followed by pop") {
|
||||
@ -91,14 +96,14 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=99),
|
||||
IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=222)
|
||||
))
|
||||
irProg.instructions().size shouldBe 4
|
||||
irProg.chunks().single().instructions.size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOADR
|
||||
(lines[0] as IRInstruction).reg1 shouldBe 222
|
||||
(lines[0] as IRInstruction).reg2 shouldBe 99
|
||||
val instr = irProg.chunks().single().instructions
|
||||
instr.size shouldBe 1
|
||||
instr[0].opcode shouldBe Opcode.LOADR
|
||||
instr[0].reg1 shouldBe 222
|
||||
instr[0].reg2 shouldBe 99
|
||||
}
|
||||
|
||||
test("remove useless div/mul, add/sub") {
|
||||
@ -114,11 +119,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 0)
|
||||
))
|
||||
irProg.instructions().size shouldBe 10
|
||||
irProg.chunks().single().instructions.size shouldBe 10
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 4
|
||||
irProg.chunks().single().instructions.size shouldBe 4
|
||||
}
|
||||
|
||||
test("replace add/sub 1 by inc/dec") {
|
||||
@ -126,13 +130,13 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.SUB, IRDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.instructions().size shouldBe 2
|
||||
irProg.chunks().single().instructions.size shouldBe 2
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 2
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.INC
|
||||
(lines[1] as IRInstruction).opcode shouldBe Opcode.DEC
|
||||
val instr = irProg.chunks().single().instructions
|
||||
instr.size shouldBe 2
|
||||
instr[0].opcode shouldBe Opcode.INC
|
||||
instr[1].opcode shouldBe Opcode.DEC
|
||||
}
|
||||
|
||||
test("remove useless and/or/xor") {
|
||||
@ -146,11 +150,10 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.XOR, IRDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.instructions().size shouldBe 8
|
||||
irProg.chunks().single().instructions.size shouldBe 8
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 4
|
||||
irProg.chunks().single().instructions.size shouldBe 4
|
||||
}
|
||||
|
||||
test("replace and/or/xor by constant number") {
|
||||
@ -160,18 +163,18 @@ class TestIRPeepholeOpt: FunSpec({
|
||||
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, value = 65535)
|
||||
))
|
||||
irProg.instructions().size shouldBe 4
|
||||
irProg.chunks().single().instructions.size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.instructions()
|
||||
lines.size shouldBe 4
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[1] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[2] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[3] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[0] as IRInstruction).value shouldBe 0
|
||||
(lines[1] as IRInstruction).value shouldBe 0
|
||||
(lines[2] as IRInstruction).value shouldBe 255
|
||||
(lines[3] as IRInstruction).value shouldBe 65535
|
||||
val instr = irProg.chunks().single().instructions
|
||||
instr.size shouldBe 4
|
||||
instr[0].opcode shouldBe Opcode.LOAD
|
||||
instr[1].opcode shouldBe Opcode.LOAD
|
||||
instr[2].opcode shouldBe Opcode.LOAD
|
||||
instr[3].opcode shouldBe Opcode.LOAD
|
||||
instr[0].value shouldBe 0
|
||||
instr[1].value shouldBe 0
|
||||
instr[2].value shouldBe 255
|
||||
instr[3].value shouldBe 65535
|
||||
}
|
||||
})
|
@ -4,7 +4,10 @@ TODO
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- ir: get rid of IRCodeLabel, make every label start a new code chunk, give those a 'label' property.
|
||||
- ir: fix joinChunks() in the IR optimizer ?
|
||||
- ir: fix program to be list of chunks
|
||||
- ir: jump/branch instructions don't link to a PC index anymore, but to the actual chunk with that label
|
||||
- ir: fix joinChunks() in the IR optimizer ? Fix TestIRPeepholeOptimizer and TestVm
|
||||
- vm: program is list of chunks, fix dispatcher
|
||||
|
||||
...
|
||||
|
||||
|
@ -32,7 +32,7 @@ class IRFileReader {
|
||||
val memorymapped = parseMemMapped(lines)
|
||||
val slabs = parseSlabs(lines)
|
||||
val initGlobals = parseInitGlobals(lines)
|
||||
val blocks = parseBlocksUntilProgramEnd(lines, variables)
|
||||
val blocks = parseBlocksUntilProgramEnd(lines)
|
||||
|
||||
val st = IRSymbolTable(null)
|
||||
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
|
||||
@ -261,9 +261,9 @@ class IRFileReader {
|
||||
if(line!="<INITGLOBALS>")
|
||||
throw IRParseException("invalid INITGLOBALS")
|
||||
line = lines.next()
|
||||
var chunk = IRCodeChunk(Position.DUMMY)
|
||||
var chunk = IRCodeChunk(null, Position.DUMMY)
|
||||
if(line=="<C>") {
|
||||
chunk = parseCodeChunk(line, lines)!!
|
||||
chunk = parseCodeChunk(line, lines, null)!!
|
||||
line = lines.next()
|
||||
}
|
||||
if(line!="</INITGLOBALS>")
|
||||
@ -271,7 +271,7 @@ class IRFileReader {
|
||||
return chunk
|
||||
}
|
||||
|
||||
private fun parseBlocksUntilProgramEnd(lines: Iterator<String>, variables: List<StStaticVariable>): List<IRBlock> {
|
||||
private fun parseBlocksUntilProgramEnd(lines: Iterator<String>): List<IRBlock> {
|
||||
val blocks = mutableListOf<IRBlock>()
|
||||
while(true) {
|
||||
var line = lines.next()
|
||||
@ -279,7 +279,7 @@ class IRFileReader {
|
||||
line = lines.next()
|
||||
if (line == "</PROGRAM>")
|
||||
break
|
||||
blocks.add(parseBlock(line, lines, variables))
|
||||
blocks.add(parseBlock(line, lines))
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
@ -291,7 +291,7 @@ class IRFileReader {
|
||||
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
||||
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
||||
|
||||
private fun parseBlock(startline: String, lines: Iterator<String>, variables: List<StStaticVariable>): IRBlock {
|
||||
private fun parseBlock(startline: String, lines: Iterator<String>): IRBlock {
|
||||
var line = startline
|
||||
if(!line.startsWith("<BLOCK "))
|
||||
throw IRParseException("invalid BLOCK")
|
||||
@ -306,20 +306,20 @@ class IRFileReader {
|
||||
if(line=="</BLOCK>")
|
||||
return block
|
||||
if(line.startsWith("<SUB ")) {
|
||||
val sub = parseSubroutine(line, lines, variables)
|
||||
val sub = parseSubroutine(line, lines)
|
||||
block += sub
|
||||
} else if(line.startsWith("<ASMSUB ")) {
|
||||
val sub = parseAsmSubroutine(line, lines)
|
||||
block += sub
|
||||
} else if(line.startsWith("<INLINEASM ")) {
|
||||
val asm = parseInlineAssembly(line, lines)
|
||||
val asm = parseInlineAssembly(line, lines, null)
|
||||
block += asm
|
||||
} else
|
||||
throw IRParseException("invalid line in BLOCK")
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseInlineAssembly(startline: String, lines: Iterator<String>): IRInlineAsmChunk {
|
||||
private fun parseInlineAssembly(startline: String, lines: Iterator<String>, label: String?): IRInlineAsmChunk {
|
||||
// <INLINEASM IR=true POS=[examples/test.p8: line 8 col 6-9]>
|
||||
val match = inlineAsmPattern.matchEntire(startline) ?: throw IRParseException("invalid INLINEASM")
|
||||
val isIr = match.groupValues[1].toBoolean()
|
||||
@ -330,7 +330,7 @@ class IRFileReader {
|
||||
asmlines.add(line)
|
||||
line = lines.next()
|
||||
}
|
||||
return IRInlineAsmChunk(asmlines.joinToString("\n"), isIr, pos)
|
||||
return IRInlineAsmChunk(label, asmlines.joinToString("\n"), isIr, pos)
|
||||
}
|
||||
|
||||
private fun parseAsmSubroutine(startline: String, lines: Iterator<String>): IRAsmSubroutine {
|
||||
@ -352,7 +352,7 @@ class IRFileReader {
|
||||
params += Pair(dt, regsf)
|
||||
}
|
||||
line = lines.next()
|
||||
val asm = parseInlineAssembly(line, lines)
|
||||
val asm = parseInlineAssembly(line, lines, null)
|
||||
while(line!="</ASMSUB>")
|
||||
line = lines.next()
|
||||
val clobberRegs = if(clobbers.isBlank()) emptyList() else clobbers.split(',').map { CpuRegister.valueOf(it) }
|
||||
@ -374,12 +374,12 @@ class IRFileReader {
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseSubroutine(startline: String, lines: Iterator<String>, variables: List<StStaticVariable>): IRSubroutine {
|
||||
private fun parseSubroutine(startline: String, lines: Iterator<String>): IRSubroutine {
|
||||
// <SUB NAME=main.start.nested.nested2 RETURNTYPE=null POS=[examples/test.p8: line 54 col 14-16]>
|
||||
val match = subPattern.matchEntire(startline) ?: throw IRParseException("invalid SUB")
|
||||
val (name, returntype, pos) = match.destructured
|
||||
val sub = IRSubroutine(name,
|
||||
parseParameters(lines, variables),
|
||||
parseParameters(lines),
|
||||
if(returntype=="null") null else parseDatatype(returntype, false),
|
||||
parsePosition(pos))
|
||||
while(true) {
|
||||
@ -387,11 +387,11 @@ class IRFileReader {
|
||||
if(line=="</SUB>")
|
||||
return sub
|
||||
val chunk = if(line=="<C>")
|
||||
parseCodeChunk(line, lines)
|
||||
parseCodeChunk(line, lines, null)
|
||||
else if(line.startsWith("<BYTES "))
|
||||
parseBinaryBytes(line, lines)
|
||||
parseBinaryBytes(line, lines, null)
|
||||
else if(line.startsWith("<INLINEASM "))
|
||||
parseInlineAssembly(line, lines)
|
||||
parseInlineAssembly(line, lines, null)
|
||||
else
|
||||
throw IRParseException("invalid sub child node")
|
||||
|
||||
@ -406,7 +406,7 @@ class IRFileReader {
|
||||
return sub
|
||||
}
|
||||
|
||||
private fun parseBinaryBytes(startline: String, lines: Iterator<String>): IRInlineBinaryChunk {
|
||||
private fun parseBinaryBytes(startline: String, lines: Iterator<String>, label: String?): IRInlineBinaryChunk {
|
||||
val match = bytesPattern.matchEntire(startline) ?: throw IRParseException("invalid BYTES")
|
||||
val pos = parsePosition(match.groupValues[1])
|
||||
val bytes = mutableListOf<UByte>()
|
||||
@ -417,10 +417,10 @@ class IRFileReader {
|
||||
}
|
||||
line = lines.next()
|
||||
}
|
||||
return IRInlineBinaryChunk(bytes, pos)
|
||||
return IRInlineBinaryChunk(label, bytes, pos)
|
||||
}
|
||||
|
||||
private fun parseParameters(lines: Iterator<String>, variables: List<StStaticVariable>): List<IRSubroutine.IRParam> {
|
||||
private fun parseParameters(lines: Iterator<String>): List<IRSubroutine.IRParam> {
|
||||
var line = lines.next()
|
||||
if(line!="<PARAMS>")
|
||||
throw IRParseException("missing PARAMS")
|
||||
@ -436,21 +436,29 @@ class IRFileReader {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseCodeChunk(firstline: String, lines: Iterator<String>): IRCodeChunk? {
|
||||
private fun parseCodeChunk(firstline: String, lines: Iterator<String>, label: String?): IRCodeChunk? {
|
||||
if(firstline!="<C>") {
|
||||
if(firstline=="</SUB>")
|
||||
return null
|
||||
else
|
||||
throw IRParseException("invalid or empty <C>ODE chunk")
|
||||
}
|
||||
val chunk = IRCodeChunk(Position.DUMMY)
|
||||
val chunk = IRCodeChunk(label, Position.DUMMY)
|
||||
while(true) {
|
||||
val line = lines.next()
|
||||
if (line == "</C>")
|
||||
return chunk
|
||||
if (line.isBlank() || line.startsWith(';'))
|
||||
continue
|
||||
chunk += parseIRCodeLine(line, 0, mutableMapOf())
|
||||
val result = parseIRCodeLine(line, 0, mutableMapOf())
|
||||
result.fold(
|
||||
ifLeft = {
|
||||
chunk += it
|
||||
},
|
||||
ifRight = {
|
||||
TODO("PROCESS LABEL $it")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
package prog8.intermediate
|
||||
|
||||
import prog8.code.core.*
|
||||
import java.io.BufferedWriter
|
||||
import prog8.code.core.ArrayDatatypes
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.InternalCompilerException
|
||||
import prog8.code.core.NumericDatatypes
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.bufferedWriter
|
||||
import kotlin.io.path.div
|
||||
@ -25,7 +27,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
if(!irProgram.options.dontReinitGlobals) {
|
||||
out.write("<C>\n")
|
||||
// note: this a block of code that loads values and stores them into the global variables to reset their values.
|
||||
irProgram.globalInits.forEach { out.writeLine(it) }
|
||||
irProgram.globalInits.forEach { out.write(it.toString()) }
|
||||
out.write("</C>\n")
|
||||
}
|
||||
out.write("</INITGLOBALS>\n")
|
||||
@ -67,7 +69,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
|
||||
chunk.instructions.forEach { instr ->
|
||||
numInstr++
|
||||
out.writeLine(instr)
|
||||
out.write(instr.toString())
|
||||
}
|
||||
out.write("</C>\n")
|
||||
}
|
||||
@ -179,12 +181,4 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
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 IRInstruction -> write(line.toString() + "\n")
|
||||
is IRCodeLabel -> write("_${line.name}:\n")
|
||||
else -> throw AssemblyError("invalid vm code line")
|
||||
}
|
||||
}
|
||||
}
|
@ -669,7 +669,7 @@ data class IRInstruction(
|
||||
val fpValue: Float?=null,
|
||||
val labelSymbol: String?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
||||
val binaryData: Collection<UByte>?=null
|
||||
): IRCodeLine() {
|
||||
) {
|
||||
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
|
||||
// This knowledge is useful in IL assembly optimizers to see how registers are used.
|
||||
val reg1direction: OperandDirection
|
||||
|
@ -52,7 +52,7 @@ class IRProgram(val name: String,
|
||||
val encoding: IStringEncoding) {
|
||||
|
||||
val asmSymbols = mutableMapOf<String, String>()
|
||||
val globalInits = mutableListOf<IRCodeLine>()
|
||||
val globalInits = mutableListOf<IRInstruction>()
|
||||
val blocks = mutableListOf<IRBlock>()
|
||||
|
||||
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.instructions)
|
||||
@ -91,10 +91,7 @@ class IRProgram(val name: String,
|
||||
usedRegisters.outputFpRegs.forEach{ (reg, count) -> outputFpRegs[reg] = outputFpRegs.getValue(reg) + count }
|
||||
}
|
||||
|
||||
globalInits.forEach {
|
||||
if(it is IRInstruction)
|
||||
it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
|
||||
}
|
||||
globalInits.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) }
|
||||
blocks.forEach {
|
||||
it.inlineAssembly.forEach { chunk -> addUsed(chunk.usedRegisters()) }
|
||||
it.subroutines.flatMap { sub->sub.chunks }.forEach { chunk -> addUsed(chunk.usedRegisters()) }
|
||||
@ -171,19 +168,15 @@ class IRAsmSubroutine(
|
||||
fun usedRegisters() = registersUsed
|
||||
}
|
||||
|
||||
sealed class IRCodeLine
|
||||
|
||||
class IRCodeLabel(val name: String): IRCodeLine()
|
||||
|
||||
abstract class IRCodeChunkBase(val position: Position) {
|
||||
val instructions = mutableListOf<IRCodeLine>()
|
||||
abstract class IRCodeChunkBase(val label: String?, val position: Position) {
|
||||
val instructions = mutableListOf<IRInstruction>()
|
||||
|
||||
abstract fun isEmpty(): Boolean
|
||||
abstract fun isNotEmpty(): Boolean
|
||||
abstract fun usedRegisters(): RegistersUsed
|
||||
}
|
||||
|
||||
class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
|
||||
class IRCodeChunk(label: String?, position: Position): IRCodeChunkBase(label, position) {
|
||||
|
||||
override fun isEmpty() = instructions.isEmpty()
|
||||
override fun isNotEmpty() = instructions.isNotEmpty()
|
||||
@ -192,15 +185,12 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
|
||||
val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
instructions.forEach {
|
||||
if(it is IRInstruction)
|
||||
it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
|
||||
}
|
||||
instructions.forEach { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) }
|
||||
return RegistersUsed(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
|
||||
}
|
||||
|
||||
operator fun plusAssign(line: IRCodeLine) {
|
||||
instructions.add(line)
|
||||
operator fun plusAssign(ins: IRInstruction) {
|
||||
instructions.add(ins)
|
||||
}
|
||||
|
||||
operator fun plusAssign(chunk: IRCodeChunkBase) {
|
||||
@ -208,8 +198,8 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
|
||||
}
|
||||
}
|
||||
|
||||
class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(position) {
|
||||
// note: no lines, asm is in the property
|
||||
class IRInlineAsmChunk(label: String?, val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(label, position) {
|
||||
// note: no instructions, asm is in the property
|
||||
override fun isEmpty() = assembly.isBlank()
|
||||
override fun isNotEmpty() = assembly.isNotBlank()
|
||||
private val registersUsed by lazy { registersUsedInAssembly(isIR, assembly) }
|
||||
@ -222,12 +212,15 @@ class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Positi
|
||||
override fun usedRegisters() = registersUsed
|
||||
}
|
||||
|
||||
class IRInlineBinaryChunk(val data: Collection<UByte>, position: Position): IRCodeChunkBase(position) {
|
||||
class IRInlineBinaryChunk(label: String?, val data: Collection<UByte>, position: Position): IRCodeChunkBase(label, position) {
|
||||
// note: no instructions, data is in the property
|
||||
override fun isEmpty() = data.isEmpty()
|
||||
override fun isNotEmpty() = data.isNotEmpty()
|
||||
override fun usedRegisters() = RegistersUsed(emptyMap(), emptyMap(), emptyMap(), emptyMap())
|
||||
}
|
||||
|
||||
typealias IRCodeChunks = List<IRCodeChunkBase>
|
||||
|
||||
class RegistersUsed(
|
||||
// register num -> number of uses
|
||||
val inputRegs: Map<Int, Int>,
|
||||
@ -251,9 +244,11 @@ private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersU
|
||||
|
||||
if(isIR) {
|
||||
assembly.lineSequence().forEach { line ->
|
||||
val code = parseIRCodeLine(line.trim(), 0, mutableMapOf())
|
||||
if(code is IRInstruction)
|
||||
code.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
|
||||
val result = parseIRCodeLine(line.trim(), 0, mutableMapOf())
|
||||
result.fold(
|
||||
ifLeft = { it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs) },
|
||||
ifRight = { /* labels can be skipped */ }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package prog8.intermediate
|
||||
|
||||
import prog8.code.StMemVar
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.InternalCompilerException
|
||||
|
||||
@ -85,12 +84,12 @@ fun parseIRValue(value: String): Float {
|
||||
private val instructionPattern = Regex("""([a-z]+)(\.b|\.w|\.f)?(.*)""", RegexOption.IGNORE_CASE)
|
||||
private val labelPattern = Regex("""_([a-zA-Z\d\._]+):""")
|
||||
|
||||
fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap<Int, String>): IRCodeLine {
|
||||
fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap<Int, String>): Either<IRInstruction, String> {
|
||||
// Note: this function is used from multiple places:
|
||||
// the IR File Reader but also the VirtualMachine itself to make sense of any inline vmasm blocks.
|
||||
val labelmatch = labelPattern.matchEntire(line.trim())
|
||||
if(labelmatch!=null)
|
||||
return IRCodeLabel(labelmatch.groupValues[1])
|
||||
return right(labelmatch.groupValues[1]) // it's a label.
|
||||
|
||||
val match = instructionPattern.matchEntire(line)
|
||||
?: throw IRParseException("invalid IR instruction: $line")
|
||||
@ -240,8 +239,8 @@ fun parseIRCodeLine(line: String, pc: Int, placeholders: MutableMap<Int, String>
|
||||
"pc", "pz", "pv","pn"))
|
||||
throw IRParseException("invalid cpu reg: $reg")
|
||||
|
||||
return IRInstruction(opcode, type, reg1, labelSymbol = reg)
|
||||
return left(IRInstruction(opcode, type, reg1, labelSymbol = reg))
|
||||
}
|
||||
|
||||
return IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue, labelSymbol = labelSymbol)
|
||||
return left(IRInstruction(opcode, type, reg1, reg2, fpReg1, fpReg2, intValue, floatValue, labelSymbol = labelSymbol))
|
||||
}
|
||||
|
@ -44,10 +44,14 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
private val cx16virtualregsBaseAddress: Int
|
||||
|
||||
init {
|
||||
program = emptyArray() // TODO
|
||||
cx16virtualregsBaseAddress = 0 // TODO
|
||||
/* TODO !!!
|
||||
program = VmProgramLoader().load(irProgram, memory).toTypedArray()
|
||||
require(program.size<=65536) {"program cannot contain more than 65536 instructions"}
|
||||
require(irProgram.st.getAsmSymbols().isEmpty()) { "virtual machine can't yet process asmsymbols defined on command line" }
|
||||
cx16virtualregsBaseAddress = (irProgram.st.lookup("cx16.r0") as? StMemVar)?.address?.toInt() ?: 0xff02
|
||||
*/
|
||||
}
|
||||
|
||||
fun run() {
|
||||
|
@ -3,6 +3,7 @@ package prog8.vm
|
||||
import prog8.code.core.DataType
|
||||
import prog8.intermediate.*
|
||||
|
||||
/*
|
||||
class VmProgramLoader {
|
||||
|
||||
private val placeholders = mutableMapOf<Int, String>() // program index to symbolname
|
||||
@ -13,12 +14,12 @@ class VmProgramLoader {
|
||||
placeholders.clear()
|
||||
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
|
||||
val symbolAddresses = allocations.allocations.toMutableMap()
|
||||
val program = mutableListOf<IRInstruction>()
|
||||
val programChunks = mutableListOf<IRCodeChunkBase>()
|
||||
|
||||
varsToMemory(irProgram, allocations, symbolAddresses, memory)
|
||||
|
||||
if(!irProgram.options.dontReinitGlobals)
|
||||
addToProgram(irProgram.globalInits, program, symbolAddresses)
|
||||
addToProgram(irProgram.globalInits, programChunks, symbolAddresses)
|
||||
|
||||
// make sure that if there is a "main.start" entrypoint, we jump to it
|
||||
irProgram.blocks.firstOrNull()?.let {
|
||||
@ -187,8 +188,8 @@ class VmProgramLoader {
|
||||
}
|
||||
|
||||
private fun addToProgram(
|
||||
instructions: Iterable<IRCodeLine>,
|
||||
program: MutableList<IRInstruction>,
|
||||
chunks: Iterable<IRCodeChunkBase>,
|
||||
program: MutableList<IRCodeChunkBase>,
|
||||
symbolAddresses: MutableMap<String, Int>
|
||||
) {
|
||||
instructions.map {
|
||||
@ -241,3 +242,4 @@ class VmProgramLoader {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -42,7 +42,7 @@ class TestVm: FunSpec( {
|
||||
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||
val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
|
||||
val code = IRCodeChunk(Position.DUMMY)
|
||||
val code = IRCodeChunk(null, Position.DUMMY)
|
||||
code += IRInstruction(Opcode.NOP)
|
||||
code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=1, value=12345)
|
||||
code += IRInstruction(Opcode.STOREM, IRDataType.WORD, reg1=1, value=1000)
|
||||
@ -69,7 +69,7 @@ class TestVm: FunSpec( {
|
||||
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||
val block = IRBlock("testmain", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
|
||||
val code = IRCodeChunk(Position.DUMMY)
|
||||
val code = IRCodeChunk(null, Position.DUMMY)
|
||||
code += IRInstruction(Opcode.BINARYDATA, binaryData = listOf(1u,2u,3u))
|
||||
code += IRInstruction(Opcode.RETURN)
|
||||
startSub += code
|
||||
|
Loading…
x
Reference in New Issue
Block a user