mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
vm: ifElse codegen uses proper branching instructions now
This commit is contained in:
parent
a7df828932
commit
6e31eebfb5
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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?
|
||||||
|
@ -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++
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user