mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
block structure
This commit is contained in:
parent
a182b13e5a
commit
b0704e86f0
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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) ->
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user