attempt at optimization to register parameter passing

This commit is contained in:
Irmen de Jong 2019-02-01 22:51:30 +01:00
parent f0a504baec
commit ae21e03e1d
7 changed files with 78 additions and 30 deletions

View File

@ -1647,6 +1647,40 @@ class Subroutine(override val name: String,
.filter { it is InlineAssembly }
.map { (it as InlineAssembly).assembly }
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it }
val canBeAsmSubroutine =false // TODO see below
// !isAsmSubroutine
// && ((parameters.size == 1 && parameters[0].type in setOf(DataType.BYTE, DataType.UBYTE, DataType.WORD, DataType.UWORD))
// || (parameters.size == 2 && parameters.map { it.type }.all { it == DataType.BYTE || it == DataType.UBYTE }))
fun intoAsmSubroutine(): Subroutine {
// TODO turn subroutine into asm calling convention. Requires rethinking of how parameters are handled (conflicts with local vardefs now, see AstIdentifierChecker...)
return this // TODO
// println("TO ASM $this") // TODO
// val paramregs = if (parameters.size == 1 && parameters[0].type in setOf(DataType.BYTE, DataType.UBYTE))
// listOf(RegisterOrStatusflag(RegisterOrPair.Y, null, null))
// else if (parameters.size == 1 && parameters[0].type in setOf(DataType.WORD, DataType.UWORD))
// listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, null))
// else if (parameters.size == 2 && parameters.map { it.type }.all { it == DataType.BYTE || it == DataType.UBYTE })
// listOf(RegisterOrStatusflag(RegisterOrPair.A, null, null), RegisterOrStatusflag(RegisterOrPair.Y, null, null))
// else throw FatalAstException("cannot convert subroutine to asm parameters")
//
// val asmsub=Subroutine(
// name,
// parameters,
// returntypes,
// paramregs,
// emptyList(),
// emptySet(),
// null,
// true,
// statements,
// position
// )
// asmsub.linkParents(parent)
// return asmsub
}
}

View File

@ -124,7 +124,8 @@ private class AstIdentifiersChecker(val heap: HeapValues) : IAstProcessor {
// NOTE:
// - numeric types BYTE and WORD and FLOAT are passed by value;
// - strings, arrays, matrices are passed by reference (their 16-bit address is passed as an uword parameter)
if(subroutine.asmAddress==null) {
// - do NOT do this is the statement can be transformed into an asm subroutine later!
if(subroutine.asmAddress==null && !subroutine.canBeAsmSubroutine) {
if(subroutine.asmParameterRegisters.isEmpty()) {
subroutine.parameters
.filter { it.name !in allDefinedNames }

View File

@ -165,8 +165,10 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
val argConst = arg.first.value.constValue(namespace, heap)
if(argConst!=null && argConst.type!=expectedDt) {
val convertedValue = argConst.intoDatatype(expectedDt)
if(convertedValue!=null)
if(convertedValue!=null) {
functionCall.arglist[arg.first.index] = convertedValue
optimizationsDone++
}
}
}
}

View File

@ -55,6 +55,18 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
linesToRemove.reversed().forEach{subroutine.statements.removeAt(it)}
}
if(subroutine.canBeAsmSubroutine) {
optimizationsDone++
return subroutine.intoAsmSubroutine() // TODO this doesn't work yet due to parameter vardecl issue
// TODO fix parameter passing so this also works:
// asmsub aa(byte arg @ Y) -> clobbers() -> () {
// byte local = arg ; @todo fix 'undefined symbol arg' by some sort of alias name for the parameter
// A=44
// }
}
return subroutine
}
@ -83,16 +95,6 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
return linesToRemove
}
private fun returnregisters(subroutine: Subroutine): List<RegisterOrStatusflag> {
return when {
subroutine.returntypes.isEmpty() -> listOf()
subroutine.returntypes.size==1 && subroutine.returntypes[0] in setOf(DataType.BYTE, DataType.UBYTE) -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null, null))
subroutine.returntypes.size==1 && subroutine.returntypes[0] in setOf(DataType.WORD, DataType.UWORD) -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, null))
subroutine.returntypes.size==2 && subroutine.returntypes.all { it in setOf(DataType.BYTE, DataType.UBYTE)} -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null, null), RegisterOrStatusflag(RegisterOrPair.Y, null, null))
else -> throw FatalAstException("can't convert return values to registers")
}
}
private fun isNotMemory(target: AssignTarget): Boolean {
if(target.register!=null)
return true

View File

@ -32,6 +32,8 @@ Add more compiler optimizations to the existing ones.
- can the parameter passing to subroutines be optimized to avoid copying?
- subroutines with 1 or 2 byte args (or 1 word arg) should be converted to asm calling convention with the args in A/Y register
this requires rethinking the way parameters are represented, simply injecting vardecls to
declare local variables for them is not always correct anymore
Also some library routines and code patterns could perhaps be optimized further

View File

@ -4,23 +4,31 @@
sub start() {
myblock2.foo()
myblock3.foo()
foo(1)
bar(1,2)
baz(3333)
bzaz(60000)
}
sub foo(byte arg) {
byte local = arg
A=44
}
sub bar(byte arg1, ubyte arg2) {
byte local1 = arg1
ubyte local2 = arg2
A=44
}
sub baz(word arg) {
word local=arg
A=44
}
sub bzaz(uword arg) {
uword local=arg
A=44
}
}
~ myblock2 {
sub foo() {
A=99
}
}
~ myblock3 {
sub foo() {
A=99
}
}

View File

@ -17,6 +17,5 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Python 3.7 interpreter library" level="application" />
</component>
</module>