mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
vm: implemented some self-assign instructions
This commit is contained in:
parent
4e1184a400
commit
181b98ef9e
@ -12,27 +12,24 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit
|
||||
print(type)
|
||||
}
|
||||
|
||||
infix fun isSameTargetAs(other: PtExpression): Boolean = when(this) {
|
||||
is PtArrayIndexer -> {
|
||||
if(other is PtArrayIndexer && other.type==type) {
|
||||
if(other.variable isSameTargetAs variable) {
|
||||
other.index isSameTargetAs index
|
||||
}
|
||||
}
|
||||
false
|
||||
infix fun isSameAs(other: PtExpression): Boolean {
|
||||
return when(this) {
|
||||
is PtAddressOf -> other is PtAddressOf && other.type==type && other.identifier isSameAs identifier
|
||||
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index
|
||||
is PtBinaryExpression -> other is PtBinaryExpression && other.left isSameAs left && other.right isSameAs right
|
||||
is PtContainmentCheck -> other is PtContainmentCheck && other.type==type && other.element isSameAs element && other.iterable isSameAs iterable
|
||||
is PtIdentifier -> other is PtIdentifier && other.type==type && other.targetName==targetName
|
||||
is PtMachineRegister -> other is PtMachineRegister && other.type==type && other.register==register
|
||||
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
|
||||
is PtNumber -> other is PtNumber && other.type==type && other.number==number
|
||||
is PtPrefix -> other is PtPrefix && other.type==type && other.operator==operator && other.value isSameAs value
|
||||
is PtRange -> other is PtRange && other.type==type && other.from==from && other.to==to && other.step==step
|
||||
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameAs value
|
||||
else -> false
|
||||
}
|
||||
is PtIdentifier -> other is PtIdentifier && other.type==type && other.targetName==targetName
|
||||
is PtMachineRegister -> other is PtMachineRegister && other.register==register
|
||||
is PtMemoryByte -> other is PtMemoryByte && address isSameTargetAs other.address
|
||||
is PtNumber -> other is PtNumber && other.type == type && other.number==number
|
||||
is PtAddressOf -> other is PtAddressOf && other.identifier isSameTargetAs identifier
|
||||
is PtPrefix -> other is PtPrefix && other.operator==operator && other.value isSameTargetAs value
|
||||
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameTargetAs value
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
|
||||
val identifier: PtIdentifier
|
||||
get() = children.single() as PtIdentifier
|
||||
|
@ -48,14 +48,33 @@ class PtAssignment(position: Position) : PtNode(position) {
|
||||
|
||||
val isInplaceAssign: Boolean by lazy {
|
||||
val target = target.children.single() as PtExpression
|
||||
if(value is PtBinaryExpression) {
|
||||
target isSameTargetAs (value as PtBinaryExpression).left
|
||||
} else
|
||||
target isSameTargetAs value
|
||||
when(val source = value) {
|
||||
is PtArrayIndexer -> {
|
||||
if(target is PtArrayIndexer && source.type==target.type) {
|
||||
if(target.variable isSameAs source.variable) {
|
||||
target.index isSameAs source.index
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
is PtIdentifier -> target is PtIdentifier && target.type==source.type && target.targetName==source.targetName
|
||||
is PtMachineRegister -> target is PtMachineRegister && target.register==source.register
|
||||
is PtMemoryByte -> target is PtMemoryByte && target.address isSameAs source.address
|
||||
is PtNumber -> target is PtNumber && target.type == source.type && target.number==source.number
|
||||
is PtAddressOf -> target is PtAddressOf && target.identifier isSameAs source.identifier
|
||||
is PtPrefix -> {
|
||||
(target is PtPrefix && target.operator==source.operator && target.value isSameAs source.value)
|
||||
||
|
||||
(target is PtIdentifier && (source.value as? PtIdentifier)?.targetName==target.targetName)
|
||||
}
|
||||
is PtTypeCast -> target is PtTypeCast && target.type==source.type && target.value isSameAs source.value
|
||||
is PtBinaryExpression ->
|
||||
target isSameAs source.left
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtAssignTarget(position: Position) : PtNode(position) {
|
||||
val identifier: PtIdentifier?
|
||||
get() = children.single() as? PtIdentifier
|
||||
|
@ -81,9 +81,9 @@ internal class VmCodeInstruction(
|
||||
fpReg2: Int?=null, // 0-$ffff
|
||||
value: Int?=null, // 0-$ffff
|
||||
fpValue: Float?=null,
|
||||
symbol: List<String>?=null // alternative to value
|
||||
labelSymbol: List<String>?=null // alternative to value for branch/call/jump labels
|
||||
): VmCodeLine() {
|
||||
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, symbol)
|
||||
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, labelSymbol)
|
||||
|
||||
init {
|
||||
if(reg1!=null && (reg1<0 || reg1>65536))
|
||||
|
@ -3,12 +3,16 @@ package prog8.codegen.virtual
|
||||
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.VmDataType
|
||||
|
||||
internal class AssignmentGen(private val codeGen: CodeGen, private val expressionEval: ExpressionGen) {
|
||||
|
||||
internal fun translate(assignment: PtAssignment): VmCodeChunk {
|
||||
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
|
||||
@ -16,14 +20,104 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
}
|
||||
|
||||
private fun translateInplaceAssign(assignment: PtAssignment): VmCodeChunk {
|
||||
// TODO can in-place assignments be optimized more? use special memory versions of instructions instead of register ones?
|
||||
return translateRegularAssign(assignment)
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
|
||||
return if(ident!=null) {
|
||||
val address = codeGen.allocations.get(ident.targetName)
|
||||
assignSelfInMemory(address, assignment.value, assignment.position, assignment)
|
||||
} else if(memory != null) {
|
||||
if(memory.address is PtNumber) {
|
||||
assignSelfInMemory((memory.address as PtNumber).number.toInt(), assignment.value, assignment.position, assignment)
|
||||
} else {
|
||||
fallbackAssign(assignment)
|
||||
}
|
||||
} else if(array!=null) {
|
||||
// TODO in-place array element assignment?
|
||||
fallbackAssign(assignment)
|
||||
} else {
|
||||
fallbackAssign(assignment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignSelfInMemory(
|
||||
targetAddress: Int,
|
||||
value: PtExpression,
|
||||
position: Position,
|
||||
origAssign: PtAssignment
|
||||
): VmCodeChunk {
|
||||
val vmDt = codeGen.vmType(value.type)
|
||||
val code = VmCodeChunk()
|
||||
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, targetAddress)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, targetAddress, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
return if (!codeGen.options.compTarget.machine.isIOAddress(targetAddress.toUInt()))
|
||||
code // do nothing, mem=mem null assignment.
|
||||
else {
|
||||
// read and write a (i/o) memory location to itself.
|
||||
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = 0, value = targetAddress.toInt())
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = 0, value = targetAddress.toInt())
|
||||
code
|
||||
}
|
||||
}
|
||||
else -> return fallbackAssign(origAssign)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun fallbackAssign(origAssign: PtAssignment): VmCodeChunk {
|
||||
if (codeGen.options.slowCodegenWarnings)
|
||||
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
|
||||
return translateRegularAssign(origAssign)
|
||||
}
|
||||
|
||||
private fun inplaceBinexpr(
|
||||
operator: String,
|
||||
right: PtExpression,
|
||||
vmDt: VmDataType,
|
||||
targetAddress: Int,
|
||||
origAssign: PtAssignment
|
||||
): VmCodeChunk {
|
||||
when(operator) {
|
||||
"+" -> { /* TODO */ }
|
||||
"-" -> { /* TODO */ }
|
||||
"*" -> { /* TODO */ }
|
||||
"/" -> { /* TODO */ }
|
||||
"|" -> { /* TODO */ }
|
||||
"&" -> { /* TODO */ }
|
||||
"^" -> { /* TODO */ }
|
||||
else -> {}
|
||||
}
|
||||
return fallbackAssign(origAssign)
|
||||
}
|
||||
|
||||
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int): VmCodeChunk {
|
||||
val code= VmCodeChunk()
|
||||
when(operator) {
|
||||
"+" -> { }
|
||||
"-" -> {
|
||||
code += VmCodeInstruction(Opcode.NEGM, vmDt, value = address)
|
||||
}
|
||||
"~" -> {
|
||||
val regMask = codeGen.vmRegisters.nextFree()
|
||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
||||
code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = address)
|
||||
}
|
||||
"not" -> {
|
||||
code += VmCodeInstruction(Opcode.NOTM, vmDt, value = address)
|
||||
}
|
||||
else -> throw AssemblyError("weird prefix operator")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translateRegularAssign(assignment: PtAssignment): VmCodeChunk {
|
||||
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
|
||||
if(assignment.target.children.single() is PtMachineRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
|
@ -116,7 +116,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=andReg, value=0x80)
|
||||
code += VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=andReg, reg2=resultRegister)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=andReg, symbol = notNegativeLabel)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=andReg, labelSymbol = notNegativeLabel)
|
||||
code += VmCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += VmCodeLabel(notNegativeLabel)
|
||||
@ -126,7 +126,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=andReg, value=0x8000)
|
||||
code += VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=andReg, reg2=resultRegister)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=andReg, symbol = notNegativeLabel)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=andReg, labelSymbol = notNegativeLabel)
|
||||
code += VmCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
||||
code += VmCodeLabel(notNegativeLabel)
|
||||
}
|
||||
|
@ -123,19 +123,19 @@ class CodeGen(internal val program: PtProgram,
|
||||
val elseLabel = createLabelName()
|
||||
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
|
||||
code += when(branch.condition) {
|
||||
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, symbol = elseLabel)
|
||||
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, symbol = elseLabel)
|
||||
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, symbol = elseLabel)
|
||||
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, symbol = elseLabel)
|
||||
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, symbol = elseLabel)
|
||||
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, symbol = elseLabel)
|
||||
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
|
||||
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
|
||||
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
|
||||
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
||||
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
||||
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
||||
BranchCondition.VC,
|
||||
BranchCondition.VS -> throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu V flag ${branch.position}")
|
||||
}
|
||||
code += translateNode(branch.trueScope)
|
||||
if(branch.falseScope.children.isNotEmpty()) {
|
||||
val endLabel = createLabelName()
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(branch.falseScope)
|
||||
code += VmCodeLabel(endLabel)
|
||||
@ -163,21 +163,21 @@ class CodeGen(internal val program: PtProgram,
|
||||
val values = choice.values.children.map {it as PtNumber}
|
||||
if(values.size==1) {
|
||||
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
||||
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, symbol = skipLabel)
|
||||
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
|
||||
code += translateNode(choice.statements)
|
||||
if(choice.statements.children.last() !is PtReturn)
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
} else {
|
||||
val matchLabel = createLabelName()
|
||||
for (value in values) {
|
||||
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
||||
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, symbol = matchLabel)
|
||||
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
|
||||
}
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = skipLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
||||
code += VmCodeLabel(matchLabel)
|
||||
code += translateNode(choice.statements)
|
||||
if(choice.statements.children.last() !is PtReturn)
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
}
|
||||
code += VmCodeLabel(skipLabel)
|
||||
}
|
||||
@ -209,11 +209,11 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += VmCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=0, reg2=indexReg, value = arrayAddress)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=0, symbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=0, labelSymbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=0, value = loopvarAddress)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
code += VmCodeLabel(endLabel)
|
||||
} else {
|
||||
// iterate over array
|
||||
@ -224,12 +224,12 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, symbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.BEQ, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=0, reg2=indexReg, value=arrayAddress)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=0, value = loopvarAddress)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = loopLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
code += VmCodeLabel(endLabel)
|
||||
}
|
||||
}
|
||||
@ -264,7 +264,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(Opcode.STOREM, 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, symbol=loopLabel)
|
||||
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -303,9 +303,9 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
|
||||
}
|
||||
code += if(rangeEndWrapped==0) {
|
||||
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, symbol = loopLabel)
|
||||
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
|
||||
} else {
|
||||
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, symbol = loopLabel)
|
||||
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
|
||||
}
|
||||
return code
|
||||
}
|
||||
@ -492,16 +492,16 @@ class CodeGen(internal val program: PtProgram,
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, symbol = elseLabel)
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, symbol = afterIfLabel)
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
}
|
||||
@ -516,16 +516,16 @@ class CodeGen(internal val program: PtProgram,
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, symbol = elseLabel)
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, symbol = afterIfLabel)
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
}
|
||||
@ -629,7 +629,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
code += VmCodeLabel(repeatLabel)
|
||||
code += translateNode(repeat.statements)
|
||||
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
||||
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, symbol = repeatLabel)
|
||||
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||
return code
|
||||
}
|
||||
|
||||
@ -638,9 +638,9 @@ class CodeGen(internal val program: PtProgram,
|
||||
if(jump.address!=null)
|
||||
throw AssemblyError("cannot jump to memory location in the vm target")
|
||||
code += if(jump.generatedLabel!=null)
|
||||
VmCodeInstruction(Opcode.JUMP, symbol = listOf(jump.generatedLabel!!))
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf(jump.generatedLabel!!))
|
||||
else if(jump.identifier!=null)
|
||||
VmCodeInstruction(Opcode.JUMP, symbol = jump.identifier!!.targetName)
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName)
|
||||
else
|
||||
throw AssemblyError("weird jump")
|
||||
return code
|
||||
|
@ -410,7 +410,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=1)
|
||||
code += VmCodeInstruction(Opcode.FCOMP, VmDataType.FLOAT, reg1=valueReg, fpReg1 = leftFpReg, fpReg2 = rightFpReg)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, symbol = label)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=valueReg, labelSymbol = label)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=resultRegister, value=0)
|
||||
code += VmCodeLabel(label)
|
||||
}
|
||||
@ -664,7 +664,7 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
|
||||
}
|
||||
}
|
||||
}
|
||||
code += VmCodeInstruction(Opcode.CALL, symbol=fcall.functionName)
|
||||
code += VmCodeInstruction(Opcode.CALL, labelSymbol=fcall.functionName)
|
||||
if(fcall.type==DataType.FLOAT) {
|
||||
if (!fcall.void && resultFpRegister != 0) {
|
||||
// Call convention: result value is in fr0, so put it in the required register instead.
|
||||
|
@ -3,8 +3,8 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- vm: implement the sin/cos functions in math.p8 and make an example 'shader' that uses them
|
||||
- vm: add more instructions operating directly on memory instead of only registers? (translate assignment self-assigns in AssignmentGen)
|
||||
- vm: implement the missing in-place operators in inplaceBinexpr()
|
||||
- vm: implement the new in-memory instructions in the VirtualMachine eval loop itself.
|
||||
- complete the Inliner
|
||||
- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value?
|
||||
|
||||
@ -23,6 +23,7 @@ Future Things and Ideas
|
||||
Compiler:
|
||||
|
||||
- vm: codeGen: various TODOs to tweak code
|
||||
- vm: implement remaining sin/cos functions in math.p8
|
||||
- vm: somehow deal with asmsubs otherwise the vm IR can't fully encode all of prog8
|
||||
- vm: don't store symbol names in instructions to make optimizing the IR easier? but what about jumps to labels. And it's no longer readable by humans.
|
||||
- vm: how to remove all unused subroutines? (in the assembly codegen, we let 64tass solve this for us)
|
||||
|
@ -4,19 +4,26 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
byte xx
|
||||
byte yy
|
||||
ubyte ubx
|
||||
|
||||
; a "pixelshader":
|
||||
sys.gfx_enable(0) ; enable lo res screen
|
||||
xx = xx
|
||||
xx = xx*9
|
||||
xx = yy*9
|
||||
xx = xx+3*yy
|
||||
xx = xx/yy
|
||||
xx = -xx
|
||||
@($4000) = @($4000)
|
||||
@($4000) = @($4000) + 2
|
||||
xx = xx | yy
|
||||
xx = xx & yy
|
||||
xx = xx ^ yy
|
||||
xx = (not xx) as byte
|
||||
xx = (~xx) as byte
|
||||
xx++
|
||||
|
||||
ubyte angle
|
||||
|
||||
for angle in 0 to 180 {
|
||||
ubyte xx = math.sinr8u(angle)
|
||||
ubyte yy = math.cosr8u(angle) / 2
|
||||
sys.gfx_plot(xx, yy, 255)
|
||||
}
|
||||
|
||||
repeat {
|
||||
}
|
||||
ubx = not ubx
|
||||
ubx = ~ubx
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,6 @@ Currently NO support for 24 or 32 bits integers.
|
||||
Floating point operations are just 'f' typed regular instructions, and additionally there are
|
||||
a few fp conversion instructions to
|
||||
|
||||
*only* LOAD AND STORE instructions have a possible memory operand, all other instructions use only registers or immediate value.
|
||||
|
||||
|
||||
LOAD/STORE
|
||||
----------
|
||||
@ -96,6 +94,7 @@ incm address - memory at address += 1
|
||||
dec reg1 - reg1 = reg1-1
|
||||
decm address - memory at address -= 1
|
||||
neg reg1 - reg1 = sign negation of reg1
|
||||
negm address - sign negate memory at address
|
||||
add reg1, reg2 - reg1 += reg2 (unsigned + signed)
|
||||
sub reg1, reg2 - reg1 -= reg2 (unsigned + signed)
|
||||
mul reg1, reg2 - unsigned multiply reg1 *= reg2 note: byte*byte->byte, no type extension to word!
|
||||
@ -116,7 +115,9 @@ All have type b or w.
|
||||
and reg1, reg2 - reg1 = reg1 bitwise and reg2
|
||||
or reg1, reg2 - reg1 = reg1 bitwise or reg2
|
||||
xor reg1, reg2 - reg1 = reg1 bitwise xor reg2
|
||||
xorm reg1, address - memory = memory bitwise xor reg1
|
||||
not reg1 - reg1 = boolean not of reg1 (0->1 , ~0 -> 0)
|
||||
notm address - memory = boolean not of that memory (0->1 , ~0 -> 0)
|
||||
lsrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits + set Carry to shifted bit
|
||||
asrn reg1, reg2 - reg1 = multi-shift reg1 right by reg2 bits (signed) + set Carry to shifted bit
|
||||
lsln reg1, reg2 - reg1 = multi-shift reg1 left by reg2 bits + set Carry to shifted bit
|
||||
@ -211,6 +212,7 @@ enum class Opcode {
|
||||
DEC,
|
||||
DECM,
|
||||
NEG,
|
||||
NEGM,
|
||||
ADD,
|
||||
SUB,
|
||||
MUL,
|
||||
@ -226,7 +228,9 @@ enum class Opcode {
|
||||
AND,
|
||||
OR,
|
||||
XOR,
|
||||
XORM,
|
||||
NOT,
|
||||
NOTM,
|
||||
ASRN,
|
||||
LSRN,
|
||||
LSLN,
|
||||
@ -277,7 +281,10 @@ val OpcodesWithAddress = setOf(
|
||||
Opcode.STOREZM,
|
||||
Opcode.STOREZX,
|
||||
Opcode.INCM,
|
||||
Opcode.DECM
|
||||
Opcode.DECM,
|
||||
Opcode.NEGM,
|
||||
Opcode.NOTM,
|
||||
Opcode.XORM
|
||||
)
|
||||
|
||||
|
||||
@ -297,7 +304,7 @@ data class Instruction(
|
||||
val fpReg2: Int?=null, // 0-$ffff
|
||||
val value: Int?=null, // 0-$ffff
|
||||
val fpValue: Float?=null,
|
||||
val symbol: List<String>?=null // alternative to value
|
||||
val labelSymbol: List<String>?=null // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
||||
) {
|
||||
init {
|
||||
val formats = instructionFormats.getValue(opcode)
|
||||
@ -318,11 +325,11 @@ data class Instruction(
|
||||
throw IllegalArgumentException("too many registers (float)")
|
||||
|
||||
if (type==VmDataType.FLOAT) {
|
||||
if(format.fpValue && (fpValue==null && symbol==null))
|
||||
throw IllegalArgumentException("$opcode: missing a fp-value or symbol")
|
||||
if(format.fpValue && (fpValue==null && labelSymbol==null))
|
||||
throw IllegalArgumentException("$opcode: missing a fp-value or labelsymbol")
|
||||
} else {
|
||||
if(format.value && (value==null && symbol==null))
|
||||
throw IllegalArgumentException("$opcode: missing a value or symbol")
|
||||
if(format.value && (value==null && labelSymbol==null))
|
||||
throw IllegalArgumentException("$opcode: missing a value or labelsymbol")
|
||||
if (fpReg1 != null || fpReg2 != null)
|
||||
throw java.lang.IllegalArgumentException("$opcode: integer point instruction can't use floating point registers")
|
||||
}
|
||||
@ -361,7 +368,7 @@ data class Instruction(
|
||||
result.add(it.toString())
|
||||
result.add(",")
|
||||
}
|
||||
symbol?.let {
|
||||
labelSymbol?.let {
|
||||
result.add("_" + it.joinToString("."))
|
||||
}
|
||||
if(result.last() == ",")
|
||||
@ -464,6 +471,7 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.DEC to InstructionFormat.from("BW,r1"),
|
||||
Opcode.DECM to InstructionFormat.from("BW,v"),
|
||||
Opcode.NEG to InstructionFormat.from("BW,r1 | F,fr1"),
|
||||
Opcode.NEGM to InstructionFormat.from("BW,v | F,v"),
|
||||
Opcode.ADD to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||
Opcode.SUB to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||
Opcode.MUL to InstructionFormat.from("BW,r1,r2 | F,fr1,fr2"),
|
||||
@ -478,7 +486,9 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.AND to InstructionFormat.from("BW,r1,r2"),
|
||||
Opcode.OR to InstructionFormat.from("BW,r1,r2"),
|
||||
Opcode.XOR to InstructionFormat.from("BW,r1,r2"),
|
||||
Opcode.XORM to InstructionFormat.from("BW,r1,v"),
|
||||
Opcode.NOT to InstructionFormat.from("BW,r1"),
|
||||
Opcode.NOTM to InstructionFormat.from("BW,v"),
|
||||
Opcode.ASRN to InstructionFormat.from("BW,r1,r2"),
|
||||
Opcode.LSRN to InstructionFormat.from("BW,r1,r2"),
|
||||
Opcode.LSLN to InstructionFormat.from("BW,r1,r2"),
|
||||
|
@ -17,7 +17,7 @@ class TestInstructions: FunSpec({
|
||||
ins.reg1 shouldBe null
|
||||
ins.reg2 shouldBe null
|
||||
ins.value shouldBe null
|
||||
ins.symbol shouldBe null
|
||||
ins.labelSymbol shouldBe null
|
||||
ins.toString() shouldBe "nop"
|
||||
}
|
||||
|
||||
@ -28,18 +28,18 @@ class TestInstructions: FunSpec({
|
||||
ins.reg1 shouldBe 42
|
||||
ins.reg2 shouldBe null
|
||||
ins.value shouldBe 9999
|
||||
ins.symbol shouldBe null
|
||||
ins.labelSymbol shouldBe null
|
||||
ins.toString() shouldBe "bz.b r42,9999"
|
||||
}
|
||||
|
||||
test("with label") {
|
||||
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, symbol = listOf("a","b","c"))
|
||||
val ins = Instruction(Opcode.BZ, VmDataType.WORD, reg1=11, labelSymbol = listOf("a","b","c"))
|
||||
ins.opcode shouldBe Opcode.BZ
|
||||
ins.type shouldBe VmDataType.WORD
|
||||
ins.reg1 shouldBe 11
|
||||
ins.reg2 shouldBe null
|
||||
ins.value shouldBe null
|
||||
ins.symbol shouldBe listOf("a","b","c")
|
||||
ins.labelSymbol shouldBe listOf("a","b","c")
|
||||
ins.toString() shouldBe "bz.w r11,_a.b.c"
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user