block structure

This commit is contained in:
Irmen de Jong 2022-08-25 21:02:18 +02:00
parent a182b13e5a
commit b0704e86f0
7 changed files with 281 additions and 225 deletions

View File

@ -46,11 +46,11 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
origAssign: PtAssignment
): VmCodeChunk {
val vmDt = codeGen.vmType(value.type)
val code = VmCodeChunk()
val code = VmCodeChunk(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, address)
is PtPrefix -> return inplacePrefix(value.operator, vmDt, address, value.position)
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, origAssign)
is PtMemoryByte -> {
return if (!codeGen.options.compTarget.machine.isIOAddress(address.toUInt()))
@ -97,8 +97,8 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
return fallbackAssign(origAssign)
}
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int): VmCodeChunk {
val code= VmCodeChunk()
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int, position: Position): VmCodeChunk {
val code= VmCodeChunk(position)
when(operator) {
"+" -> { }
"-" -> {
@ -122,7 +122,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
val array = assignment.target.array
val vmDt = codeGen.vmType(assignment.value.type)
val code = VmCodeChunk()
val code = VmCodeChunk(assignment.position)
var resultRegister = -1
var resultFpRegister = -1
val zero = codeGen.isZero(assignment.value)
@ -181,7 +181,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=variableAddr)
} else {
val indexReg = codeGen.vmRegisters.nextFree()
code += loadIndexReg(array, itemsize, indexReg)
code += loadIndexReg(array, itemsize, indexReg, array.position)
code += VmCodeInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, value=variableAddr)
}
} else {
@ -191,7 +191,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
code += VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value=variableAddr)
} else {
val indexReg = codeGen.vmRegisters.nextFree()
code += loadIndexReg(array, itemsize, indexReg)
code += loadIndexReg(array, itemsize, indexReg, array.position)
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
}
} else {
@ -200,7 +200,7 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value=variableAddr)
} else {
val indexReg = codeGen.vmRegisters.nextFree()
code += loadIndexReg(array, itemsize, indexReg)
code += loadIndexReg(array, itemsize, indexReg, array.position)
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
}
}
@ -231,8 +231,8 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
return code
}
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int): VmCodeChunk {
val code = VmCodeChunk()
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(itemsize==1) {
code += expressionEval.translateExpression(array.index, indexReg, -1)
}

View File

@ -4,6 +4,7 @@ import prog8.code.StStaticVariable
import prog8.code.ast.*
import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.vm.Opcode
import prog8.vm.Syscall
import prog8.vm.VmDataType
@ -25,9 +26,9 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
"rsave",
"rsavex",
"rrestore",
"rrestorex" -> VmCodeChunk() // vm doesn't have registers to save/restore
"rnd" -> funcRnd(resultRegister)
"rndw" -> funcRndw(resultRegister)
"rrestorex" -> VmCodeChunk(call.position) // vm doesn't have registers to save/restore
"rnd" -> funcRnd(resultRegister, call.position)
"rndw" -> funcRndw(resultRegister, call.position)
"callfar" -> throw AssemblyError("callfar() is for cx16 target only")
"callrom" -> throw AssemblyError("callrom() is for cx16 target only")
"msb" -> funcMsb(call, resultRegister)
@ -37,7 +38,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
"peekw" -> funcPeekW(call, resultRegister)
"poke" -> funcPoke(call)
"pokew" -> funcPokeW(call)
"pokemon" -> VmCodeChunk()
"pokemon" -> VmCodeChunk(call.position)
"mkword" -> funcMkword(call, resultRegister)
"sort" -> funcSort(call)
"reverse" -> funcReverse(call)
@ -50,7 +51,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcCmp(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val leftRegister = codeGen.vmRegisters.nextFree()
val rightRegister = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
@ -62,7 +63,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val syscall =
when (array.dt) {
DataType.ARRAY_UB,
@ -92,7 +93,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
DataType.ARRAY_F -> Syscall.ALL_FLOAT
else -> throw IllegalArgumentException("weird type")
}
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], 0, -1)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
@ -102,7 +103,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val sourceDt = call.args.single().type
if(sourceDt!=DataType.UWORD) {
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
@ -136,7 +137,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
@ -144,7 +145,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
@ -152,7 +153,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPop(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
code += assignRegisterTo(call.args.single(), reg)
@ -160,7 +161,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPopw(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
code += assignRegisterTo(call.args.single(), reg)
@ -168,7 +169,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPush(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
@ -176,7 +177,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPushw(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
val reg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), reg, -1)
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
@ -193,7 +194,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
DataType.ARRAY_F -> Syscall.REVERSE_FLOATS
else -> throw IllegalArgumentException("weird type to reverse")
}
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], 0, -1)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
@ -213,7 +214,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported")
else -> throw IllegalArgumentException("weird type to sort")
}
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], 0, -1)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
@ -222,7 +223,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val msbReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], msbReg, -1)
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
@ -230,7 +231,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
if(codeGen.isZero(call.args[1])) {
if (call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
@ -257,7 +258,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
if(codeGen.isZero(call.args[1])) {
if (call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
@ -284,7 +285,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
if(call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
@ -297,7 +298,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
if(call.args[0] is PtNumber) {
val address = (call.args[0] as PtNumber).number.toInt()
code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
@ -309,14 +310,14 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
return code
}
private fun funcRnd(resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
private fun funcRnd(resultRegister: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
code += VmCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
return code
}
private fun funcRndw(resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
private fun funcRndw(resultRegister: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
code += VmCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
return code
}
@ -326,20 +327,20 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val size = (call.args[1] as PtNumber).number.toUInt()
val align = (call.args[2] as PtNumber).number.toUInt()
val label = codeGen.addMemorySlab(name, size, align, call.position)
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = listOf(label))
return code
}
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
return code
}
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
@ -348,7 +349,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
val vmDt = codeGen.vmType(call.args[0].type)
val code = VmCodeChunk()
val code = VmCodeChunk(call.position)
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
code += assignRegisterTo(call.args[0], resultRegister)
@ -356,7 +357,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
private fun assignRegisterTo(target: PtExpression, register: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(target.position)
val assignment = PtAssignment(target.position)
val assignTarget = PtAssignTarget(target.position)
assignTarget.children.add(target)

View File

@ -53,7 +53,7 @@ class CodeGen(internal val program: PtProgram,
if(!options.dontReinitGlobals) {
// collect global variables initializers
program.allBlocks().forEach {
val code = VmCodeChunk()
val code = VmCodeChunk(it.position)
it.children.filterIsInstance<PtAssignment>().forEach { assign -> code += assignmentGen.translate(assign) }
irProg.addGlobalInits(code)
}
@ -82,18 +82,17 @@ class CodeGen(internal val program: PtProgram,
internal fun translateNode(node: PtNode): VmCodeChunk {
val code = when(node) {
is PtBlock -> translate(node)
is PtSub -> translate(node)
is PtAsmSub -> translate(node)
is PtScopeVarsDecls -> VmCodeChunk() // vars should be looked up via symbol table
is PtVariable -> VmCodeChunk() // var should be looked up via symbol table
is PtMemMapped -> VmCodeChunk() // memmapped var should be looked up via symbol table
is PtConstant -> VmCodeChunk() // constants have all been folded into the code
is PtScopeVarsDecls -> VmCodeChunk(node.position) // vars should be looked up via symbol table
is PtVariable -> VmCodeChunk(node.position) // var should be looked up via symbol table
is PtMemMapped -> VmCodeChunk(node.position) // memmapped var should be looked up via symbol table
is PtConstant -> VmCodeChunk(node.position) // constants have all been folded into the code
is PtAssignment -> assignmentGen.translate(node)
is PtNodeGroup -> translateGroup(node.children)
is PtNodeGroup -> translateGroup(node.children, node.position)
is PtBuiltinFunctionCall -> translateBuiltinFunc(node, 0)
is PtFunctionCall -> expressionEval.translate(node, 0, 0)
is PtNop -> VmCodeChunk()
is PtNop -> VmCodeChunk(node.position)
is PtReturn -> translate(node)
is PtJump -> translate(node)
is PtWhen -> translate(node)
@ -101,11 +100,11 @@ class CodeGen(internal val program: PtProgram,
is PtIfElse -> translate(node)
is PtPostIncrDecr -> translate(node)
is PtRepeatLoop -> translate(node)
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT))
is PtLabel -> VmCodeChunk(node.position, VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(node.position, VmCodeInstruction(Opcode.BREAKPOINT))
is PtConditionalBranch -> translate(node)
is PtInlineAssembly -> VmCodeChunk(VmCodeInlineAsm(node.assembly))
is PtIncludeBinary -> VmCodeChunk(VmCodeInlineBinary(node.file, node.offset, node.length))
is PtInlineAssembly -> VmInlineAsmChunk(node.assembly, node.position)
is PtIncludeBinary -> VmCodeChunk(node.position, VmCodeInlineBinary(node.file, node.offset, node.length))
is PtAddressOf,
is PtContainmentCheck,
is PtMemoryByte,
@ -121,16 +120,15 @@ class CodeGen(internal val program: PtProgram,
is PtSubroutineParameter,
is PtNumber,
is PtArray,
is PtBlock,
is PtString -> throw AssemblyError("should not occur as separate statement node ${node.position}")
else -> TODO("missing codegen for $node")
}
if(code.lines.isNotEmpty() && node.position.line!=0)
code.lines.add(0, VmCodeComment(node.position.toString()))
return code
}
private fun translate(branch: PtConditionalBranch): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(branch.position)
val elseLabel = createLabelName()
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
code += when(branch.condition) {
@ -157,9 +155,9 @@ class CodeGen(internal val program: PtProgram,
}
private fun translate(whenStmt: PtWhen): VmCodeChunk {
val code = VmCodeChunk(whenStmt.position)
if(whenStmt.choices.children.isEmpty())
return VmCodeChunk()
val code = VmCodeChunk()
return code
val valueReg = vmRegisters.nextFree()
val choiceReg = vmRegisters.nextFree()
val valueDt = vmType(whenStmt.value.type)
@ -200,7 +198,7 @@ class CodeGen(internal val program: PtProgram,
private fun translate(forLoop: PtForLoop): VmCodeChunk {
val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable
val iterable = forLoop.iterable
val code = VmCodeChunk()
val code = VmCodeChunk(forLoop.position)
when(iterable) {
is PtRange -> {
if(iterable.from is PtNumber && iterable.to is PtNumber)
@ -240,7 +238,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
code += translateNode(forLoop.statements)
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
code += VmCodeInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
} else if(lengthBytes==256) {
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
@ -248,7 +246,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
code += translateNode(forLoop.statements)
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
code += addConstReg(VmDataType.BYTE, indexReg, elementSize, iterable.position)
code += VmCodeInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
} else {
throw AssemblyError("iterator length should never exceed 256")
@ -270,14 +268,14 @@ class CodeGen(internal val program: PtProgram,
val loopvarAddress = allocations.get(loopvar.scopedName)
val loopvarDt = vmType(loopvar.dt)
val loopLabel = createLabelName()
val code = VmCodeChunk()
val code = VmCodeChunk(forLoop.position)
code += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
code += expressionEval.translateExpression(iterable.from, indexReg, -1)
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
code += VmCodeLabel(loopLabel)
code += translateNode(forLoop.statements)
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step)
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step, iterable.position)
code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
@ -298,7 +296,7 @@ class CodeGen(internal val program: PtProgram,
if(step>0 && rangeEndUntyped<rangeStart || step<0 && rangeEndUntyped>rangeStart)
throw AssemblyError("empty range")
val rangeEndWrapped = if(loopvarDt==VmDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535
val code = VmCodeChunk()
val code = VmCodeChunk(forLoop.position)
val endvalueReg: Int
if(rangeEndWrapped!=0) {
endvalueReg = vmRegisters.nextFree()
@ -310,7 +308,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
code += VmCodeLabel(loopLabel)
code += translateNode(forLoop.statements)
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step)
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step, iterable.position)
code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
code += if(rangeEndWrapped==0) {
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
@ -320,8 +318,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun addConstReg(dt: VmDataType, reg: Int, value: Int): VmCodeChunk {
val code = VmCodeChunk()
private fun addConstReg(dt: VmDataType, reg: Int, value: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
when(value) {
0 -> { /* do nothing */ }
1 -> {
@ -349,8 +347,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun addConstMem(dt: VmDataType, address: UInt, value: Int): VmCodeChunk {
val code = VmCodeChunk()
private fun addConstMem(dt: VmDataType, address: UInt, value: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
when(value) {
0 -> { /* do nothing */ }
1 -> {
@ -382,8 +380,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun multiplyByConstFloat(fpReg: Int, factor: Float): VmCodeChunk {
val code = VmCodeChunk()
internal fun multiplyByConstFloat(fpReg: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1f)
return code
code += if(factor==0f) {
@ -394,8 +392,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun multiplyByConstFloatInplace(address: Int, factor: Float): VmCodeChunk {
val code = VmCodeChunk()
internal fun multiplyByConstFloatInplace(address: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1f)
return code
if(factor==0f) {
@ -410,8 +408,8 @@ class CodeGen(internal val program: PtProgram,
internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk {
val code = VmCodeChunk()
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
@ -434,8 +432,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int): VmCodeChunk {
val code = VmCodeChunk()
internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
@ -461,8 +459,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun divideByConstFloat(fpReg: Int, factor: Float): VmCodeChunk {
val code = VmCodeChunk()
internal fun divideByConstFloat(fpReg: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1f)
return code
code += if(factor==0f) {
@ -473,8 +471,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun divideByConstFloatInplace(address: Int, factor: Float): VmCodeChunk {
val code = VmCodeChunk()
internal fun divideByConstFloatInplace(address: Int, factor: Float, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1f)
return code
if(factor==0f) {
@ -489,8 +487,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean): VmCodeChunk {
val code = VmCodeChunk()
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
@ -518,8 +516,8 @@ class CodeGen(internal val program: PtProgram,
return code
}
internal fun divideByConstInplace(dt: VmDataType, address: Int, factor: Int, signed: Boolean): VmCodeChunk {
val code = VmCodeChunk()
internal fun divideByConstInplace(dt: VmDataType, address: Int, factor: Int, signed: Boolean, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
if(factor==1)
return code
val pow2 = powersOfTwo.indexOf(factor)
@ -558,7 +556,7 @@ class CodeGen(internal val program: PtProgram,
val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
val vmDt = vmType(ifElse.condition.left.type)
val code = VmCodeChunk()
val code = VmCodeChunk(ifElse.position)
fun translateNonZeroComparison(): VmCodeChunk {
val elseBranch = when(ifElse.condition.operator) {
@ -643,7 +641,7 @@ class CodeGen(internal val program: PtProgram,
private fun translate(postIncrDecr: PtPostIncrDecr): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(postIncrDecr.position)
val operationMem: Opcode
val operationRegister: Opcode
when(postIncrDecr.operator) {
@ -700,15 +698,15 @@ class CodeGen(internal val program: PtProgram,
private fun translate(repeat: PtRepeatLoop): VmCodeChunk {
when (constIntValue(repeat.count)) {
0 -> return VmCodeChunk()
1 -> return translateGroup(repeat.children)
0 -> return VmCodeChunk(repeat.position)
1 -> return translateGroup(repeat.children, repeat.position)
256 -> {
// 256 iterations can still be done with just a byte counter if you set it to zero as starting value.
repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position)
}
}
val code = VmCodeChunk()
val code = VmCodeChunk(repeat.position)
val counterReg = vmRegisters.nextFree()
val vmDt = vmType(repeat.count.type)
code += expressionEval.translateExpression(repeat.count, counterReg, -1)
@ -721,7 +719,7 @@ class CodeGen(internal val program: PtProgram,
}
private fun translate(jump: PtJump): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(jump.position)
if(jump.address!=null)
throw AssemblyError("cannot jump to memory location in the vm target")
code += if(jump.generatedLabel!=null)
@ -733,14 +731,14 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun translateGroup(group: List<PtNode>): VmCodeChunk {
val code = VmCodeChunk()
private fun translateGroup(group: List<PtNode>, position: Position): VmCodeChunk {
val code = VmCodeChunk(position)
group.forEach { code += translateNode(it) }
return code
}
private fun translate(ret: PtReturn): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(ret.position)
val value = ret.value
if(value!=null) {
// Call Convention: return value is always returned in r0 (or fr0 if float)
@ -753,33 +751,39 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun translate(sub: PtSub): VmCodeChunk {
val code = VmCodeChunk()
code += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
code += VmCodeLabel(sub.scopedName)
private fun translate(sub: PtSub): VmSubroutine {
val vmsub = VmSubroutine(sub.scopedName, sub.returntype, sub.position)
vmsub += VmCodeLabel(sub.scopedName)
for (child in sub.children) {
code += translateNode(child)
vmsub += translateNode(child)
}
code += VmCodeComment("SUB-END '${sub.name}'")
return code
return vmsub
}
private fun translate(sub: PtAsmSub): VmCodeChunk {
val code = VmCodeChunk()
code += VmCodeComment("ASMSUB: ${sub.scopedName}")
code += VmCodeLabel(sub.scopedName)
private fun translate(sub: PtAsmSub): VmAsmSubroutine {
val vmsub = VmAsmSubroutine(sub.scopedName, sub.position)
vmsub += VmCodeLabel(sub.scopedName)
for (child in sub.children) {
code += translateNode(child)
vmsub += translateNode(child)
}
code += VmCodeComment("ASMSUB-END '${sub.name}'")
return code
return vmsub
}
private fun translate(block: PtBlock): VmBlock {
val vmblock = VmBlock(block.name, block.address, block.alignment) // no use for other attributes yet?
val vmblock = VmBlock(block.name, block.address, block.alignment, block.position) // no use for other attributes yet?
for (child in block.children) {
if(child !is PtAssignment) // global variable initialization is done elsewhere
vmblock += translateNode(child)
when(child) {
is PtNop -> { /* nothing */ }
is PtAssignment -> { /* global variable initialization is done elsewhere */ }
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
is PtSub -> vmblock += translateNode(child)
is PtAsmSub -> vmblock += translateNode(child)
is PtInlineAssembly -> vmblock += translateNode(child)
else -> {
println("BLOCK: TRANSLATING WEIRD THING $child")
vmblock += translateNode(child)
}
}
}
return vmblock
}

View File

@ -13,7 +13,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
require(codeGen.vmRegisters.peekNext() > resultRegister)
val code = VmCodeChunk()
val code = VmCodeChunk(expr.position)
when (expr) {
is PtMachineRegister -> {
@ -73,7 +73,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(check.position)
code += translateExpression(check.element, resultRegister, -1) // load the element to check in resultRegister
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
when(iterable.dt) {
@ -106,7 +106,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type)
val vmDt = codeGen.vmType(arrayIx.type)
val code = VmCodeChunk()
val code = VmCodeChunk(arrayIx.position)
val idxReg = codeGen.vmRegisters.nextFree()
val arrayLocation = codeGen.allocations.get(arrayIx.variable.targetName)
@ -131,7 +131,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} else {
code += translateExpression(arrayIx.index, idxReg, -1)
if(eltSize>1)
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize)
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize, arrayIx.position)
if(vmDt==VmDataType.FLOAT)
code += VmCodeInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, value = arrayLocation)
else
@ -141,7 +141,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun translate(expr: PtPrefix, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(expr.position)
code += translateExpression(expr.value, resultRegister, -1)
val vmDt = codeGen.vmType(expr.type)
when(expr.operator) {
@ -159,7 +159,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun translate(cast: PtTypeCast, predefinedResultRegister: Int, predefinedResultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(cast.position)
if(cast.type==cast.value.type)
return code
val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.vmRegisters.nextFreeFloat()
@ -272,7 +272,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
signed: Boolean,
greaterEquals: Boolean
): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
@ -321,7 +321,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
signed: Boolean,
lessEquals: Boolean
): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
@ -364,7 +364,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, notEquals: Boolean): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
@ -402,7 +402,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(codeGen.isOne(binExpr.right)) {
code += translateExpression(binExpr.left, resultRegister, -1)
val opc = if (signed) Opcode.ASR else Opcode.LSR
@ -418,7 +418,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorShiftRightInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
if(codeGen.isOne(operand)) {
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
code += VmCodeInstruction(opc, vmDt, value=address)
@ -432,7 +432,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(codeGen.isOne(binExpr.right)){
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister)
@ -446,7 +446,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorShiftLeftInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
if(codeGen.isOne(operand)){
code += VmCodeInstruction(Opcode.LSLM, vmDt, value=address)
} else {
@ -458,7 +458,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorXor(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
@ -472,7 +472,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorXorInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = address)
@ -480,7 +480,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
@ -494,7 +494,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorAndInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=address)
@ -502,7 +502,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorOr(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
code += VmCodeInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
@ -516,7 +516,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorOrInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
code += VmCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = address)
@ -526,7 +526,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): VmCodeChunk {
if(vmDt==VmDataType.FLOAT)
throw IllegalArgumentException("floating-point modulo not supported")
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
val rightResultReg = codeGen.vmRegisters.nextFree()
if(binExpr.right is PtNumber) {
code += translateExpression(binExpr.left, resultRegister, -1)
@ -544,13 +544,13 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
resultRegister: Int,
resultFpRegister: Int,
signed: Boolean): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
val constFactorRight = binExpr.right as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
val factor = constFactorRight.number.toFloat()
code += codeGen.divideByConstFloat(resultFpRegister, factor)
code += codeGen.divideByConstFloat(resultFpRegister, factor, binExpr.position)
} else {
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, resultFpRegister)
@ -564,7 +564,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
code += translateExpression(binExpr.left, resultRegister, -1)
val factor = constFactorRight.number.toInt()
code += codeGen.divideByConst(vmDt, resultRegister, factor, signed)
code += codeGen.divideByConst(vmDt, resultRegister, factor, signed, binExpr.position)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
if(binExpr.right is PtNumber) {
@ -587,12 +587,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorDivideInplace(address: Int, vmDt: VmDataType, signed: Boolean, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
val constFactorRight = operand as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val factor = constFactorRight.number.toFloat()
code += codeGen.divideByConstFloatInplace(address, factor)
code += codeGen.divideByConstFloatInplace(address, factor, operand.position)
} else {
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(operand, -1, operandFpReg)
@ -604,7 +604,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val factor = constFactorRight.number.toInt()
code += codeGen.divideByConstInplace(vmDt, address, factor, signed)
code += codeGen.divideByConstInplace(vmDt, address, factor, signed, operand.position)
} else {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
@ -618,18 +618,18 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
val constFactorLeft = binExpr.left as? PtNumber
val constFactorRight = binExpr.right as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorLeft!=null) {
code += translateExpression(binExpr.right, -1, resultFpRegister)
val factor = constFactorLeft.number.toFloat()
code += codeGen.multiplyByConstFloat(resultFpRegister, factor)
code += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorLeft.position)
} else if(constFactorRight!=null) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
val factor = constFactorRight.number.toFloat()
code += codeGen.multiplyByConstFloat(resultFpRegister, factor)
code += codeGen.multiplyByConstFloat(resultFpRegister, factor, constFactorRight.position)
} else {
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(binExpr.left, -1, resultFpRegister)
@ -640,11 +640,11 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
code += translateExpression(binExpr.right, resultRegister, -1)
val factor = constFactorLeft.number.toInt()
code += codeGen.multiplyByConst(vmDt, resultRegister, factor)
code += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorLeft.position)
} else if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
code += translateExpression(binExpr.left, resultRegister, -1)
val factor = constFactorRight.number.toInt()
code += codeGen.multiplyByConst(vmDt, resultRegister, factor)
code += codeGen.multiplyByConst(vmDt, resultRegister, factor, constFactorRight.position)
} else {
val rightResultReg = codeGen.vmRegisters.nextFree()
code += translateExpression(binExpr.left, resultRegister, -1)
@ -656,12 +656,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorMultiplyInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
val constFactorRight = operand as? PtNumber
if(vmDt==VmDataType.FLOAT) {
if(constFactorRight!=null) {
val factor = constFactorRight.number.toFloat()
code += codeGen.multiplyByConstFloatInplace(address, factor)
code += codeGen.multiplyByConstFloatInplace(address, factor, constFactorRight.position)
} else {
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
code += translateExpression(operand, -1, operandFpReg)
@ -670,7 +670,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
} else {
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
val factor = constFactorRight.number.toInt()
code += codeGen.multiplyByConstInplace(vmDt, address, factor)
code += codeGen.multiplyByConstInplace(vmDt, address, factor, constFactorRight.position)
} else {
val operandReg = codeGen.vmRegisters.nextFree()
code += translateExpression(operand, operandReg, -1)
@ -681,7 +681,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
if((binExpr.right as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.left, -1, resultFpRegister)
@ -719,7 +719,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorMinusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
if(vmDt==VmDataType.FLOAT) {
if((operand as? PtNumber)?.number==1.0) {
code += VmCodeInstruction(Opcode.DECM, vmDt, value=address)
@ -743,7 +743,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(binExpr.position)
if(vmDt==VmDataType.FLOAT) {
if((binExpr.left as? PtNumber)?.number==1.0) {
code += translateExpression(binExpr.right, -1, resultFpRegister)
@ -789,7 +789,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
internal fun operatorPlusInplace(address: Int, vmDt: VmDataType, operand: PtExpression): VmCodeChunk {
val code = VmCodeChunk()
val code = VmCodeChunk(operand.position)
if(vmDt==VmDataType.FLOAT) {
if((operand as? PtNumber)?.number==1.0) {
code += VmCodeInstruction(Opcode.INCM, vmDt, value = address)
@ -815,7 +815,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): VmCodeChunk {
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.functionName)) {
is StSub -> {
val code = VmCodeChunk()
val code = VmCodeChunk(fcall.position)
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
val paramDt = codeGen.vmType(parameter.type)
if(codeGen.isZero(arg)) {

View File

@ -7,37 +7,46 @@ import prog8.vm.VmDataType
class IRPeepholeOptimizer(private val vmprog: IRProgram) {
fun optimize() {
vmprog.getBlocks().forEach { block ->
do {
val indexedInstructions = block.lines.withIndex()
.filter { it.value is VmCodeInstruction }
.map { IndexedValue(it.index, (it.value as VmCodeInstruction).ins) }
val changed = removeNops(block, indexedInstructions)
|| removeDoubleLoadsAndStores(block, indexedInstructions) // TODO not yet implemented
|| removeUselessArithmetic(block, indexedInstructions)
|| removeWeirdBranches(block, indexedInstructions)
|| removeDoubleSecClc(block, indexedInstructions)
|| cleanupPushPop(block, indexedInstructions)
// TODO other optimizations:
// more complex optimizations such as unused registers
} while(changed)
vmprog.blocks.forEach { block ->
block.children.forEach { child ->
when(child) {
is VmCodeChunk -> {
do {
val indexedInstructions = child.lines.withIndex()
.filter { it.value is VmCodeInstruction }
.map { IndexedValue(it.index, (it.value as VmCodeInstruction).ins) }
val changed = removeNops(child, indexedInstructions)
|| removeDoubleLoadsAndStores(child, indexedInstructions) // TODO not yet implemented
|| removeUselessArithmetic(child, indexedInstructions)
|| removeWeirdBranches(child, indexedInstructions)
|| removeDoubleSecClc(child, indexedInstructions)
|| cleanupPushPop(child, indexedInstructions)
// TODO other optimizations:
// more complex optimizations such as unused registers
} while (changed)
}
else -> {
TODO("block child $child")
}
}
}
}
}
private fun cleanupPushPop(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun cleanupPushPop(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// push followed by pop to same target, or different target->replace with load
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode==Opcode.PUSH) {
if(idx < block.lines.size-1) {
val insAfter = block.lines[idx+1] as? VmCodeInstruction
if(idx < chunk.lines.size-1) {
val insAfter = chunk.lines[idx+1] as? VmCodeInstruction
if(insAfter!=null && insAfter.ins.opcode ==Opcode.POP) {
if(ins.reg1==insAfter.ins.reg1) {
block.lines.removeAt(idx)
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
chunk.lines.removeAt(idx)
} else {
block.lines[idx] = VmCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1)
block.lines.removeAt(idx+1)
chunk.lines[idx] = VmCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1)
chunk.lines.removeAt(idx+1)
}
changed = true
}
@ -47,25 +56,24 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeDoubleSecClc(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeDoubleSecClc(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// double sec, clc
// sec+clc or clc+sec
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode==Opcode.SEC || ins.opcode==Opcode.CLC) {
if(idx < block.lines.size-1) {
val insAfter = block.lines[idx+1] as? VmCodeInstruction
if(idx < chunk.lines.size-1) {
val insAfter = chunk.lines[idx+1] as? VmCodeInstruction
if(insAfter?.ins?.opcode == ins.opcode) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
else if(ins.opcode==Opcode.SEC && insAfter?.ins?.opcode==Opcode.CLC) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
else if(ins.opcode==Opcode.CLC && insAfter?.ins?.opcode==Opcode.SEC) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
}
@ -74,16 +82,16 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeWeirdBranches(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeWeirdBranches(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// jump/branch to label immediately below
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if(ins.opcode==Opcode.JUMP && ins.labelSymbol!=null) {
// if jumping to label immediately following this
if(idx < block.lines.size-1) {
val label = block.lines[idx+1] as? VmCodeLabel
if(idx < chunk.lines.size-1) {
val label = chunk.lines[idx+1] as? VmCodeLabel
if(label?.name == ins.labelSymbol) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
}
@ -92,54 +100,54 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeUselessArithmetic(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeUselessArithmetic(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
when (ins.opcode) {
Opcode.DIV, Opcode.DIVS, Opcode.MUL, Opcode.MOD -> {
if (ins.value == 1) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
}
Opcode.ADD, Opcode.SUB -> {
if (ins.value == 1) {
block.lines[idx] = VmCodeInstruction(
chunk.lines[idx] = VmCodeInstruction(
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
ins.type,
ins.reg1
)
changed = true
} else if (ins.value == 0) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
}
Opcode.AND -> {
if (ins.value == 0) {
block.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
chunk.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
changed = true
} else if (ins.value == 255 && ins.type == VmDataType.BYTE) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
} else if (ins.value == 65535 && ins.type == VmDataType.WORD) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
}
Opcode.OR -> {
if (ins.value == 0) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
} else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) {
block.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
chunk.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
changed = true
}
}
Opcode.XOR -> {
if (ins.value == 0) {
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
changed = true
}
}
@ -149,18 +157,18 @@ class IRPeepholeOptimizer(private val vmprog: IRProgram) {
return changed
}
private fun removeNops(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeNops(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if (ins.opcode == Opcode.NOP) {
changed = true
block.lines.removeAt(idx)
chunk.lines.removeAt(idx)
}
}
return changed
}
private fun removeDoubleLoadsAndStores(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
private fun removeDoubleLoadsAndStores(chunk: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
var changed = false
indexedInstructions.forEach { (idx, ins) ->

View File

@ -20,8 +20,8 @@ class IRProgram(val name: String,
private val encoding: IStringEncoding,
private val st: SymbolTable) {
private val globalInits = mutableListOf<VmCodeLine>()
private val blocks = mutableListOf<VmBlock>()
val globalInits = mutableListOf<VmCodeLine>()
val blocks = mutableListOf<VmBlock>()
fun writeFile() {
val outfile = options.outputDir / ("$name.p8ir")
@ -34,23 +34,52 @@ class IRProgram(val name: String,
if(!options.dontReinitGlobals) {
// note: this a block of code that loads values and stores them into the global variables to reset their values.
out.write("\n[INITGLOBALS]\n")
out.write("\n<INITGLOBALS>\n")
globalInits.forEach { out.writeLine(it) }
out.write("[/INITGLOBALS]\n")
out.write("</INITGLOBALS>\n")
}
out.write("\n[CODE]\n")
blocks.forEach { block ->
out.write("\n[BLOCK NAME=${block.name} ADDRESS=${block.address} ALIGN=${block.alignment}]\n")
block.lines.forEach { out.writeLine(it) }
out.write("[/BLOCK]\n")
out.write("\n<PROGRAM>\n")
writeBlocks(out)
out.write("</PROGRAM>\n")
}
}
private fun writeBlocks(out: BufferedWriter) {
blocks.forEach { block ->
out.write("\n<BLOCK NAME=${block.name} ADDRESS=${block.address} ALIGN=${block.alignment} POS=${block.position}>\n")
block.children.forEach {
when(it) {
is VmSubroutine -> {
out.write("<SUB ${it.scopedName.joinToString(".")} returntype=${it.returnType} POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</SUB>\n")
}
is VmAsmSubroutine -> {
out.write("<ASMSUB ${it.scopedName.joinToString(".")} POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</ASMSUB>\n")
}
is VmInlineAsmChunk -> {
out.write("<INLINEASM POS=${it.position}>\n")
it.lines.forEach { line -> out.writeLine(line) }
out.write("</INLINEASM>\n")
}
is VmCodeChunk -> {
println("GENERIC CHUNK IN BLOCK $it ${it.position}") // TODO must all be VmSubroutine
it.lines.forEach { line -> out.writeLine(line) }
}
else -> {
TODO("BLOCK CHILD $it")
}
}
}
out.write("[/CODE]\n")
out.write("</BLOCK>\n")
}
}
private fun writeOptions(out: BufferedWriter) {
out.write("[OPTIONS]\n")
out.write("<OPTIONS>\n")
out.write("compTarget = ${options.compTarget.name}\n")
out.write("output = ${options.output}\n")
out.write("launcher = ${options.launcher}\n")
@ -60,11 +89,11 @@ class IRProgram(val name: String,
out.write("dontReinitGlobals = ${options.dontReinitGlobals}\n")
out.write("evalStackBaseAddress = ${options.evalStackBaseAddress}\n")
// other options not yet useful here?
out.write("[/OPTIONS]\n")
out.write("</OPTIONS>\n")
}
private fun writeVariableAllocations(out: Writer) {
out.write("\n[VARIABLES]\n")
out.write("\n<VARIABLES>\n")
for (variable in st.allVariables) {
val typeStr = when(variable.dt) {
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
@ -100,9 +129,9 @@ class IRProgram(val name: String,
// TODO have uninitialized variables? (BSS SECTION)
out.write("VAR ${variable.scopedName.joinToString(".")} $typeStr = $value\n")
}
out.write("[/VARIABLES]\n")
out.write("</VARIABLES>\n")
out.write("\n[MEMORYMAPPEDVARIABLES]\n")
out.write("\n<MEMORYMAPPEDVARIABLES>\n")
for (variable in st.allMemMappedVariables) {
val typeStr = when(variable.dt) {
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
@ -114,11 +143,11 @@ class IRProgram(val name: String,
}
out.write("MAP ${variable.scopedName.joinToString(".")} $typeStr ${variable.address}\n")
}
out.write("[/MEMORYMAPPEDVARIABLES]\n")
out.write("</MEMORYMAPPEDVARIABLES>\n")
out.write("\n[MEMORYSLABS]\n")
out.write("\n<MEMORYSLABS>\n")
st.allMemorySlabs.forEach{ slab -> out.write("SLAB _${slab.name} ${slab.size} ${slab.align}\n") }
out.write("[/MEMORYSLABS]\n")
out.write("</MEMORYSLABS>\n")
}
private fun BufferedWriter.writeLine(line: VmCodeLine) {
@ -128,7 +157,7 @@ class IRProgram(val name: String,
write(line.ins.toString() + "\n")
}
is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
is VmCodeInlineAsm -> {
is VmInlineAsm -> {
// TODO FIXUP ASM SYMBOLS???
write(line.assembly+"\n")
}
@ -146,7 +175,6 @@ class IRProgram(val name: String,
fun addGlobalInits(chunk: VmCodeChunk) = globalInits.addAll(chunk.lines)
fun addBlock(block: VmBlock) = blocks.add(block)
fun getBlocks(): List<VmBlock> = blocks
}
sealed class VmCodeLine
@ -191,18 +219,32 @@ class VmCodeInstruction(
}
class VmCodeLabel(val name: List<String>): VmCodeLine()
internal class VmCodeComment(val comment: String): VmCodeLine()
class VmCodeComment(val comment: String): VmCodeLine()
class VmBlock(
val name: String,
val address: UInt?,
val alignment: PtBlock.BlockAlignment,
initial: VmCodeLine? = null
): VmCodeChunk(initial)
val position: Position
) {
val children = mutableListOf<VmCodeChunk>()
operator fun plusAssign(child: VmCodeChunk) {
children += child
}
}
open class VmCodeChunk(initial: VmCodeLine? = null) {
class VmSubroutine(val scopedName: List<String>,
val returnType: DataType?,
position: Position,
initial: VmCodeLine? = null): VmCodeChunk(position, initial)
class VmAsmSubroutine(val scopedName: List<String>,
position: Position,
initial: VmCodeLine? = null): VmCodeChunk(position, initial)
open class VmCodeChunk(val position: Position, initial: VmCodeLine? = null) {
val lines = mutableListOf<VmCodeLine>()
init {
@ -219,9 +261,12 @@ open class VmCodeChunk(initial: VmCodeLine? = null) {
}
}
internal class VmCodeInlineAsm(asm: String): VmCodeLine() {
class VmInlineAsmChunk(asm: String, position: Position): VmCodeChunk(position, VmInlineAsm(asm))
class VmInlineAsm(asm: String): VmCodeLine() {
// TODO INLINE ASSEMBLY IN IL CODE
val assembly: String = "; TODO INLINE ASSMBLY IN IL CODE" // was: asm.trimIndent()
val assembly: String = "; TODO INLINE ASSEMBLY IN IL CODE" // was: asm.trimIndent()
}
internal class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine()
class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine()

View File

@ -445,10 +445,8 @@ internal fun asmGeneratorFor(program: Program,
options: CompilationOptions): IAssemblyGenerator
{
if(options.experimentalCodegen) {
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) {
val intermediateAst = IntermediateAstMaker(program).transform()
return prog8.codegen.experimental.CodeGen(intermediateAst, symbolTable, options, errors)
}
val intermediateAst = IntermediateAstMaker(program).transform()
return prog8.codegen.experimental.CodeGen(intermediateAst, symbolTable, options, errors)
} else {
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
// TODO rewrite 6502 codegen on new Intermediary Ast or on new Intermediate Representation