some more optimizations for swap() function call asm code generation

This commit is contained in:
Irmen de Jong 2020-06-17 22:40:57 +02:00
parent cb9825484d
commit ee2ba5f398
4 changed files with 49 additions and 66 deletions

View File

@ -10,6 +10,46 @@ import prog8.ast.statements.*
internal class AstVariousTransforms(private val program: Program) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
if(functionCallStatement.target.nameInSource == listOf("swap")) {
// if x and y are both just identifiers, do not rewrite (there should be asm generation for that)
// otherwise:
// rewrite swap(x,y) as follows:
// - declare a temp variable of the same datatype
// - temp = x, x = y, y= temp
val first = functionCallStatement.args[0]
val second = functionCallStatement.args[1]
if(first !is IdentifierReference && second !is IdentifierReference) {
val dt = first.inferType(program).typeOrElse(DataType.STRUCT)
val tempname = "prog8_swaptmp_${functionCallStatement.hashCode()}"
val tempvardecl = VarDecl(VarDeclType.VAR, dt, ZeropageWish.DONTCARE, null, tempname, null, null, isArray = false, autogeneratedDontRemove = true, position = first.position)
val tempvar = IdentifierReference(listOf(tempname), first.position)
val assignTemp = Assignment(
AssignTarget(null, tempvar, null, null, first.position),
null,
first,
first.position
)
val assignFirst = Assignment(
AssignTarget.fromExpr(first),
null,
second,
first.position
)
val assignSecond = Assignment(
AssignTarget.fromExpr(second),
null,
tempvar,
first.position
)
val scope = AnonymousScope(mutableListOf(tempvardecl, assignTemp, assignFirst, assignSecond), first.position)
return listOf(IAstModification.ReplaceNode(functionCallStatement, scope, parent))
}
}
return noModifications
}
override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
if(functionCall.target.nameInSource.size==1 && functionCall.target.nameInSource[0]=="lsb") {
// lsb(...) is just an alias for type cast to ubyte, so replace with "... as ubyte"
@ -104,11 +144,11 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
// this array literal is part of an expression, turn it into an identifier reference
val litval2 = array.cast(arrayDt.typeOrElse(DataType.STRUCT))
if(litval2!=null && litval2!=array) {
val vardecl = VarDecl.createAuto(litval2)
val identifier = IdentifierReference(listOf(vardecl.name), vardecl.position)
val vardecl2 = VarDecl.createAuto(litval2)
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
return listOf(
IAstModification.ReplaceNode(array, identifier, parent),
IAstModification.InsertFirst(vardecl, array.definingScope() as Node)
IAstModification.InsertFirst(vardecl2, array.definingScope() as Node)
)
}
}

View File

@ -2,12 +2,8 @@ package prog8.compiler.target.c64.codegen
import prog8.ast.IFunctionCall
import prog8.ast.Program
import prog8.ast.base.ByteDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.Register
import prog8.ast.base.WordDatatypes
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.AssignTarget
import prog8.ast.statements.FunctionCallStatement
import prog8.compiler.AssemblyError
import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage
@ -605,48 +601,8 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
}
// TODO more optimized cases?
// if(first is ArrayIndexedExpression && second is ArrayIndexedExpression && first.identifier == second.identifier) {
// // swapping two elements of an array
// // we optimize just some simple cases here: same array, const/var/reg index.
// val arrayName = asmgen.asmIdentifierName(first.identifier)
// val dt = first.inferType(program).typeOrElse(DataType.STRUCT)
// val constIndex1 = first.arrayspec.index.constValue(program)
// val constIndex2 = second.arrayspec.index.constValue(program)
// val varIndex1 = first.arrayspec.index as? IdentifierReference
// val varIndex2 = first.arrayspec.index as? IdentifierReference
// val regIndex1 = (first.arrayspec.index as? RegisterExpr)?.register
// val regIndex2 = (first.arrayspec.index as? RegisterExpr)?.register
// when(dt) {
// DataType.UBYTE, DataType.BYTE -> {
// TODO("swap byte in array $arrayName")
// }
// DataType.UWORD, DataType.WORD -> {
// // swap word in array
// if(varIndex1!=null && varIndex2!=null){
// TODO("swap word in array $arrayName with varindexes")
// } else if(constIndex1!=null && constIndex2!=null) {
// TODO("swap word in array $arrayName with constants")
// } else if(regIndex1!=null && regIndex2!=null) {
// TODO("swap word in array $arrayName with register indexes")
// }
// }
// DataType.FLOAT -> {
// TODO("swap float in array $arrayName")
// }
// else -> throw AssemblyError("invalid array dt")
// }
// }
// suboptimal code via the evaluation stack...
asmgen.translateExpression(first)
asmgen.translateExpression(second)
// pop in reverse order
val firstTarget = AssignTarget.fromExpr(first)
val secondTarget = AssignTarget.fromExpr(second)
asmgen.assignFromEvalResult(firstTarget)
asmgen.assignFromEvalResult(secondTarget)
// other types of swap() calls should have been replaced by a different statement sequence involving a temp variable
throw AssemblyError("no asm generation for swap funccall $fcall")
}
private fun funcAbs(fcall: IFunctionCall, func: FSignature) {

View File

@ -143,18 +143,9 @@ main {
for i1 in 0 to i {
ubyte i2 = i1+1
if(rotatedz[i1] > rotatedz[i2]) {
; swap(rotatedx[i1], rotatedx[i2]) ; TODO eventually, implment the swap()
; swap(rotatedy[i1], rotatedy[i2])
; swap(rotatedz[i1], rotatedz[i2])
word tmp1 = rotatedx[i1]
rotatedx[i1] = rotatedx[i2] ; TODO fix assignment error
rotatedx[i2] = tmp1
tmp1 = rotatedy[i1]
rotatedy[i1] = rotatedy[i2]
rotatedy[i2] = tmp1
tmp1 = rotatedz[i1]
rotatedz[i1] = rotatedz[i2]
rotatedz[i2] = tmp1
swap(rotatedx[i1], rotatedx[i2])
swap(rotatedy[i1], rotatedy[i2])
swap(rotatedz[i1], rotatedz[i2])
}
}
}

View File

@ -23,10 +23,6 @@ main {
swap(uba[0], uba[1])
swap(uwa[0], uwa[1])
swap(fa[A], fa[Y])
swap(uba[A], uba[Y])
swap(uwa[A], uwa[Y])
ubyte i1
ubyte i2
swap(fa[i1], fa[i2])