mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +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) {
|
||||
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
|
||||
|
@ -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")
|
||||
|
@ -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?
|
||||
|
@ -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++
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user