mirror of
https://github.com/irmen/prog8.git
synced 2024-11-18 19:12:44 +00:00
attempts to optimize in-place assignments
This commit is contained in:
parent
b8b9244ffa
commit
e4fe1d2b8d
@ -41,6 +41,17 @@ interface IAstModification {
|
||||
}
|
||||
}
|
||||
|
||||
class InsertLast(val stmt: Statement, val parent: Node) : IAstModification {
|
||||
override fun perform() {
|
||||
if(parent is INameScope) {
|
||||
parent.statements.add(stmt)
|
||||
stmt.linkParents(parent)
|
||||
} else {
|
||||
throw FatalAstException("parent of an insert modification is not an INameScope")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InsertAfter(val after: Statement, val stmt: Statement, val parent: Node) : IAstModification {
|
||||
override fun perform() {
|
||||
if(parent is INameScope) {
|
||||
|
@ -54,7 +54,7 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
if(block.isInLibrary) {
|
||||
return listOf(
|
||||
IAstModification.Remove(block, parent),
|
||||
IAstModification.InsertAfter(parent.statements.last(), block, parent)
|
||||
IAstModification.InsertLast(block, parent)
|
||||
)
|
||||
}
|
||||
|
||||
@ -71,7 +71,6 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
)
|
||||
}
|
||||
}
|
||||
reorderVardeclsAndDirectives(subroutine.statements)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
@ -104,18 +103,7 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
|
||||
override fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
if(assignment.aug_op!=null) {
|
||||
val leftOperand: Expression =
|
||||
when {
|
||||
assignment.target.register != null -> RegisterExpr(assignment.target.register!!, assignment.target.position)
|
||||
assignment.target.identifier != null -> assignment.target.identifier!!
|
||||
assignment.target.arrayindexed != null -> assignment.target.arrayindexed!!
|
||||
assignment.target.memoryAddress != null -> DirectMemoryRead(assignment.target.memoryAddress!!.addressExpression, assignment.value.position)
|
||||
else -> throw FatalAstException("strange assignment")
|
||||
}
|
||||
|
||||
val expression = BinaryExpression(leftOperand, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
|
||||
val convertedAssignment = Assignment(assignment.target, null, expression, assignment.position)
|
||||
return listOf(IAstModification.ReplaceNode(assignment, convertedAssignment, parent))
|
||||
return listOf(IAstModification.ReplaceNode(assignment, assignment.asDesugaredNonaugmented(), parent))
|
||||
}
|
||||
|
||||
val valueType = assignment.value.inferType(program)
|
||||
|
@ -371,6 +371,31 @@ open class Assignment(var target: AssignTarget, val aug_op : String?, var value:
|
||||
override fun toString(): String {
|
||||
return("Assignment(augop: $aug_op, target: $target, value: $value, pos=$position)")
|
||||
}
|
||||
|
||||
fun asDesugaredNonaugmented(): Assignment {
|
||||
if(aug_op==null)
|
||||
return this
|
||||
|
||||
val leftOperand: Expression =
|
||||
when {
|
||||
target.register != null -> RegisterExpr(target.register!!, target.position)
|
||||
target.identifier != null -> target.identifier!!
|
||||
target.arrayindexed != null -> target.arrayindexed!!
|
||||
target.memoryAddress != null -> DirectMemoryRead(target.memoryAddress!!.addressExpression, value.position)
|
||||
else -> throw FatalAstException("strange this")
|
||||
}
|
||||
|
||||
val assignment =
|
||||
if(aug_op=="setvalue") {
|
||||
Assignment(target, null, value, position)
|
||||
} else {
|
||||
val expression = BinaryExpression(leftOperand, aug_op.substringBeforeLast('='), value, position)
|
||||
Assignment(target, null, expression, position)
|
||||
}
|
||||
assignment.linkParents(parent)
|
||||
|
||||
return assignment
|
||||
}
|
||||
}
|
||||
|
||||
data class AssignTarget(val register: Register?,
|
||||
|
@ -41,11 +41,13 @@ fun compileProgram(filepath: Path,
|
||||
optimizeAst(programAst, errors)
|
||||
postprocessAst(programAst, errors, compilationOptions)
|
||||
|
||||
// printAst(programAst)
|
||||
printAst(programAst) // TODO
|
||||
|
||||
if(writeAssembly)
|
||||
programName = writeAssembly(programAst, errors, outputDir, optimize, compilationOptions)
|
||||
}
|
||||
System.out.flush()
|
||||
System.err.flush()
|
||||
println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.")
|
||||
return CompilationResult(true, programAst, programName, importedFiles)
|
||||
|
||||
@ -186,12 +188,15 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
|
||||
val zeropage = CompilationTarget.machine.getZeropage(compilerOptions)
|
||||
programAst.prepareAsmVariablesAndReturns(errors)
|
||||
errors.handle()
|
||||
|
||||
val assembly = CompilationTarget.asmGenerator(
|
||||
programAst,
|
||||
errors,
|
||||
zeropage,
|
||||
compilerOptions,
|
||||
outputDir).compileToAssembly(optimize)
|
||||
assembly.assemble(compilerOptions)
|
||||
errors.handle()
|
||||
return assembly.name
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.ErrorReporter
|
||||
import prog8.ast.base.NumericDatatypes
|
||||
import prog8.ast.base.VarDeclType
|
||||
import prog8.ast.expressions.BinaryExpression
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstModification
|
||||
@ -60,7 +61,7 @@ class AsmVariableAndReturnsPreparer(val program: Program, val errors: ErrorRepor
|
||||
&& subroutine.amountOfRtsInAsm()==0
|
||||
&& subroutine.statements.lastOrNull {it !is VarDecl } !is Return
|
||||
&& subroutine.statements.last() !is Subroutine) {
|
||||
mods += IAstModification.InsertAfter(subroutine.statements.last(), returnStmt, subroutine)
|
||||
mods += IAstModification.InsertLast(returnStmt, subroutine)
|
||||
}
|
||||
|
||||
// precede a subroutine with a return to avoid falling through into the subroutine from code above it
|
||||
@ -77,4 +78,22 @@ class AsmVariableAndReturnsPreparer(val program: Program, val errors: ErrorRepor
|
||||
|
||||
return mods
|
||||
}
|
||||
|
||||
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
// modify A = A + 5 back into augmented form A += 5 for easier code generation for optimized in-place assignments
|
||||
// also to put code generation stuff together, single value assignment (A = 5) is converted to a special
|
||||
// augmented form as wel (with the operator "setvalue")
|
||||
if(assignment.aug_op==null) {
|
||||
val binExpr = assignment.value as? BinaryExpression
|
||||
if (binExpr != null) {
|
||||
if (assignment.target.isSameAs(binExpr.left)) {
|
||||
val augAssignment = Assignment(assignment.target, binExpr.operator + "=", binExpr.right, assignment.position)
|
||||
return listOf(IAstModification.ReplaceNode(assignment, augAssignment, parent))
|
||||
}
|
||||
}
|
||||
val augAssignment = Assignment(assignment.target, "setvalue", assignment.value, assignment.position)
|
||||
return listOf(IAstModification.ReplaceNode(assignment, augAssignment, parent))
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package prog8.compiler.target
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.ErrorReporter
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.Zeropage
|
||||
import java.nio.file.Path
|
||||
@ -12,6 +13,6 @@ internal interface CompilationTarget {
|
||||
lateinit var machine: IMachineDefinition
|
||||
lateinit var encodeString: (str: String, altEncoding: Boolean) -> List<Short>
|
||||
lateinit var decodeString: (bytes: List<Short>, altEncoding: Boolean) -> String
|
||||
lateinit var asmGenerator: (Program, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator
|
||||
lateinit var asmGenerator: (Program, ErrorReporter, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
internal class AsmGen(private val program: Program,
|
||||
private val errors: ErrorReporter,
|
||||
private val zeropage: Zeropage,
|
||||
private val options: CompilationOptions,
|
||||
private val outputDir: Path): IAssemblyGenerator {
|
||||
@ -38,7 +39,7 @@ internal class AsmGen(private val program: Program,
|
||||
private val forloopsAsmGen = ForLoopsAsmGen(program, this)
|
||||
private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this)
|
||||
private val functioncallAsmGen = FunctionCallAsmGen(program, this)
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, this)
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, errors, this)
|
||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this)
|
||||
internal val loopEndLabels = ArrayDeque<String>()
|
||||
internal val loopContinueLabels = ArrayDeque<String>()
|
||||
@ -913,6 +914,7 @@ internal class AsmGen(private val program: Program,
|
||||
val indexName = asmIdentifierName(index)
|
||||
out(" lda $indexName")
|
||||
}
|
||||
// TODO optimize more cases
|
||||
else -> {
|
||||
expressionsAsmGen.translateExpression(index)
|
||||
out(" inx | lda $ESTACK_LO_HEX,x")
|
||||
@ -920,6 +922,28 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translateArrayIndexIntoY(expr: ArrayIndexedExpression) {
|
||||
when (val index = expr.arrayspec.index) {
|
||||
is NumericLiteralValue -> throw AssemblyError("this should be optimized directly")
|
||||
is RegisterExpr -> {
|
||||
when (index.register) {
|
||||
Register.A -> out(" tay")
|
||||
Register.X -> out(" txa | tay")
|
||||
Register.Y -> {}
|
||||
}
|
||||
}
|
||||
is IdentifierReference -> {
|
||||
val indexName = asmIdentifierName(index)
|
||||
out(" ldy $indexName")
|
||||
}
|
||||
// TODO optimize more cases, see translateArrayIndexIntoA
|
||||
else -> {
|
||||
expressionsAsmGen.translateExpression(index)
|
||||
out(" inx | ldy $ESTACK_LO_HEX,x")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translateExpression(expression: Expression) =
|
||||
expressionsAsmGen.translateExpression(expression)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -106,7 +106,7 @@ main {
|
||||
|
||||
check_eval_stack()
|
||||
|
||||
c64scr.print("\nyou should see no errors above.")
|
||||
c64scr.print("\nyou should see no errors printed above (only at first run).")
|
||||
}
|
||||
|
||||
sub check_eval_stack() {
|
||||
|
@ -13,7 +13,7 @@ main {
|
||||
c64.SPXY[0] = 80
|
||||
c64.SPXY[1] = 100
|
||||
|
||||
c64.SCROLX = c64.SCROLX & %11110111 ; 38 column mode
|
||||
c64.SCROLX &= %11110111 ; 38 column mode
|
||||
|
||||
c64utils.set_rasterirq(1) ; enable animation
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
%import c64graphics
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
|
@ -3,7 +3,6 @@
|
||||
%import c64flt
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
const uword width = 30
|
||||
const uword height = 20
|
||||
|
@ -1,7 +1,6 @@
|
||||
%import c64utils
|
||||
%import c64lib
|
||||
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
@ -18,7 +17,7 @@ main {
|
||||
|
||||
irq {
|
||||
|
||||
const ubyte barheight = 4
|
||||
const ubyte barheight = 4 ; should be big enough to re-trigger the Raster irq properly.
|
||||
ubyte[] colors = [6,2,4,5,15,7,1,13,3,12,8,11,9]
|
||||
ubyte color = 0
|
||||
ubyte yanim = 0
|
||||
|
@ -1,27 +1,11 @@
|
||||
%import c64lib
|
||||
%import c64utils
|
||||
%import c64flt
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
float[] floats = [1.1, 2.2]
|
||||
ubyte index=1
|
||||
|
||||
c64flt.print_f(floats[0])
|
||||
c64flt.print_f(floats[1])
|
||||
floats[0] = 9.99
|
||||
floats[index] = 8.88
|
||||
c64flt.print_f(floats[0])
|
||||
c64flt.print_f(floats[1])
|
||||
|
||||
derp("hello")
|
||||
|
||||
}
|
||||
|
||||
sub derp(uword addr) {
|
||||
A=lsb(addr)
|
||||
str foo = "foo"
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user