mirror of
https://github.com/irmen/prog8.git
synced 2026-04-19 20:16:51 +00:00
refactor IR codegen into separate module
This commit is contained in:
@@ -26,7 +26,7 @@ compileTestKotlin {
|
||||
dependencies {
|
||||
implementation project(':codeCore')
|
||||
implementation project(':intermediate')
|
||||
implementation project(':virtualmachine')
|
||||
implementation project(':codeGenIntermediate')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
<orderEntry type="module" module-name="codeCore" />
|
||||
<orderEntry type="module" module-name="virtualmachine" />
|
||||
<orderEntry type="module" module-name="codeGenIntermediate" />
|
||||
<orderEntry type="module" module-name="intermediate" />
|
||||
<orderEntry type="module" module-name="codeCore" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,294 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.core.SignedDatatypes
|
||||
import prog8.intermediate.IRCodeChunk
|
||||
import prog8.intermediate.IRCodeInstruction
|
||||
import prog8.intermediate.Opcode
|
||||
import prog8.intermediate.VmDataType
|
||||
|
||||
internal class AssignmentGen(private val codeGen: CodeGen, private val expressionEval: ExpressionGen) {
|
||||
|
||||
internal fun translate(assignment: PtAssignment): IRCodeChunk {
|
||||
if(assignment.target.children.single() is PtMachineRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
|
||||
return if (assignment.isInplaceAssign)
|
||||
translateInplaceAssign(assignment)
|
||||
else
|
||||
translateRegularAssign(assignment)
|
||||
}
|
||||
|
||||
private fun translateInplaceAssign(assignment: PtAssignment): IRCodeChunk {
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
|
||||
return if(ident!=null) {
|
||||
assignSelfInMemory(ident.targetName.joinToString("."), assignment.value, assignment)
|
||||
} else if(memory != null) {
|
||||
if(memory.address is PtNumber)
|
||||
assignSelfInMemoryKnownAddress((memory.address as PtNumber).number.toInt(), assignment.value, assignment)
|
||||
else
|
||||
fallbackAssign(assignment)
|
||||
} else if(array!=null) {
|
||||
// NOTE: naive fallback assignment here will sometimes generate code that loads the index value multiple times
|
||||
// in a register. It's way too much work to optimize that here - instead, we trust that the generated IL assembly
|
||||
// will be optimized later and have the double assignments removed.
|
||||
fallbackAssign(assignment)
|
||||
} else {
|
||||
fallbackAssign(assignment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignSelfInMemoryKnownAddress(
|
||||
address: Int,
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(value.type)
|
||||
val code = IRCodeChunk(origAssign.position)
|
||||
when(value) {
|
||||
is PtIdentifier -> return code // do nothing, x=x null assignment.
|
||||
is PtMachineRegister -> return code // do nothing, reg=reg null assignment
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, address, null, value.position)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, null, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
return if (!codeGen.options.compTarget.machine.isIOAddress(address.toUInt()))
|
||||
code // do nothing, mem=mem null assignment.
|
||||
else {
|
||||
// read and write a (i/o) memory location to itself.
|
||||
val tempReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
|
||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
|
||||
code
|
||||
}
|
||||
}
|
||||
else -> return fallbackAssign(origAssign)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignSelfInMemory(
|
||||
symbol: String,
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(value.type)
|
||||
val code = IRCodeChunk(origAssign.position)
|
||||
when(value) {
|
||||
is PtIdentifier -> return code // do nothing, x=x null assignment.
|
||||
is PtMachineRegister -> return code // do nothing, reg=reg null assignment
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, null, symbol, value.position)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
val tempReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
return code
|
||||
}
|
||||
else -> return fallbackAssign(origAssign)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fallbackAssign(origAssign: PtAssignment): IRCodeChunk {
|
||||
if (codeGen.options.slowCodegenWarnings)
|
||||
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
|
||||
return translateRegularAssign(origAssign)
|
||||
}
|
||||
|
||||
private fun inplaceBinexpr(
|
||||
operator: String,
|
||||
operand: PtExpression,
|
||||
vmDt: VmDataType,
|
||||
signed: Boolean,
|
||||
knownAddress: Int?,
|
||||
symbol: String?,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
if(knownAddress!=null) {
|
||||
when (operator) {
|
||||
"+" -> return expressionEval.operatorPlusInplace(knownAddress, null, vmDt, operand)
|
||||
"-" -> return expressionEval.operatorMinusInplace(knownAddress, null, vmDt, operand)
|
||||
"*" -> return expressionEval.operatorMultiplyInplace(knownAddress, null, vmDt, operand)
|
||||
"/" -> return expressionEval.operatorDivideInplace(knownAddress, null, vmDt, signed, operand)
|
||||
"|" -> return expressionEval.operatorOrInplace(knownAddress, null, vmDt, operand)
|
||||
"&" -> return expressionEval.operatorAndInplace(knownAddress, null, vmDt, operand)
|
||||
"^" -> return expressionEval.operatorXorInplace(knownAddress, null, vmDt, operand)
|
||||
"<<" -> return expressionEval.operatorShiftLeftInplace(knownAddress, null, vmDt, operand)
|
||||
">>" -> return expressionEval.operatorShiftRightInplace(knownAddress, null, vmDt, signed, operand)
|
||||
else -> {}
|
||||
}
|
||||
} else {
|
||||
symbol!!
|
||||
when (operator) {
|
||||
"+" -> return expressionEval.operatorPlusInplace(null, symbol, vmDt, operand)
|
||||
"-" -> return expressionEval.operatorMinusInplace(null, symbol, vmDt, operand)
|
||||
"*" -> return expressionEval.operatorMultiplyInplace(null, symbol, vmDt, operand)
|
||||
"/" -> return expressionEval.operatorDivideInplace(null, symbol, vmDt, signed, operand)
|
||||
"|" -> return expressionEval.operatorOrInplace(null, symbol, vmDt, operand)
|
||||
"&" -> return expressionEval.operatorAndInplace(null, symbol, vmDt, operand)
|
||||
"^" -> return expressionEval.operatorXorInplace(null, symbol, vmDt, operand)
|
||||
"<<" -> return expressionEval.operatorShiftLeftInplace(null, symbol, vmDt, operand)
|
||||
">>" -> return expressionEval.operatorShiftRightInplace(null, symbol, vmDt, signed, operand)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return fallbackAssign(origAssign)
|
||||
}
|
||||
|
||||
private fun inplacePrefix(operator: String, vmDt: VmDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunk {
|
||||
val code= IRCodeChunk(position)
|
||||
when(operator) {
|
||||
"+" -> { }
|
||||
"-" -> {
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.NEGM, vmDt, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.NEGM, vmDt, labelSymbol = addressSymbol)
|
||||
}
|
||||
"~" -> {
|
||||
val regMask = codeGen.vmRegisters.nextFree()
|
||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, labelSymbol = addressSymbol)
|
||||
}
|
||||
else -> throw AssemblyError("weird prefix operator")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunk {
|
||||
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
val vmDt = codeGen.vmType(assignment.value.type)
|
||||
|
||||
val code = IRCodeChunk(assignment.position)
|
||||
var resultRegister = -1
|
||||
var resultFpRegister = -1
|
||||
val zero = codeGen.isZero(assignment.value)
|
||||
if(!zero) {
|
||||
// calculate the assignment value
|
||||
if (vmDt == VmDataType.FLOAT) {
|
||||
resultFpRegister = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += expressionEval.translateExpression(assignment.value, -1, resultFpRegister)
|
||||
} else {
|
||||
resultRegister = if (assignment.value is PtMachineRegister) {
|
||||
(assignment.value as PtMachineRegister).register
|
||||
} else {
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(assignment.value, reg, -1)
|
||||
reg
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ident!=null) {
|
||||
val symbol = ident.targetName.joinToString(".")
|
||||
code += if(zero) {
|
||||
IRCodeInstruction(Opcode.STOREZM, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
if (vmDt == VmDataType.FLOAT)
|
||||
IRCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
||||
else
|
||||
IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
else if(array!=null) {
|
||||
val variable = array.variable.targetName.joinToString(".")
|
||||
val itemsize = codeGen.program.memsizer.memorySize(array.type)
|
||||
|
||||
if(array.variable.type==DataType.UWORD) {
|
||||
// indexing a pointer var instead of a real array or string
|
||||
if(itemsize!=1)
|
||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
||||
if(array.index.type!=DataType.UBYTE)
|
||||
throw AssemblyError("non-array var indexing requires bytes index")
|
||||
val idxReg = codeGen.vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, idxReg, -1)
|
||||
if(zero) {
|
||||
// there's no STOREZIX instruction
|
||||
resultRegister = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
|
||||
}
|
||||
code += IRCodeInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = variable)
|
||||
return code
|
||||
}
|
||||
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
if(zero) {
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRCodeInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRCodeInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable)
|
||||
}
|
||||
} else {
|
||||
if(vmDt== VmDataType.FLOAT) {
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
}
|
||||
} else {
|
||||
if(fixedIndex!=null) {
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(memory!=null) {
|
||||
require(vmDt== VmDataType.BYTE)
|
||||
if(zero) {
|
||||
if(memory.address is PtNumber) {
|
||||
code += IRCodeInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
||||
}
|
||||
} else {
|
||||
if(memory.address is PtNumber) {
|
||||
code += IRCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
throw AssemblyError("weird assigntarget")
|
||||
return code
|
||||
}
|
||||
|
||||
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
if(itemsize==1) {
|
||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
}
|
||||
else {
|
||||
val mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
code += expressionEval.translateExpression(mult, indexReg, -1)
|
||||
}
|
||||
return code
|
||||
}
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
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.intermediate.*
|
||||
import prog8.vm.Syscall
|
||||
|
||||
|
||||
internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: ExpressionGen) {
|
||||
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
return when(call.name) {
|
||||
"any" -> funcAny(call, resultRegister)
|
||||
"all" -> funcAll(call, resultRegister)
|
||||
"abs" -> funcAbs(call, resultRegister)
|
||||
"cmp" -> funcCmp(call)
|
||||
"sgn" -> funcSgn(call, resultRegister)
|
||||
"sqrt16" -> funcSqrt16(call, resultRegister)
|
||||
"pop" -> funcPop(call)
|
||||
"popw" -> funcPopw(call)
|
||||
"push" -> funcPush(call)
|
||||
"pushw" -> funcPushw(call)
|
||||
"rsave",
|
||||
"rsavex",
|
||||
"rrestore",
|
||||
"rrestorex" -> IRCodeChunk(call.position) // vm doesn't have registers to save/restore
|
||||
"rnd" -> funcRnd(resultRegister, call.position)
|
||||
"rndw" -> funcRndw(resultRegister, call.position)
|
||||
"callfar" -> throw AssemblyError("callfar() is for cx16 target only")
|
||||
"callrom" -> throw AssemblyError("callrom() is for cx16 target only")
|
||||
"msb" -> funcMsb(call, resultRegister)
|
||||
"lsb" -> funcLsb(call, resultRegister)
|
||||
"memory" -> funcMemory(call, resultRegister)
|
||||
"peek" -> funcPeek(call, resultRegister)
|
||||
"peekw" -> funcPeekW(call, resultRegister)
|
||||
"poke" -> funcPoke(call)
|
||||
"pokew" -> funcPokeW(call)
|
||||
"pokemon" -> IRCodeChunk(call.position)
|
||||
"mkword" -> funcMkword(call, resultRegister)
|
||||
"sort" -> funcSort(call)
|
||||
"reverse" -> funcReverse(call)
|
||||
"rol" -> funcRolRor(Opcode.ROXL, call, resultRegister)
|
||||
"ror" -> funcRolRor(Opcode.ROXR, call, resultRegister)
|
||||
"rol2" -> funcRolRor(Opcode.ROL, call, resultRegister)
|
||||
"ror2" -> funcRolRor(Opcode.ROR, call, resultRegister)
|
||||
else -> throw AssemblyError("missing builtinfunc for ${call.name}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val leftRegister = codeGen.vmRegisters.nextFree()
|
||||
val rightRegister = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
|
||||
code += exprGen.translateExpression(call.args[1], rightRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val code = IRCodeChunk(call.position)
|
||||
val syscall =
|
||||
when (array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
DataType.ARRAY_B -> Syscall.ANY_BYTE
|
||||
DataType.ARRAY_UW,
|
||||
DataType.ARRAY_W -> Syscall.ANY_WORD
|
||||
DataType.ARRAY_F -> Syscall.ANY_FLOAT
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
|
||||
code += IRCodeInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
||||
if (resultRegister != 0)
|
||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
DataType.ARRAY_B -> Syscall.ALL_BYTE
|
||||
DataType.ARRAY_UW,
|
||||
DataType.ARRAY_W -> Syscall.ALL_WORD
|
||||
DataType.ARRAY_F -> Syscall.ALL_FLOAT
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val sourceDt = call.args.single().type
|
||||
if(sourceDt!=DataType.UWORD) {
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
when (sourceDt) {
|
||||
DataType.UBYTE -> {
|
||||
code += IRCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
|
||||
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
|
||||
code += IRCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += IRCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val sortSyscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> Syscall.REVERSE_BYTES
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> Syscall.REVERSE_WORDS
|
||||
DataType.ARRAY_F -> Syscall.REVERSE_FLOATS
|
||||
else -> throw IllegalArgumentException("weird type to reverse")
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val sortSyscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB -> Syscall.SORT_UBYTE
|
||||
DataType.ARRAY_B -> Syscall.SORT_BYTE
|
||||
DataType.ARRAY_UW -> Syscall.SORT_UWORD
|
||||
DataType.ARRAY_W -> Syscall.SORT_WORD
|
||||
DataType.STR -> Syscall.SORT_UBYTE
|
||||
DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported")
|
||||
else -> throw IllegalArgumentException("weird type to sort")
|
||||
}
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val msbReg = codeGen.vmRegisters.nextFree()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], msbReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPokeW(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRCodeInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPoke(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += IRCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += IRCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
code += IRCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
code += IRCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val name = (call.args[0] as PtString).value
|
||||
val size = (call.args[1] as PtNumber).number.toUInt()
|
||||
val align = (call.args[2] as PtNumber).number.toUInt()
|
||||
val label = codeGen.addMemorySlab(name, size, align, call.position)
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = label)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(call.args[0].type)
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
code += IRCodeInstruction(opcode, vmDt, reg1=resultRegister)
|
||||
code += assignRegisterTo(call.args[0], resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(target.position)
|
||||
val assignment = PtAssignment(target.position)
|
||||
val assignTarget = PtAssignTarget(target.position)
|
||||
assignTarget.children.add(target)
|
||||
assignment.children.add(assignTarget)
|
||||
assignment.children.add(PtMachineRegister(register, target.type, target.position))
|
||||
code += codeGen.translateNode(assignment)
|
||||
return code
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,947 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.StRomSub
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.StSub
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.intermediate.*
|
||||
|
||||
|
||||
internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
fun translateExpression(expr: PtExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
require(codeGen.vmRegisters.peekNext() > resultRegister)
|
||||
|
||||
val code = IRCodeChunk(expr.position)
|
||||
|
||||
when (expr) {
|
||||
is PtMachineRegister -> {
|
||||
if(resultRegister!=expr.register) {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
code += IRCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
|
||||
}
|
||||
}
|
||||
is PtNumber -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
code += if(vmDt==VmDataType.FLOAT)
|
||||
IRCodeInstruction(Opcode.LOAD, vmDt, fpReg1 = resultFpRegister, fpValue = expr.number.toFloat())
|
||||
else
|
||||
IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
val symbol = expr.targetName.joinToString(".")
|
||||
code += if (expr.type in PassByValueDatatypes) {
|
||||
if(vmDt==VmDataType.FLOAT)
|
||||
IRCodeInstruction(Opcode.LOADM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
||||
else
|
||||
IRCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
} else {
|
||||
// for strings and arrays etc., load the *address* of the value instead
|
||||
IRCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
is PtAddressOf -> {
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
val symbol = expr.identifier.targetName.joinToString(".")
|
||||
// note: LOAD <symbol> gets you the address of the symbol, whereas LOADM <symbol> would get you the value stored at that location
|
||||
code += IRCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, labelSymbol = symbol)
|
||||
}
|
||||
is PtMemoryByte -> {
|
||||
if(expr.address is PtNumber) {
|
||||
val address = (expr.address as PtNumber).number.toInt()
|
||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1=resultRegister, value = address)
|
||||
} else {
|
||||
val addressRegister = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(expr.address, addressRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
|
||||
}
|
||||
}
|
||||
is PtTypeCast -> code += translate(expr, resultRegister, resultFpRegister)
|
||||
is PtPrefix -> code += translate(expr, resultRegister)
|
||||
is PtArrayIndexer -> code += translate(expr, resultRegister, resultFpRegister)
|
||||
is PtBinaryExpression -> code += translate(expr, resultRegister, resultFpRegister)
|
||||
is PtBuiltinFunctionCall -> code += codeGen.translateBuiltinFunc(expr, resultRegister)
|
||||
is PtFunctionCall -> code += translate(expr, resultRegister, resultFpRegister)
|
||||
is PtContainmentCheck -> code += translate(expr, resultRegister, resultFpRegister)
|
||||
is PtRange,
|
||||
is PtArray,
|
||||
is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression")
|
||||
else -> throw AssemblyError("weird expression")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(check: PtContainmentCheck, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(check.position)
|
||||
code += translateExpression(check.element, resultRegister, -1) // load the element to check in resultRegister
|
||||
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.targetName) as StStaticVariable
|
||||
when(iterable.dt) {
|
||||
DataType.STR -> {
|
||||
val call = PtFunctionCall(listOf("prog8_lib", "string_contains"), false, DataType.UBYTE, check.position)
|
||||
call.children.add(check.element)
|
||||
call.children.add(check.iterable)
|
||||
code += translate(call, resultRegister, resultFpRegister)
|
||||
}
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||
val call = PtFunctionCall(listOf("prog8_lib", "bytearray_contains"), false, DataType.UBYTE, check.position)
|
||||
call.children.add(check.element)
|
||||
call.children.add(check.iterable)
|
||||
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
|
||||
code += translate(call, resultRegister, resultFpRegister)
|
||||
}
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
val call = PtFunctionCall(listOf("prog8_lib", "wordarray_contains"), false, DataType.UBYTE, check.position)
|
||||
call.children.add(check.element)
|
||||
call.children.add(check.iterable)
|
||||
call.children.add(PtNumber(DataType.UBYTE, iterable.length!!.toDouble(), iterable.position))
|
||||
code += translate(call, resultRegister, resultFpRegister)
|
||||
}
|
||||
DataType.ARRAY_F -> throw AssemblyError("containment check in float-array not supported")
|
||||
else -> throw AssemblyError("weird iterable dt ${iterable.dt} for ${check.iterable.targetName}")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type)
|
||||
val vmDt = codeGen.vmType(arrayIx.type)
|
||||
val code = IRCodeChunk(arrayIx.position)
|
||||
val idxReg = codeGen.vmRegisters.nextFree()
|
||||
val arrayVarSymbol = arrayIx.variable.targetName.joinToString(".")
|
||||
|
||||
if(arrayIx.variable.type==DataType.UWORD) {
|
||||
// indexing a pointer var instead of a real array or string
|
||||
if(eltSize!=1)
|
||||
throw AssemblyError("non-array var indexing requires bytes dt")
|
||||
if(arrayIx.index.type!=DataType.UBYTE)
|
||||
throw AssemblyError("non-array var indexing requires bytes index")
|
||||
code += translateExpression(arrayIx.index, idxReg, -1)
|
||||
code += IRCodeInstruction(Opcode.LOADIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol)
|
||||
return code
|
||||
}
|
||||
|
||||
if(arrayIx.index is PtNumber) {
|
||||
val memOffset = ((arrayIx.index as PtNumber).number.toInt() * eltSize).toString()
|
||||
if(vmDt==VmDataType.FLOAT)
|
||||
code += IRCodeInstruction(Opcode.LOADM, VmDataType.FLOAT, fpReg1=resultFpRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
||||
else
|
||||
code += IRCodeInstruction(Opcode.LOADM, vmDt, reg1=resultRegister, labelSymbol = "$arrayVarSymbol+$memOffset")
|
||||
} else {
|
||||
code += translateExpression(arrayIx.index, idxReg, -1)
|
||||
if(eltSize>1)
|
||||
code += codeGen.multiplyByConst(VmDataType.BYTE, idxReg, eltSize, arrayIx.position)
|
||||
if(vmDt==VmDataType.FLOAT)
|
||||
code += IRCodeInstruction(Opcode.LOADX, VmDataType.FLOAT, fpReg1 = resultFpRegister, reg1=idxReg, labelSymbol = arrayVarSymbol)
|
||||
else
|
||||
code += IRCodeInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = arrayVarSymbol)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(expr: PtPrefix, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(expr.position)
|
||||
code += translateExpression(expr.value, resultRegister, -1)
|
||||
val vmDt = codeGen.vmType(expr.type)
|
||||
when(expr.operator) {
|
||||
"+" -> { }
|
||||
"-" -> {
|
||||
code += IRCodeInstruction(Opcode.NEG, vmDt, reg1=resultRegister)
|
||||
}
|
||||
"~" -> {
|
||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||
code += IRCodeInstruction(Opcode.XOR, vmDt, reg1=resultRegister, value=mask)
|
||||
}
|
||||
else -> throw AssemblyError("weird prefix operator")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(cast: PtTypeCast, predefinedResultRegister: Int, predefinedResultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(cast.position)
|
||||
if(cast.type==cast.value.type)
|
||||
return code
|
||||
val actualResultFpReg = if(predefinedResultFpRegister>=0) predefinedResultFpRegister else codeGen.vmRegisters.nextFreeFloat()
|
||||
val actualResultReg = if(predefinedResultRegister>=0) predefinedResultRegister else codeGen.vmRegisters.nextFree()
|
||||
if(cast.value.type==DataType.FLOAT) {
|
||||
// a cast from float to integer, so evaluate the value into a float register first
|
||||
code += translateExpression(cast.value, -1, actualResultFpReg)
|
||||
}
|
||||
else
|
||||
code += translateExpression(cast.value, actualResultReg, -1)
|
||||
when(cast.type) {
|
||||
DataType.UBYTE -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
||||
DataType.FLOAT -> code += IRCodeInstruction(Opcode.FTOUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
when(cast.value.type) {
|
||||
DataType.UBYTE, DataType.UWORD, DataType.WORD -> { /* just keep the LSB as it is */ }
|
||||
DataType.FLOAT -> code += IRCodeInstruction(Opcode.FTOSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
// byte -> uword: sign extend
|
||||
code += IRCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// ubyte -> uword: sign extend
|
||||
code += IRCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.WORD -> { }
|
||||
DataType.FLOAT -> {
|
||||
code += IRCodeInstruction(Opcode.FTOUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
when(cast.value.type) {
|
||||
DataType.BYTE -> {
|
||||
// byte -> word: sign extend
|
||||
code += IRCodeInstruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// byte -> word: sign extend
|
||||
code += IRCodeInstruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = actualResultReg)
|
||||
}
|
||||
DataType.UWORD -> { }
|
||||
DataType.FLOAT -> {
|
||||
code += IRCodeInstruction(Opcode.FTOSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
code += when(cast.value.type) {
|
||||
DataType.UBYTE -> {
|
||||
IRCodeInstruction(Opcode.FFROMUB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
IRCodeInstruction(Opcode.FFROMSB, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
IRCodeInstruction(Opcode.FFROMUW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
IRCodeInstruction(Opcode.FFROMSW, VmDataType.FLOAT, reg1=actualResultReg, fpReg1 = actualResultFpReg)
|
||||
}
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("weird cast type")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(binExpr.left.type)
|
||||
val signed = binExpr.left.type in SignedDatatypes
|
||||
return when(binExpr.operator) {
|
||||
"+" -> operatorPlus(binExpr, vmDt, resultRegister, resultFpRegister)
|
||||
"-" -> operatorMinus(binExpr, vmDt, resultRegister, resultFpRegister)
|
||||
"*" -> operatorMultiply(binExpr, vmDt, resultRegister, resultFpRegister)
|
||||
"/" -> operatorDivide(binExpr, vmDt, resultRegister, resultFpRegister, signed)
|
||||
"%" -> operatorModulo(binExpr, vmDt, resultRegister)
|
||||
"|" -> operatorOr(binExpr, vmDt, resultRegister)
|
||||
"&" -> operatorAnd(binExpr, vmDt, resultRegister)
|
||||
"^" -> operatorXor(binExpr, vmDt, resultRegister)
|
||||
"<<" -> operatorShiftLeft(binExpr, vmDt, resultRegister)
|
||||
">>" -> operatorShiftRight(binExpr, vmDt, resultRegister, signed)
|
||||
"==" -> operatorEquals(binExpr, vmDt, resultRegister, false)
|
||||
"!=" -> operatorEquals(binExpr, vmDt, resultRegister, true)
|
||||
"<" -> operatorLessThan(binExpr, vmDt, resultRegister, signed, false)
|
||||
">" -> operatorGreaterThan(binExpr, vmDt, resultRegister, signed, false)
|
||||
"<=" -> operatorLessThan(binExpr, vmDt, resultRegister, signed, true)
|
||||
">=" -> operatorGreaterThan(binExpr, vmDt, resultRegister, signed, true)
|
||||
else -> throw AssemblyError("weird operator ${binExpr.operator}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun operatorGreaterThan(
|
||||
binExpr: PtBinaryExpression,
|
||||
vmDt: VmDataType,
|
||||
resultRegister: Int,
|
||||
signed: Boolean,
|
||||
greaterEquals: Boolean
|
||||
): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
val ins = if (signed) {
|
||||
if (greaterEquals) Opcode.SGES else Opcode.SGTS
|
||||
} else {
|
||||
if (greaterEquals) Opcode.SGE else Opcode.SGT
|
||||
}
|
||||
code += IRCodeInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
||||
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
||||
comparisonCall.children.add(binExpr.left)
|
||||
comparisonCall.children.add(binExpr.right)
|
||||
code += translate(comparisonCall, resultRegister, -1)
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
code += if(greaterEquals)
|
||||
IRCodeInstruction(Opcode.SGES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
else
|
||||
IRCodeInstruction(Opcode.SGTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val ins = if (signed) {
|
||||
if (greaterEquals) Opcode.SGES else Opcode.SGTS
|
||||
} else {
|
||||
if (greaterEquals) Opcode.SGE else Opcode.SGT
|
||||
}
|
||||
code += IRCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorLessThan(
|
||||
binExpr: PtBinaryExpression,
|
||||
vmDt: VmDataType,
|
||||
resultRegister: Int,
|
||||
signed: Boolean,
|
||||
lessEquals: Boolean
|
||||
): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
val ins = if (signed) {
|
||||
if (lessEquals) Opcode.SLES else Opcode.SLTS
|
||||
} else {
|
||||
if (lessEquals) Opcode.SLE else Opcode.SLT
|
||||
}
|
||||
code += IRCodeInstruction(ins, VmDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister)
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
||||
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
||||
comparisonCall.children.add(binExpr.left)
|
||||
comparisonCall.children.add(binExpr.right)
|
||||
code += translate(comparisonCall, resultRegister, -1)
|
||||
val zeroRegister = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=zeroRegister, value=0)
|
||||
code += if(lessEquals)
|
||||
IRCodeInstruction(Opcode.SLES, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
else
|
||||
IRCodeInstruction(Opcode.SLTS, VmDataType.BYTE, reg1=resultRegister, reg2=zeroRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val ins = if (signed) {
|
||||
if (lessEquals) Opcode.SLES else Opcode.SLTS
|
||||
} else {
|
||||
if (lessEquals) Opcode.SLE else Opcode.SLT
|
||||
}
|
||||
code += IRCodeInstruction(ins, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorEquals(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, notEquals: Boolean): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
val leftFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
val rightFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, leftFpReg)
|
||||
code += translateExpression(binExpr.right, -1, rightFpReg)
|
||||
if (notEquals) {
|
||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=resultRegister, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
} else {
|
||||
val label = codeGen.createLabelName()
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
|
||||
code += IRCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += IRCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
|
||||
code += IRCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
|
||||
code += IRCodeLabel(label)
|
||||
}
|
||||
} else {
|
||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
||||
val comparisonCall = PtFunctionCall(listOf("prog8_lib", "string_compare"), false, DataType.BYTE, Position.DUMMY)
|
||||
comparisonCall.children.add(binExpr.left)
|
||||
comparisonCall.children.add(binExpr.right)
|
||||
code += translate(comparisonCall, resultRegister, -1)
|
||||
if(!notEquals)
|
||||
code += IRCodeInstruction(Opcode.INV, vmDt, reg1=resultRegister)
|
||||
code += IRCodeInstruction(Opcode.AND, vmDt, reg1=resultRegister, value=1)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val opcode = if (notEquals) Opcode.SNE else Opcode.SEQ
|
||||
code += IRCodeInstruction(opcode, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorShiftRight(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, signed: Boolean): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(codeGen.isOne(binExpr.right)) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
val opc = if (signed) Opcode.ASR else Opcode.LSR
|
||||
code += IRCodeInstruction(opc, vmDt, reg1 = resultRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
val opc = if (signed) Opcode.ASRN else Opcode.LSRN
|
||||
code += IRCodeInstruction(opc, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(codeGen.isOne(operand)) {
|
||||
val opc = if (signed) Opcode.ASRM else Opcode.LSRM
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(opc, vmDt, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(opc, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(opc, vmDt, reg1 = operandReg, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(opc, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorShiftLeft(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(codeGen.isOne(binExpr.right)){
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.LSL, vmDt, reg1=resultRegister)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.LSLN, vmDt, reg1=resultRegister, rightResultReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(codeGen.isOne(operand)){
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.LSLM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.LSLM, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.LSLNM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorXor(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.XOR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.XORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.XORM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorAnd(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.AND, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.ANDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.ANDM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorOr(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.OR, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.ORR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.ORM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
|
||||
if(vmDt==VmDataType.FLOAT)
|
||||
throw IllegalArgumentException("floating-point modulo not supported")
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.MOD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.MODR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorDivide(binExpr: PtBinaryExpression,
|
||||
vmDt: VmDataType,
|
||||
resultRegister: Int,
|
||||
resultFpRegister: Int,
|
||||
signed: Boolean): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
val constFactorRight = binExpr.right as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.divideByConstFloat(resultFpRegister, factor, binExpr.position)
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += if(signed)
|
||||
IRCodeInstruction(Opcode.DIVSR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DIVR, vmDt, fpReg1 = resultFpRegister, fpReg2=rightResultFpReg)
|
||||
}
|
||||
} else {
|
||||
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, binExpr.position)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += if (signed)
|
||||
IRCodeInstruction(Opcode.DIVS, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
else
|
||||
IRCodeInstruction(Opcode.DIV, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += if (signed)
|
||||
IRCodeInstruction(Opcode.DIVSR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DIVR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, signed: Boolean, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.divideByConstFloatInplace(knownAddress, symbol, factor, operand.position)
|
||||
} else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(signed) {
|
||||
if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DIVSM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DIVM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.divideByConstInplace(vmDt, knownAddress, symbol, factor, signed, operand.position)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(signed) {
|
||||
if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.DIVSM, vmDt, reg1 = operandReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DIVSM, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.DIVM, vmDt, reg1 = operandReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DIVM, vmDt, reg1 = operandReg, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorMultiply(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
val constFactorLeft = binExpr.left as? PtNumber
|
||||
val constFactorRight = binExpr.right as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(constFactorLeft!=null) {
|
||||
code += translateExpression(binExpr.right, -1, resultFpRegister)
|
||||
val factor = constFactorLeft.number.toFloat()
|
||||
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, constFactorRight.position)
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += IRCodeInstruction(Opcode.MULR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||
}
|
||||
} else {
|
||||
if(constFactorLeft!=null && constFactorLeft.type!=DataType.FLOAT) {
|
||||
code += translateExpression(binExpr.right, resultRegister, -1)
|
||||
val factor = constFactorLeft.number.toInt()
|
||||
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, constFactorRight.position)
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.MULR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
val constFactorRight = operand as? PtNumber
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if(constFactorRight!=null) {
|
||||
val factor = constFactorRight.number.toFloat()
|
||||
code += codeGen.multiplyByConstFloatInplace(knownAddress, symbol, factor, constFactorRight.position)
|
||||
} else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.MULM, vmDt, fpReg1 = operandFpReg, labelSymbol = symbol)
|
||||
}
|
||||
} else {
|
||||
if(constFactorRight!=null && constFactorRight.type!=DataType.FLOAT) {
|
||||
val factor = constFactorRight.number.toInt()
|
||||
code += codeGen.multiplyByConstInplace(vmDt, knownAddress, symbol, factor, constFactorRight.position)
|
||||
} else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.MULM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorMinus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += IRCodeInstruction(Opcode.DEC, vmDt, fpReg1 = resultFpRegister)
|
||||
}
|
||||
else {
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += IRCodeInstruction(Opcode.SUB, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += IRCodeInstruction(Opcode.SUBR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.DEC, vmDt, reg1=resultRegister)
|
||||
}
|
||||
else {
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.SUB, vmDt, reg1 = resultRegister, value = (binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.SUBR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.SUBM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.DECM, vmDt, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.DECM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.SUBM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun operatorPlus(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(binExpr.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if((binExpr.left as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.right, -1, resultFpRegister)
|
||||
code += IRCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
|
||||
}
|
||||
else if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += IRCodeInstruction(Opcode.INC, vmDt, fpReg1=resultFpRegister)
|
||||
}
|
||||
else {
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += IRCodeInstruction(Opcode.ADD, vmDt, fpReg1 = resultFpRegister, fpValue = (binExpr.right as PtNumber).number.toFloat())
|
||||
} else {
|
||||
val rightResultFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(binExpr.left, -1, resultFpRegister)
|
||||
code += translateExpression(binExpr.right, -1, rightResultFpReg)
|
||||
code += IRCodeInstruction(Opcode.ADDR, vmDt, fpReg1 = resultFpRegister, fpReg2 = rightResultFpReg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if((binExpr.left as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.right, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
||||
}
|
||||
else if((binExpr.right as? PtNumber)?.number==1.0) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.INC, vmDt, reg1=resultRegister)
|
||||
}
|
||||
else {
|
||||
if(binExpr.right is PtNumber) {
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += IRCodeInstruction(Opcode.ADD, vmDt, reg1 = resultRegister, value=(binExpr.right as PtNumber).number.toInt())
|
||||
} else {
|
||||
val rightResultReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(binExpr.left, resultRegister, -1)
|
||||
code += translateExpression(binExpr.right, rightResultReg, -1)
|
||||
code += IRCodeInstruction(Opcode.ADDR, vmDt, reg1 = resultRegister, reg2 = rightResultReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: VmDataType, operand: PtExpression): IRCodeChunk {
|
||||
val code = IRCodeChunk(operand.position)
|
||||
if(vmDt==VmDataType.FLOAT) {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.INCM, vmDt, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(operand, -1, operandFpReg)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.ADDM, vmDt, fpReg1=operandFpReg, labelSymbol = symbol)
|
||||
}
|
||||
} else {
|
||||
if((operand as? PtNumber)?.number==1.0) {
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.INCM, vmDt, value = knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.INCM, vmDt, labelSymbol = symbol)
|
||||
}
|
||||
else {
|
||||
val operandReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(operand, operandReg, -1)
|
||||
code += if(knownAddress!=null)
|
||||
IRCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, value=knownAddress)
|
||||
else
|
||||
IRCodeInstruction(Opcode.ADDM, vmDt, reg1=operandReg, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
fun translate(fcall: PtFunctionCall, resultRegister: Int, resultFpRegister: Int): IRCodeChunk {
|
||||
when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.functionName)) {
|
||||
is StSub -> {
|
||||
val code = IRCodeChunk(fcall.position)
|
||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||
val paramDt = codeGen.vmType(parameter.type)
|
||||
val symbol = (fcall.functionName + parameter.name).joinToString(".")
|
||||
if(codeGen.isZero(arg)) {
|
||||
code += IRCodeInstruction(Opcode.STOREZM, paramDt, labelSymbol = symbol)
|
||||
} else {
|
||||
if (paramDt == VmDataType.FLOAT) {
|
||||
val argFpReg = codeGen.vmRegisters.nextFreeFloat()
|
||||
code += translateExpression(arg, -1, argFpReg)
|
||||
code += IRCodeInstruction(Opcode.STOREM, paramDt, fpReg1 = argFpReg, labelSymbol = symbol)
|
||||
} else {
|
||||
val argReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(arg, argReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STOREM, paramDt, reg1 = argReg, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
code += IRCodeInstruction(Opcode.CALL, labelSymbol=fcall.functionName.joinToString("."))
|
||||
if(fcall.type==DataType.FLOAT) {
|
||||
if (!fcall.void && resultFpRegister != 0) {
|
||||
// Call convention: result value is in fr0, so put it in the required register instead.
|
||||
code += IRCodeInstruction(Opcode.LOADR, VmDataType.FLOAT, fpReg1 = resultFpRegister, fpReg2 = 0)
|
||||
}
|
||||
} else {
|
||||
if (!fcall.void && resultRegister != 0) {
|
||||
// Call convention: result value is in r0, so put it in the required register instead.
|
||||
code += IRCodeInstruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1 = resultRegister, reg2 = 0)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
is StRomSub -> {
|
||||
val code = IRCodeChunk(fcall.position)
|
||||
for ((arg, parameter) in fcall.args.zip(callTarget.parameters)) {
|
||||
val paramDt = codeGen.vmType(parameter.type)
|
||||
val paramRegStr = if(parameter.register.registerOrPair!=null) parameter.register.registerOrPair.toString() else parameter.register.statusflag.toString()
|
||||
if(codeGen.isZero(arg)) {
|
||||
code += IRCodeInstruction(Opcode.STOREZCPU, paramDt, labelSymbol = paramRegStr)
|
||||
} else {
|
||||
if (paramDt == VmDataType.FLOAT)
|
||||
throw AssemblyError("doesn't support float register argument in asm romsub")
|
||||
val argReg = codeGen.vmRegisters.nextFree()
|
||||
code += translateExpression(arg, argReg, -1)
|
||||
code += IRCodeInstruction(Opcode.STORECPU, paramDt, reg1 = argReg, labelSymbol = paramRegStr)
|
||||
}
|
||||
}
|
||||
code += IRCodeInstruction(Opcode.CALL, value=callTarget.address.toInt())
|
||||
if(!fcall.void) {
|
||||
if(callTarget.returns.size!=1)
|
||||
throw AssemblyError("expect precisely 1 return value")
|
||||
if(fcall.type==DataType.FLOAT)
|
||||
throw AssemblyError("doesn't support float register result in asm romsub")
|
||||
val returns = callTarget.returns.single()
|
||||
val regStr = if(returns.registerOrPair!=null) returns.registerOrPair.toString() else returns.statusflag.toString()
|
||||
code += IRCodeInstruction(Opcode.LOADCPU, codeGen.vmType(fcall.type), reg1=resultRegister, labelSymbol = regStr)
|
||||
}
|
||||
return code
|
||||
}
|
||||
else -> throw AssemblyError("invalid node type")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.intermediate.*
|
||||
import java.io.BufferedWriter
|
||||
import kotlin.io.path.bufferedWriter
|
||||
import kotlin.io.path.div
|
||||
|
||||
class VmAssemblyProgram(override val name: String, val irProgram: IRProgram): IAssemblyProgram {
|
||||
|
||||
// TODO once this is working, replace the codeGenVirtual by codeGenExperimental
|
||||
// after that, add an option to the VmRunner to accept an IRProgram object directly and skip this intermediate .p8ir step when -emu is present
|
||||
|
||||
|
||||
override fun assemble(options: CompilationOptions): Boolean {
|
||||
val outfile = options.outputDir / ("$name.p8virt")
|
||||
println("write code to $outfile")
|
||||
|
||||
// at last, allocate the variables in memory.
|
||||
val allocations = VmVariableAllocator(irProgram.st, irProgram.encoding, irProgram.options.compTarget)
|
||||
|
||||
outfile.bufferedWriter().use { out ->
|
||||
allocations.asVmMemory().forEach { (name, alloc) ->
|
||||
out.write("var ${name.joinToString(".")} $alloc\n")
|
||||
}
|
||||
|
||||
out.write("------PROGRAM------\n")
|
||||
|
||||
if(!options.dontReinitGlobals) {
|
||||
out.write("; global var inits\n")
|
||||
irProgram.globalInits.forEach { out.writeLine(it) }
|
||||
}
|
||||
irProgram.blocks.firstOrNull()?.let {
|
||||
if(it.subroutines.any { it.name=="main.start" }) {
|
||||
// there is a "main.start" entrypoint, jump to it
|
||||
out.writeLine(IRCodeInstruction(Opcode.JUMP, labelSymbol = "main.start"))
|
||||
}
|
||||
}
|
||||
|
||||
out.write("; actual program code\n")
|
||||
|
||||
irProgram.blocks.forEach { block ->
|
||||
if(block.address!=null)
|
||||
TODO("blocks can't have a load address for vm")
|
||||
out.write("; BLOCK ${block.name} ${block.position}\n")
|
||||
block.inlineAssembly.forEach { asm ->
|
||||
out.write("; ASM ${asm.position}\n")
|
||||
out.write(asm.assembly)
|
||||
out.write("\n")
|
||||
}
|
||||
block.subroutines.forEach { sub ->
|
||||
out.write("; SUB ${sub.name} ${sub.position}\n")
|
||||
out.write("_${sub.name}:\n")
|
||||
sub.chunks.forEach { chunk ->
|
||||
if(chunk is IRInlineAsmChunk) {
|
||||
out.write("; ASM ${chunk.position}\n")
|
||||
out.write(processInlinedAsm(chunk.assembly, allocations))
|
||||
out.write("\n")
|
||||
} else {
|
||||
chunk.lines.forEach { out.writeLine(it) }
|
||||
}
|
||||
}
|
||||
out.write("; END SUB ${sub.name}\n")
|
||||
}
|
||||
block.asmSubroutines.forEach { sub ->
|
||||
out.write("; ASMSUB ${sub.name} ${sub.position}\n")
|
||||
out.write("_${sub.name}:\n")
|
||||
out.write(processInlinedAsm(sub.assembly, allocations))
|
||||
out.write("\n; END ASMSUB ${sub.name}\n")
|
||||
}
|
||||
out.write("; END BLOCK ${block.name}\n")
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun processInlinedAsm(asm: String, allocations: VmVariableAllocator): String {
|
||||
// TODO do we have to replace variable names by their allocated address???
|
||||
return asm
|
||||
}
|
||||
}
|
||||
|
||||
private fun BufferedWriter.writeLine(line: IRCodeLine) {
|
||||
when(line) {
|
||||
is IRCodeComment -> {
|
||||
write("; ${line.comment}\n")
|
||||
}
|
||||
is IRCodeInstruction -> {
|
||||
write(line.ins.toString() + "\n")
|
||||
}
|
||||
is IRCodeInlineBinary -> {
|
||||
write("!binary ")
|
||||
line.data.withIndex().forEach {(index, byte) ->
|
||||
write(byte.toString(16).padStart(2,'0'))
|
||||
if(index and 63 == 63 && index<line.data.size-1)
|
||||
write("\n!binary ")
|
||||
}
|
||||
write("\n")
|
||||
}
|
||||
is IRCodeLabel -> {
|
||||
write("_${line.name}:\n")
|
||||
}
|
||||
else -> throw AssemblyError("invalid IR code line")
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.core.*
|
||||
import prog8.intermediate.getTypeString
|
||||
|
||||
class VmVariableAllocator(val st: SymbolTable, val encoding: IStringEncoding, memsizer: IMemSizer) {
|
||||
|
||||
internal val allocations = mutableMapOf<List<String>, Int>()
|
||||
private var freeMemoryStart: Int
|
||||
|
||||
val freeMem: Int
|
||||
get() = freeMemoryStart
|
||||
|
||||
|
||||
init {
|
||||
var nextLocation = 0
|
||||
for (variable in st.allVariables) {
|
||||
val memsize =
|
||||
when (variable.dt) {
|
||||
DataType.STR -> variable.onetimeInitializationStringValue!!.first.length + 1 // include the zero byte
|
||||
in NumericDatatypes -> memsizer.memorySize(variable.dt)
|
||||
in ArrayDatatypes -> memsizer.memorySize(variable.dt, variable.length!!)
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
|
||||
allocations[variable.scopedName] = nextLocation
|
||||
nextLocation += memsize
|
||||
}
|
||||
for(slab in st.allMemorySlabs) {
|
||||
// we ignore the alignment for the VM.
|
||||
allocations[slab.scopedName] = nextLocation
|
||||
nextLocation += slab.size.toInt()
|
||||
}
|
||||
|
||||
freeMemoryStart = nextLocation
|
||||
}
|
||||
|
||||
fun asVmMemory(): List<Pair<List<String>, String>> {
|
||||
val mm = mutableListOf<Pair<List<String>, String>>()
|
||||
|
||||
// normal variables
|
||||
for (variable in st.allVariables) {
|
||||
val location = allocations.getValue(variable.scopedName)
|
||||
val value = when(variable.dt) {
|
||||
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
|
||||
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0).toHex()
|
||||
DataType.STR -> {
|
||||
val encoded = encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
|
||||
encoded.joinToString(",") { it.toInt().toHex() }
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
if(variable.onetimeInitializationArrayValue!=null) {
|
||||
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
|
||||
} else {
|
||||
(1..variable.length!!).joinToString(",") { "0" }
|
||||
}
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
if(variable.onetimeInitializationArrayValue!==null) {
|
||||
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toHex() }
|
||||
} else {
|
||||
(1..variable.length!!).joinToString(",") { "0" }
|
||||
}
|
||||
}
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
mm.add(Pair(variable.scopedName, "@$location ${getTypeString(variable)} $value"))
|
||||
}
|
||||
|
||||
// memory mapped variables
|
||||
for (variable in st.allMemMappedVariables) {
|
||||
val value = when(variable.dt) {
|
||||
DataType.FLOAT -> "0.0"
|
||||
in NumericDatatypes -> "0"
|
||||
DataType.ARRAY_F -> (1..variable.length!!).joinToString(",") { "0.0" }
|
||||
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
||||
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
||||
}
|
||||
mm.add(Pair(variable.scopedName, "@${variable.address} ${getTypeString(variable)} $value"))
|
||||
}
|
||||
|
||||
// memory slabs.
|
||||
for(slab in st.allMemorySlabs) {
|
||||
val address = allocations.getValue(slab.scopedName)
|
||||
mm.add(Pair(slab.scopedName, "@$address ubyte[${slab.size}] 0"))
|
||||
}
|
||||
|
||||
return mm
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user