mirror of
https://github.com/irmen/prog8.git
synced 2024-10-19 07:23:56 +00:00
added some more asm code optimizations by splitting certain assignments
This commit is contained in:
parent
e947067dcf
commit
acc942f690
@ -16,6 +16,7 @@ import kotlin.math.abs
|
|||||||
|
|
||||||
|
|
||||||
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
|
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
|
||||||
|
val comparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
||||||
|
|
||||||
|
|
||||||
sealed class Expression: Node {
|
sealed class Expression: Node {
|
||||||
|
@ -61,6 +61,18 @@ interface IAstModification {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InsertBefore(val before: Statement, val stmt: Statement, val parent: Node) : IAstModification {
|
||||||
|
override fun perform() {
|
||||||
|
if(parent is INameScope) {
|
||||||
|
val idx = parent.statements.indexOfFirst { it===before }
|
||||||
|
parent.statements.add(idx, stmt)
|
||||||
|
stmt.linkParents(parent)
|
||||||
|
} else {
|
||||||
|
throw FatalAstException("parent of an insert modification is not an INameScope")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ReplaceNode(val node: Node, val replacement: Node, val parent: Node) : IAstModification {
|
class ReplaceNode(val node: Node, val replacement: Node, val parent: Node) : IAstModification {
|
||||||
override fun perform() {
|
override fun perform() {
|
||||||
parent.replaceChildNode(node, replacement)
|
parent.replaceChildNode(node, replacement)
|
||||||
|
@ -21,6 +21,25 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||||
|
// Try to replace A = B <operator> Something by A= B, A = A <operator> Something
|
||||||
|
// this triggers the more efficent augmented assignment code generation more often.
|
||||||
|
if(!assignment.isAugmentable
|
||||||
|
&& assignment.target.identifier != null
|
||||||
|
&& assignment.target.isNotMemory(program.namespace)) {
|
||||||
|
val binExpr = assignment.value as? BinaryExpression
|
||||||
|
if(binExpr!=null && binExpr.operator !in comparisonOperators) {
|
||||||
|
if(binExpr.left !is BinaryExpression) {
|
||||||
|
val assignLeft = Assignment(assignment.target, binExpr.left, assignment.position)
|
||||||
|
return listOf(
|
||||||
|
IAstModification.InsertBefore(assignment, assignLeft, parent),
|
||||||
|
IAstModification.ReplaceNode(binExpr.left, assignment.target.toExpression(), binExpr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
||||||
val decls = scope.statements.filterIsInstance<VarDecl>()
|
val decls = scope.statements.filterIsInstance<VarDecl>()
|
||||||
val sub = scope.definingSubroutine()
|
val sub = scope.definingSubroutine()
|
||||||
|
@ -193,7 +193,7 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
|
|||||||
programAst.processAstBeforeAsmGeneration(errors)
|
programAst.processAstBeforeAsmGeneration(errors)
|
||||||
errors.handle()
|
errors.handle()
|
||||||
|
|
||||||
printAst(programAst)
|
// printAst(programAst)
|
||||||
|
|
||||||
val assembly = CompilationTarget.asmGenerator(
|
val assembly = CompilationTarget.asmGenerator(
|
||||||
programAst,
|
programAst,
|
||||||
|
@ -188,13 +188,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
// TODO more specialized code for types such as memory read etc.
|
// TODO more specialized code for types such as memory read etc.
|
||||||
value is TypecastExpression -> {
|
value is TypecastExpression -> {
|
||||||
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
|
if (tryRemoveRedundantCast(value, target, operator, origAssign)) return
|
||||||
inplaceModification_byte_value_to_memory(name, operator, value, origAssign)
|
inplaceModification_byte_value_to_memory(name, operator, value)
|
||||||
}
|
}
|
||||||
else -> inplaceModification_byte_value_to_memory(name, operator, value, origAssign)
|
else -> inplaceModification_byte_value_to_memory(name, operator, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
println("warning: slow stack evaluation used (1): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO
|
println("warning: slow stack evaluation used (1): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO optimize...
|
||||||
asmgen.translateExpression(memory.addressExpression)
|
asmgen.translateExpression(memory.addressExpression)
|
||||||
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta ${C64Zeropage.SCRATCH_B1}")
|
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta ${C64Zeropage.SCRATCH_B1}")
|
||||||
// the original memory byte's value is now in the scratch B1 location.
|
// the original memory byte's value is now in the scratch B1 location.
|
||||||
@ -245,8 +245,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
stx ${C64Zeropage.SCRATCH_REG_X}
|
stx ${C64Zeropage.SCRATCH_REG_X}
|
||||||
lda #<$name
|
lda #<$name
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr c64flt.CONUPK
|
jsr c64flt.FADD
|
||||||
jsr c64flt.FADDT
|
|
||||||
ldx #<$name
|
ldx #<$name
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr c64flt.MOVMF
|
jsr c64flt.MOVMF
|
||||||
@ -259,8 +258,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
stx ${C64Zeropage.SCRATCH_REG_X}
|
stx ${C64Zeropage.SCRATCH_REG_X}
|
||||||
lda #<$name
|
lda #<$name
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr c64flt.CONUPK
|
jsr c64flt.FSUB
|
||||||
jsr c64flt.FSUBT
|
|
||||||
ldx #<$name
|
ldx #<$name
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr c64flt.MOVMF
|
jsr c64flt.MOVMF
|
||||||
@ -284,9 +282,33 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
|
|
||||||
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference) {
|
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference) {
|
||||||
val valueDt = ident.targetVarDecl(program.namespace)!!.datatype
|
val valueDt = ident.targetVarDecl(program.namespace)!!.datatype
|
||||||
// TODO check valueDt
|
if(valueDt != DataType.FLOAT)
|
||||||
|
throw AssemblyError("float variable expected")
|
||||||
|
|
||||||
val otherName = asmgen.asmIdentifierName(ident)
|
val otherName = asmgen.asmIdentifierName(ident)
|
||||||
TODO("Not yet implemented $name $operator= $otherName")
|
when (operator) {
|
||||||
|
"**" -> TODO("pow")
|
||||||
|
"+" -> TODO("+")
|
||||||
|
"-" -> TODO("-")
|
||||||
|
"*" -> {
|
||||||
|
asmgen.out("""
|
||||||
|
stx ${C64Zeropage.SCRATCH_REG_X}
|
||||||
|
lda #<$name
|
||||||
|
ldy #>$name
|
||||||
|
jsr c64flt.MOVFM
|
||||||
|
lda #<$otherName
|
||||||
|
ldy #>$otherName
|
||||||
|
jsr c64flt.FMULT
|
||||||
|
ldx #<$name
|
||||||
|
ldy #>$name
|
||||||
|
jsr c64flt.MOVMF
|
||||||
|
ldx ${C64Zeropage.SCRATCH_REG_X}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
"/" -> TODO("div")
|
||||||
|
"%" -> TODO("float remainder???")
|
||||||
|
else -> throw AssemblyError("invalid operator for in-place float modification $operator")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) {
|
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) {
|
||||||
@ -303,8 +325,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
jsr c64flt.MOVFM
|
jsr c64flt.MOVFM
|
||||||
lda #<$constValueName
|
lda #<$constValueName
|
||||||
ldy #>$constValueName
|
ldy #>$constValueName
|
||||||
jsr c64flt.CONUPK
|
jsr c64flt.FADD
|
||||||
jsr c64flt.FADDT
|
|
||||||
ldx #<$name
|
ldx #<$name
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr c64flt.MOVMF
|
jsr c64flt.MOVMF
|
||||||
@ -321,32 +342,29 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
jsr c64flt.MOVFM
|
jsr c64flt.MOVFM
|
||||||
lda #<$name
|
lda #<$name
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr c64flt.CONUPK
|
jsr c64flt.FSUB
|
||||||
jsr c64flt.FSUBT
|
|
||||||
ldx #<$name
|
ldx #<$name
|
||||||
ldy #>$name
|
ldy #>$name
|
||||||
jsr c64flt.MOVMF
|
jsr c64flt.MOVMF
|
||||||
ldx ${C64Zeropage.SCRATCH_REG_X}
|
ldx ${C64Zeropage.SCRATCH_REG_X}
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
"*" -> TODO("mul")
|
||||||
"/" -> {
|
"/" -> {
|
||||||
if (value == 0.0)
|
if (value == 0.0)
|
||||||
throw AssemblyError("division by zero")
|
throw AssemblyError("division by zero")
|
||||||
TODO("div")
|
TODO("div")
|
||||||
// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
|
||||||
}
|
}
|
||||||
"%" -> {
|
"%" -> {
|
||||||
|
if (value == 0.0)
|
||||||
|
throw AssemblyError("division by zero")
|
||||||
TODO("float remainder???")
|
TODO("float remainder???")
|
||||||
// if(types==DataType.BYTE)
|
|
||||||
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
|
||||||
// asmgen.out(" jsr prog8_lib.remainder_ub")
|
|
||||||
}
|
}
|
||||||
else -> throw AssemblyError("invalid operator for in-place float modification $operator")
|
else -> throw AssemblyError("invalid operator for in-place float modification $operator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inplaceModification_byte_value_to_memory(pointername: String, operator: String, value: Expression, origAssign: Assignment) {
|
private fun inplaceModification_byte_value_to_memory(pointername: String, operator: String, value: Expression) {
|
||||||
println("warning: slow stack evaluation used (3): @($pointername) $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
println("warning: slow stack evaluation used (3): @($pointername) $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
||||||
asmgen.translateExpression(value)
|
asmgen.translateExpression(value)
|
||||||
fun loadByteFromPointerIntoA() {
|
fun loadByteFromPointerIntoA() {
|
||||||
@ -463,8 +481,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
asmgen.out(" sec | sbc #$value | sta (${C64Zeropage.SCRATCH_W1}),y")
|
asmgen.out(" sec | sbc #$value | sta (${C64Zeropage.SCRATCH_W1}),y")
|
||||||
}
|
}
|
||||||
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
"*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||||
"/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
"/" -> {
|
||||||
|
if(value==0)
|
||||||
|
throw AssemblyError("division by zero")
|
||||||
|
TODO("div")
|
||||||
|
// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||||
|
}
|
||||||
"%" -> {
|
"%" -> {
|
||||||
|
if(value==0)
|
||||||
|
throw AssemblyError("division by zero")
|
||||||
TODO("byte remainder")
|
TODO("byte remainder")
|
||||||
// if(types==DataType.BYTE)
|
// if(types==DataType.BYTE)
|
||||||
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||||
@ -567,8 +592,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
lda math.multiply_words.result+1
|
lda math.multiply_words.result+1
|
||||||
sta $name+1""")
|
sta $name+1""")
|
||||||
}
|
}
|
||||||
"/" -> TODO("word $name /= $value")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
"/" -> {
|
||||||
|
if(value==0)
|
||||||
|
throw AssemblyError("division by zero")
|
||||||
|
TODO("word $name /= $value")
|
||||||
|
// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||||
|
}
|
||||||
"%" -> {
|
"%" -> {
|
||||||
|
if(value==0)
|
||||||
|
throw AssemblyError("division by zero")
|
||||||
TODO("word remainder $value")
|
TODO("word remainder $value")
|
||||||
// if(types==DataType.BYTE)
|
// if(types==DataType.BYTE)
|
||||||
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||||
@ -903,6 +935,24 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
"&" -> asmgen.out(" lda $name | and $otherName | sta $name")
|
"&" -> asmgen.out(" lda $name | and $otherName | sta $name")
|
||||||
"^" -> asmgen.out(" lda $name | xor $otherName | sta $name")
|
"^" -> asmgen.out(" lda $name | xor $otherName | sta $name")
|
||||||
"|" -> asmgen.out(" lda $name | ora $otherName | sta $name")
|
"|" -> asmgen.out(" lda $name | ora $otherName | sta $name")
|
||||||
|
"and" -> asmgen.out("""
|
||||||
|
lda $name
|
||||||
|
and $otherName
|
||||||
|
beq +
|
||||||
|
lda #1
|
||||||
|
+ sta $name""")
|
||||||
|
"or" -> asmgen.out("""
|
||||||
|
lda $name
|
||||||
|
ora $otherName
|
||||||
|
beq +
|
||||||
|
lda #1
|
||||||
|
+ sta $name""")
|
||||||
|
"xor" -> asmgen.out("""
|
||||||
|
lda $name
|
||||||
|
eor $otherName
|
||||||
|
beq +
|
||||||
|
lda #1
|
||||||
|
+ sta $name""")
|
||||||
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
else -> throw AssemblyError("invalid operator for in-place modification $operator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -932,10 +982,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"%" -> {
|
"%" -> {
|
||||||
TODO("$dt remainder")
|
if(dt==DataType.BYTE)
|
||||||
// if(types==DataType.BYTE)
|
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
||||||
// throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
|
asmgen.out("""
|
||||||
// asmgen.out(" jsr prog8_lib.remainder_ub")
|
lda $name
|
||||||
|
ldy #$value
|
||||||
|
jsr math.divmod_ub
|
||||||
|
sta $name""")
|
||||||
}
|
}
|
||||||
"<<" -> {
|
"<<" -> {
|
||||||
repeat(value) { asmgen.out(" asl $name") }
|
repeat(value) { asmgen.out(" asl $name") }
|
||||||
|
Loading…
Reference in New Issue
Block a user