mirror of
https://github.com/irmen/prog8.git
synced 2025-02-27 03:29:22 +00:00
attempt to make if-statement not use stack eval anymore
This commit is contained in:
parent
a9b0400d13
commit
857724c7e6
@ -1019,10 +1019,6 @@ class AsmGen(private val program: Program,
|
||||
requireComparisonExpression(stmt.condition) // IfStatement: condition must be of form 'x <comparison> <value>'
|
||||
val booleanCondition = stmt.condition as BinaryExpression
|
||||
|
||||
// DISABLED FOR NOW:
|
||||
// if(!booleanCondition.left.isSimple || !booleanCondition.right.isSimple)
|
||||
// throw AssemblyError("both operands for if comparison expression should have been simplified")
|
||||
|
||||
if (stmt.elsepart.isEmpty()) {
|
||||
val endLabel = makeLabel("if_end")
|
||||
expressionsAsmGen.translateComparisonExpressionWithJumpIfFalse(booleanCondition, endLabel)
|
||||
@ -1197,6 +1193,7 @@ $repeatLabel lda $counterVar
|
||||
private fun translate(stmt: WhileLoop) {
|
||||
requireComparisonExpression(stmt.condition) // WhileLoop: condition must be of form 'x <comparison> <value>'
|
||||
val booleanCondition = stmt.condition as BinaryExpression
|
||||
|
||||
val whileLabel = makeLabel("while")
|
||||
val endLabel = makeLabel("whileend")
|
||||
loopEndLabels.push(endLabel)
|
||||
@ -1211,6 +1208,7 @@ $repeatLabel lda $counterVar
|
||||
private fun translate(stmt: UntilLoop) {
|
||||
requireComparisonExpression(stmt.condition) // UntilLoop: condition must be of form 'x <comparison> <value>'
|
||||
val booleanCondition = stmt.condition as BinaryExpression
|
||||
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
val endLabel = makeLabel("repeatend")
|
||||
loopEndLabels.push(endLabel)
|
||||
|
@ -30,7 +30,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
is ArrayIndexedExpression -> translateExpression(expression)
|
||||
is TypecastExpression -> translateExpression(expression)
|
||||
is AddressOf -> translateExpression(expression)
|
||||
is DirectMemoryRead -> translateDirectMemReadExpression(expression, true)
|
||||
is DirectMemoryRead -> translateDirectMemReadExpressionToRegAorStack(expression, true)
|
||||
is NumericLiteralValue -> translateExpression(expression)
|
||||
is IdentifierReference -> translateExpression(expression)
|
||||
is FunctionCall -> translateFunctionCallResultOntoStack(expression)
|
||||
@ -40,6 +40,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move this function to AsmGen class so that this one only exposes the toplevel translateExpression()
|
||||
internal fun translateComparisonExpressionWithJumpIfFalse(expr: BinaryExpression, jumpIfFalseLabel: String) {
|
||||
// This is a helper routine called from while, do-util, and if expressions to generate optimized conditional branching code.
|
||||
// First, if it is of the form: <constvalue> <comparison> X , then flip the expression so the constant is always the right operand.
|
||||
@ -439,7 +440,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
}
|
||||
else if (left is DirectMemoryRead) {
|
||||
return if(rightConstVal.number.toInt()!=0) {
|
||||
translateDirectMemReadExpression(left, false)
|
||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
||||
code("#${rightConstVal.number}")
|
||||
}
|
||||
else
|
||||
@ -663,7 +664,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
asmgen.out(" beq $jumpIfFalseLabel")
|
||||
}
|
||||
else if (left is DirectMemoryRead) {
|
||||
translateDirectMemReadExpression(left, false)
|
||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
||||
return if(rightConstVal.number.toInt()!=0)
|
||||
code("#${rightConstVal.number}")
|
||||
else
|
||||
@ -828,7 +829,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
asmgen.out(" bne $jumpIfFalseLabel")
|
||||
}
|
||||
else if (left is DirectMemoryRead) {
|
||||
translateDirectMemReadExpression(left, false)
|
||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
||||
return if(rightConstVal.number.toInt()!=0)
|
||||
code("#${rightConstVal.number}")
|
||||
else
|
||||
@ -996,7 +997,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
}
|
||||
else if (left is DirectMemoryRead) {
|
||||
if(rightConstVal.number.toInt()!=0) {
|
||||
translateDirectMemReadExpression(left, false)
|
||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
||||
code("#${rightConstVal.number}")
|
||||
}
|
||||
return
|
||||
@ -1139,7 +1140,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
asmgen.out(" bne $jumpIfFalseLabel")
|
||||
}
|
||||
else if (left is DirectMemoryRead) {
|
||||
translateDirectMemReadExpression(left, false)
|
||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
||||
return if(rightConstVal.number.toInt()!=0)
|
||||
code("#${rightConstVal.number}")
|
||||
else
|
||||
@ -1176,7 +1177,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
asmgen.out(" beq $jumpIfFalseLabel")
|
||||
}
|
||||
else if (left is DirectMemoryRead) {
|
||||
translateDirectMemReadExpression(left, false)
|
||||
translateDirectMemReadExpressionToRegAorStack(left, false)
|
||||
return if(rightConstVal.number.toInt()!=0)
|
||||
code("#${rightConstVal.number}")
|
||||
else
|
||||
@ -1766,7 +1767,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
asmgen.out(" lda #<$name | sta P8ESTACK_LO,x | lda #>$name | sta P8ESTACK_HI,x | dex")
|
||||
}
|
||||
|
||||
internal fun translateDirectMemReadExpression(expr: DirectMemoryRead, pushResultOnEstack: Boolean) {
|
||||
// TODO move this function to another class so that this one only exposes the toplevel translateExpression()
|
||||
internal fun translateDirectMemReadExpressionToRegAorStack(expr: DirectMemoryRead, pushResultOnEstack: Boolean) {
|
||||
|
||||
fun assignViaExprEval() {
|
||||
asmgen.assignExpressionToVariable(expr.addressExpression, "P8ZP_SCRATCH_W2", DataType.UWORD, null)
|
||||
|
@ -209,7 +209,7 @@ internal class AsmAssignment(val source: AsmAssignSource,
|
||||
if(target.register !in arrayOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY))
|
||||
require(source.datatype != DataType.UNDEFINED) { "must not be placeholder/undefined datatype" }
|
||||
require(memsizer.memorySize(source.datatype) <= memsizer.memorySize(target.datatype)) {
|
||||
"source storage size must be less or equal to target datatype storage size"
|
||||
"source storage size must be less or equal to target datatype storage size at $position"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -657,14 +657,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
private fun inplaceModification_byte_memread_to_variable(name: String, dt: DataType, operator: String, memread: DirectMemoryRead) {
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc $name
|
||||
sta $name""")
|
||||
}
|
||||
"-" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out("""
|
||||
sta P8ZP_SCRATCH_B1
|
||||
lda $name
|
||||
@ -673,15 +673,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
sta $name""")
|
||||
}
|
||||
"|", "or" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out(" ora $name | sta $name")
|
||||
}
|
||||
"&", "and" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out(" and $name | sta $name")
|
||||
}
|
||||
"^", "xor" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out(" eor $name | sta $name")
|
||||
}
|
||||
// TODO: tuned code for more operators
|
||||
@ -694,7 +694,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
private fun inplaceModification_word_memread_to_variable(name: String, dt: DataType, operator: String, memread: DirectMemoryRead) {
|
||||
when (operator) {
|
||||
"+" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out("""
|
||||
clc
|
||||
adc $name
|
||||
@ -704,7 +704,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
+""")
|
||||
}
|
||||
"-" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out("""
|
||||
sta P8ZP_SCRATCH_B1
|
||||
lda $name
|
||||
@ -716,11 +716,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
+""")
|
||||
}
|
||||
"|", "or" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out(" ora $name | sta $name")
|
||||
}
|
||||
"&", "and" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out(" and $name | sta $name")
|
||||
if(dt in WordDatatypes) {
|
||||
if(asmgen.isTargetCpu(CpuType.CPU65c02))
|
||||
@ -730,7 +730,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
"^", "xor" -> {
|
||||
exprAsmGen.translateDirectMemReadExpression(memread, false)
|
||||
exprAsmGen.translateDirectMemReadExpressionToRegAorStack(memread, false)
|
||||
asmgen.out(" eor $name | sta $name")
|
||||
}
|
||||
// TODO: tuned code for more operators
|
||||
|
@ -6,12 +6,14 @@ prog8_lib {
|
||||
%asminclude "library:prog8_lib.asm"
|
||||
%asminclude "library:prog8_funcs.asm"
|
||||
|
||||
; to store intermediary expression results for return values (hopefully allocated on ZP to reduce code size):
|
||||
; to store intermediary expression results for return values:
|
||||
; NOTE: these variables are used in the StatementReorderer and StatementOptimizer
|
||||
uword @zp retval_interm_uw
|
||||
word @zp retval_interm_w
|
||||
ubyte @zp retval_interm_ub
|
||||
byte @zp retval_interm_b
|
||||
word retval_interm_w2
|
||||
byte retval_interm_b2
|
||||
|
||||
|
||||
asmsub pattern_match(str string @AY, str pattern @R0) clobbers(Y) -> ubyte @A {
|
||||
|
@ -11,6 +11,7 @@ import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.compiler.astprocessing.isSubroutineParameter
|
||||
import prog8.compiler.target.AssemblyError
|
||||
import prog8.compilerinterface.*
|
||||
|
||||
|
||||
@ -201,12 +202,74 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
|
||||
return listOf(IAstModification.ReplaceNode(ifStatement.condition, booleanExpr, ifStatement))
|
||||
}
|
||||
|
||||
if((binExpr.operator=="==" || binExpr.operator=="!=") &&
|
||||
(binExpr.left as? NumericLiteralValue)?.number==0 &&
|
||||
if((binExpr.left as? NumericLiteralValue)?.number==0 &&
|
||||
(binExpr.right as? NumericLiteralValue)?.number!=0)
|
||||
throw InternalCompilerException("if 0==X should have been swapped to if X==0")
|
||||
throw FatalAstException("0==X should have been swapped to if X==0")
|
||||
|
||||
return noModifications
|
||||
// simplify the conditional expression, introduce simple assignments if required.
|
||||
// TODO sometimes this increases code size significantly (Petaxian) !!! FIX THIS
|
||||
val simplify = simplifyConditionalExpression(binExpr)
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
if(simplify.rightVarAssignment!=null) {
|
||||
modifications += IAstModification.ReplaceNode(binExpr.right, simplify.rightOperandReplacement!!, binExpr)
|
||||
modifications += IAstModification.InsertBefore(ifStatement, simplify.rightVarAssignment, parent as IStatementContainer)
|
||||
}
|
||||
if(simplify.leftVarAssignment!=null) {
|
||||
modifications += IAstModification.ReplaceNode(binExpr.left, simplify.leftOperandReplacement!!, binExpr)
|
||||
modifications += IAstModification.InsertBefore(ifStatement, simplify.leftVarAssignment, parent as IStatementContainer)
|
||||
}
|
||||
|
||||
return modifications
|
||||
}
|
||||
|
||||
private class CondExprSimplificationResult(
|
||||
val leftVarAssignment: Assignment?,
|
||||
val leftOperandReplacement: Expression?,
|
||||
val rightVarAssignment: Assignment?,
|
||||
val rightOperandReplacement: Expression?
|
||||
)
|
||||
|
||||
private fun simplifyConditionalExpression(expr: BinaryExpression): CondExprSimplificationResult {
|
||||
var leftAssignment: Assignment? = null
|
||||
var leftOperandReplacement: Expression? = null
|
||||
var rightAssignment: Assignment? = null
|
||||
var rightOperandReplacement: Expression? = null
|
||||
if(!expr.left.isSimple) {
|
||||
val dt = expr.left.inferType(program)
|
||||
val name = when {
|
||||
dt.istype(DataType.UBYTE) -> listOf("cx16","r15L")
|
||||
dt.istype(DataType.UWORD) -> listOf("cx16","r15")
|
||||
dt.istype(DataType.BYTE) -> listOf("prog8_lib","retval_interm_b")
|
||||
dt.istype(DataType.WORD) -> listOf("prog8_lib","retval_interm_w")
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
leftOperandReplacement = IdentifierReference(name, expr.position)
|
||||
leftAssignment = Assignment(
|
||||
AssignTarget(IdentifierReference(name, expr.position), null, null, expr.position),
|
||||
expr.left,
|
||||
expr.position
|
||||
)
|
||||
}
|
||||
if(!expr.right.isSimple) {
|
||||
val dt = expr.right.inferType(program)
|
||||
val name = when {
|
||||
dt.istype(DataType.UBYTE) -> listOf("prog8_lib","retval_interm_ub")
|
||||
dt.istype(DataType.UWORD) -> listOf("prog8_lib","retval_interm_uw")
|
||||
dt.istype(DataType.BYTE) -> listOf("prog8_lib","retval_interm_b2")
|
||||
dt.istype(DataType.WORD) -> listOf("prog8_lib","retval_interm_w2")
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
rightOperandReplacement = IdentifierReference(name, expr.position)
|
||||
rightAssignment = Assignment(
|
||||
AssignTarget(IdentifierReference(name, expr.position), null, null, expr.position),
|
||||
expr.right,
|
||||
expr.position
|
||||
)
|
||||
}
|
||||
return CondExprSimplificationResult(
|
||||
leftAssignment, leftOperandReplacement,
|
||||
rightAssignment, rightOperandReplacement
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
@ -224,6 +287,13 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
|
||||
val booleanExpr = BinaryExpression(untilLoop.condition, "!=", NumericLiteralValue.optimalInteger(0, untilLoop.condition.position), untilLoop.condition.position)
|
||||
return listOf(IAstModification.ReplaceNode(untilLoop.condition, booleanExpr, untilLoop))
|
||||
}
|
||||
|
||||
if((binExpr.left as? NumericLiteralValue)?.number==0 &&
|
||||
(binExpr.right as? NumericLiteralValue)?.number!=0)
|
||||
throw FatalAstException("0==X should have been swapped to if X==0")
|
||||
|
||||
// TODO simplify conditional expression like in if-statement
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
@ -242,6 +312,13 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
|
||||
val booleanExpr = BinaryExpression(whileLoop.condition, "!=", NumericLiteralValue.optimalInteger(0, whileLoop.condition.position), whileLoop.condition.position)
|
||||
return listOf(IAstModification.ReplaceNode(whileLoop.condition, booleanExpr, whileLoop))
|
||||
}
|
||||
|
||||
if((binExpr.left as? NumericLiteralValue)?.number==0 &&
|
||||
(binExpr.right as? NumericLiteralValue)?.number!=0)
|
||||
throw FatalAstException("0==X should have been swapped to if X==0")
|
||||
|
||||
// TODO simplify conditional expression like in if-statement
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,6 @@ internal class AstChecker(private val program: Program,
|
||||
super.visit(forLoop)
|
||||
}
|
||||
|
||||
|
||||
override fun visit(jump: Jump) {
|
||||
val ident = jump.identifier
|
||||
if(ident!=null) {
|
||||
|
@ -3,7 +3,8 @@ TODO
|
||||
|
||||
For next compiler release (7.3)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
- if-statement expression simplification sometimes increases code size (Petaxian) FIX THIS!
|
||||
- add expression simplification to while and until loops as well.
|
||||
|
||||
|
||||
Blocked by Commander-x16 v39 release
|
||||
@ -16,7 +17,6 @@ Future
|
||||
^^^^^^
|
||||
- fix the asm-labels problem (github issue #62)
|
||||
- find a way to optimize asm-subroutine param passing where it now sometimes uses the evalstack?
|
||||
- [complicated?] find a way to optimize if-statement codegen so that "if var & %10000" doesn't use evalstack & subroutine call, but also that the simple case "if X {...}" remains fast
|
||||
- document the various compiler command line options in more detail. See "Compiling program code" in the docs
|
||||
- get rid of all TODO's in the code
|
||||
- improve testability further, add more tests
|
||||
|
@ -3,16 +3,18 @@
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
uword xw
|
||||
ubyte xb
|
||||
|
||||
sub sub1() -> uword {
|
||||
return xw+xb
|
||||
}
|
||||
|
||||
sub start() {
|
||||
|
||||
xw=sub1()
|
||||
ubyte unused ; TODO FIX : why is this not removed as an unused variable?
|
||||
|
||||
ubyte iteration_in_progress
|
||||
uword num_bytes
|
||||
|
||||
ubyte qq = not iteration_in_progress or not num_bytes ; TODO FIX COMPILER CRASH (STORAGE SIZE)
|
||||
|
||||
if not iteration_in_progress or not num_bytes
|
||||
return
|
||||
|
||||
; word xx=0
|
||||
; word[] xarr = [1,2,3]
|
||||
@ -34,13 +36,14 @@ main {
|
||||
; txt.print("xx is zero\n")
|
||||
; }
|
||||
|
||||
; ubyte yy=$30
|
||||
ubyte yy=$30
|
||||
; ubyte zz=9
|
||||
; sys.memset(xx+200, yy*2, ~yy)
|
||||
;
|
||||
; if yy & %10000 {
|
||||
; yy++
|
||||
; }
|
||||
|
||||
if yy & %10000 {
|
||||
yy++
|
||||
}
|
||||
;
|
||||
; @($c030) = 10
|
||||
; @(~xx) *= 2
|
||||
|
Loading…
x
Reference in New Issue
Block a user