vm: ifElse codegen uses proper branching instructions now

This commit is contained in:
Irmen de Jong 2022-05-12 21:26:17 +02:00
parent a7df828932
commit 6e31eebfb5
5 changed files with 111 additions and 49 deletions

View File

@ -95,8 +95,8 @@ class PtForLoop(position: Position) : PtNode(position) {
class PtIfElse(position: Position) : PtNode(position) {
val condition: PtExpression
get() = children[0] as PtExpression
val condition: PtBinaryExpression
get() = children[0] as PtBinaryExpression
val ifScope: PtNodeGroup
get() = children[1] as PtNodeGroup
val elseScope: PtNodeGroup

View File

@ -465,46 +465,95 @@ class CodeGen(internal val program: PtProgram,
}
private fun translate(ifElse: PtIfElse): VmCodeChunk {
var branch = Opcode.BZ
var condition = ifElse.condition
if(ifElse.condition.operator !in ComparisonOperators)
throw AssemblyError("if condition should only be a binary comparison expression")
val cond = ifElse.condition as? PtBinaryExpression
if(cond!=null && constValue(cond.right)==0.0) {
if(cond.operator == "==") {
// if X==0 ... so we branch on Not-zero instead.
branch = Opcode.BNZ
condition = cond.left
}
else if(cond.operator == "!=") {
// if X!=0 ... so we keep branching on Zero.
condition = cond.left
}
}
val conditionReg = vmRegisters.nextFree()
val vmDt = vmType(condition.type)
val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
val vmDt = vmType(ifElse.condition.type)
val code = VmCodeChunk()
code += expressionEval.translateExpression(condition, conditionReg, -1)
if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope)
code += VmCodeLabel(afterIfLabel)
} else {
// only if part
val afterIfLabel = createLabelName()
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
fun translateNonZeroComparison(): VmCodeChunk {
val elseBranch = when(ifElse.condition.operator) {
"==" -> Opcode.BNE
"!=" -> Opcode.BEQ
"<" -> if(signed) Opcode.BGES else Opcode.BGE
">" -> if(signed) Opcode.BLES else Opcode.BLE
"<=" -> if(signed) Opcode.BGTS else Opcode.BGT
">=" -> if(signed) Opcode.BLTS else Opcode.BLT
else -> throw AssemblyError("invalid comparison operator")
}
val leftReg = vmRegisters.nextFree()
val rightReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
code += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1)
if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, symbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Opcode.JUMP, symbol = 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 += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
}
return code
}
return code
fun translateZeroComparison(): VmCodeChunk {
fun equalOrNotEqualZero(elseBranch: Opcode): VmCodeChunk {
val leftReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, symbol = elseLabel)
code += translateNode(ifElse.ifScope)
code += VmCodeInstruction(Opcode.JUMP, symbol = 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 += translateNode(ifElse.ifScope)
code += VmCodeLabel(afterIfLabel)
}
return code
}
return when (ifElse.condition.operator) {
"==" -> {
// if X==0 ... so we just branch on left expr is Not-zero.
equalOrNotEqualZero(Opcode.BNZ)
}
"!=" -> {
// if X!=0 ... so we just branch on left expr is Zero.
equalOrNotEqualZero(Opcode.BZ)
}
else -> {
// another comparison against 0, just use regular codegen for this.
translateNonZeroComparison()
}
}
}
return if(constValue(ifElse.condition.right)==0.0)
translateZeroComparison()
else
translateNonZeroComparison()
}
private fun translate(postIncrDecr: PtPostIncrDecr): VmCodeChunk {
val code = VmCodeChunk()
val operationMem: Opcode
@ -603,7 +652,7 @@ class CodeGen(internal val program: PtProgram,
}
private fun translate(assignment: PtAssignment): VmCodeChunk {
// TODO can in-place assignments be optimized more?
// TODO can in-place assignments be optimized more? use special memory versions of instructions instead of register ones?
// 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")

View File

@ -3,9 +3,9 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm: use more instructions in codegen: branching, don't use the conditional set instructions here
- vm: get rid of all the conditional set instructions
- vm: add more instructions operating directly on memory instead of only registers?
- vm: check array type in PtAssignTarget
- in-place modifiying functions (rol, ror, ..) don't accept a memory address but require a memory-read expression. that is weird.
- 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?

View File

@ -28,6 +28,19 @@ main {
ubyte lowb = 4
ubyte highb = $ea
if lowb+4
lowb++
if math.sin8u(lowb)
lowb++
if lowb
lowb++
if lowb==0
lowb++
if lowb!=0
lowb++
if lowb==3
lowb++

View File

@ -184,16 +184,16 @@ enum class Opcode {
BSTPOS,
BZ,
BNZ,
BEQ, // TODO not used in codegen??? == nonzero
BNE, // TODO not used in codegen??? != nonzero
BLT, // TODO not used in codegen??? <
BLTS, // TODO not used in codegen??? <
BGT, // TODO not used in codegen??? >
BGTS, // TODO not used in codegen??? >
BLE, // TODO should be used in codegen conditional branch too
BLES, // TODO should be used in codegen conditional branch too
BGE, // TODO not used in codegen??? >=
BGES, // TODO not used in codegen??? >=
BEQ,
BNE,
BLT,
BLTS,
BGT,
BGTS,
BLE,
BLES,
BGE,
BGES,
SEQ,
SNE,
SLT,