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) { class PtIfElse(position: Position) : PtNode(position) {
val condition: PtExpression val condition: PtBinaryExpression
get() = children[0] as PtExpression get() = children[0] as PtBinaryExpression
val ifScope: PtNodeGroup val ifScope: PtNodeGroup
get() = children[1] as PtNodeGroup get() = children[1] as PtNodeGroup
val elseScope: PtNodeGroup val elseScope: PtNodeGroup

View File

@ -465,46 +465,95 @@ class CodeGen(internal val program: PtProgram,
} }
private fun translate(ifElse: PtIfElse): VmCodeChunk { private fun translate(ifElse: PtIfElse): VmCodeChunk {
var branch = Opcode.BZ if(ifElse.condition.operator !in ComparisonOperators)
var condition = ifElse.condition throw AssemblyError("if condition should only be a binary comparison expression")
val cond = ifElse.condition as? PtBinaryExpression val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
if(cond!=null && constValue(cond.right)==0.0) { val vmDt = vmType(ifElse.condition.type)
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 code = VmCodeChunk() val code = VmCodeChunk()
code += expressionEval.translateExpression(condition, conditionReg, -1)
if(ifElse.elseScope.children.isNotEmpty()) { fun translateNonZeroComparison(): VmCodeChunk {
// if and else parts val elseBranch = when(ifElse.condition.operator) {
val elseLabel = createLabelName() "==" -> Opcode.BNE
val afterIfLabel = createLabelName() "!=" -> Opcode.BEQ
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = elseLabel) "<" -> if(signed) Opcode.BGES else Opcode.BGE
code += translateNode(ifElse.ifScope) ">" -> if(signed) Opcode.BLES else Opcode.BLE
code += VmCodeInstruction(Opcode.JUMP, symbol = afterIfLabel) "<=" -> if(signed) Opcode.BGTS else Opcode.BGT
code += VmCodeLabel(elseLabel) ">=" -> if(signed) Opcode.BLTS else Opcode.BLT
code += translateNode(ifElse.elseScope) else -> throw AssemblyError("invalid comparison operator")
code += VmCodeLabel(afterIfLabel) }
} else {
// only if part val leftReg = vmRegisters.nextFree()
val afterIfLabel = createLabelName() val rightReg = vmRegisters.nextFree()
code += VmCodeInstruction(branch, vmDt, reg1=conditionReg, symbol = afterIfLabel) code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
code += translateNode(ifElse.ifScope) code += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1)
code += VmCodeLabel(afterIfLabel) 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 { private fun translate(postIncrDecr: PtPostIncrDecr): VmCodeChunk {
val code = VmCodeChunk() val code = VmCodeChunk()
val operationMem: Opcode val operationMem: Opcode
@ -603,7 +652,7 @@ class CodeGen(internal val program: PtProgram,
} }
private fun translate(assignment: PtAssignment): VmCodeChunk { 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. // note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
if(assignment.target.children.single() is PtMachineRegister) if(assignment.target.children.single() is PtMachineRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister") 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 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: get rid of all the conditional set instructions
- vm: add more instructions operating directly on memory instead of only registers? - 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. - in-place modifiying functions (rol, ror, ..) don't accept a memory address but require a memory-read expression. that is weird.
- complete the Inliner - 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? - 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 lowb = 4
ubyte highb = $ea 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 if lowb==3
lowb++ lowb++

View File

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