a few more inlinings of trivial return values

This commit is contained in:
Irmen de Jong 2021-10-09 01:36:13 +02:00
parent 07132a2c42
commit e8f308f654
3 changed files with 115 additions and 22 deletions

View File

@ -39,6 +39,41 @@ internal class StatementOptimizer(private val program: Program,
return noModifications return noModifications
} }
override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
// if the first instruction in the called subroutine is a return statement with a simple value,
// remove the jump altogeter and inline the returnvalue directly.
val subroutine = functionCall.target.targetSubroutine(program)
if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is Return && first.value?.isSimple==true) {
val orig = first.value!!
val copy = when(orig) {
is AddressOf -> {
val scoped = scopePrefix(orig.identifier, subroutine)
AddressOf(scoped, orig.position)
}
is DirectMemoryRead -> {
when(val expr = orig.addressExpression) {
is NumericLiteralValue -> DirectMemoryRead(expr.copy(), orig.position)
else -> return noModifications
}
}
is IdentifierReference -> scopePrefix(orig, subroutine)
is NumericLiteralValue -> orig.copy()
is StringLiteralValue -> orig.copy()
else -> return noModifications
}
return listOf(IAstModification.ReplaceNode(functionCall, copy, parent))
}
}
return noModifications
}
private fun scopePrefix(variable: IdentifierReference, subroutine: Subroutine): IdentifierReference {
val scoped = subroutine.makeScopedName(variable.nameInSource.last())
return IdentifierReference(scoped.split('.'), variable.position)
}
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> { override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
if(functionCallStatement.target.nameInSource.size==1 && functionCallStatement.target.nameInSource[0] in functions.names) { if(functionCallStatement.target.nameInSource.size==1 && functionCallStatement.target.nameInSource[0] in functions.names) {
val functionName = functionCallStatement.target.nameInSource[0] val functionName = functionCallStatement.target.nameInSource[0]
@ -101,19 +136,19 @@ internal class StatementOptimizer(private val program: Program,
return noModifications return noModifications
} }
override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> { // override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
// if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value // // if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value
val subroutine = functionCall.target.targetSubroutine(program) // val subroutine = functionCall.target.targetSubroutine(program)
if(subroutine!=null) { // if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull() // val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is Return && first.value!=null) { // if(first is Return && first.value!=null) {
val constval = first.value?.constValue(program) // val constval = first.value?.constValue(program)
if(constval!=null) // if(constval!=null)
return listOf(IAstModification.ReplaceNode(functionCall, constval, parent)) // return listOf(IAstModification.ReplaceNode(functionCall, constval, parent))
} // }
} // }
return noModifications // return noModifications
} // }
override fun after(ifStatement: IfStatement, parent: Node): Iterable<IAstModification> { override fun after(ifStatement: IfStatement, parent: Node): Iterable<IAstModification> {
// remove empty if statements // remove empty if statements

View File

@ -348,7 +348,7 @@ class DirectMemoryRead(var addressExpression: Expression, override val position:
this.addressExpression.linkParents(this) this.addressExpression.linkParents(this)
} }
override val isSimple = true override val isSimple = addressExpression is NumericLiteralValue || addressExpression is IdentifierReference
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is Expression && node===addressExpression) require(replacement is Expression && node===addressExpression)
@ -366,8 +366,6 @@ class DirectMemoryRead(var addressExpression: Expression, override val position:
override fun toString(): String { override fun toString(): String {
return "DirectMemoryRead($addressExpression)" return "DirectMemoryRead($addressExpression)"
} }
fun copy() = DirectMemoryRead(addressExpression, position)
} }
class NumericLiteralValue(val type: DataType, // only numerical types allowed class NumericLiteralValue(val type: DataType, // only numerical types allowed
@ -376,6 +374,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
override lateinit var parent: Node override lateinit var parent: Node
override val isSimple = true override val isSimple = true
fun copy() = NumericLiteralValue(type, number, position)
companion object { companion object {
fun fromBoolean(bool: Boolean, position: Position) = fun fromBoolean(bool: Boolean, position: Position) =
@ -509,6 +508,7 @@ class StringLiteralValue(val value: String,
} }
override val isSimple = true override val isSimple = true
fun copy() = StringLiteralValue(value, altEncoding, position)
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
throw FatalAstException("can't replace here") throw FatalAstException("can't replace here")

View File

@ -1,12 +1,70 @@
%import palette %import textio
%import test_stack %zeropage dontuse
%zeropage basicsafe
main { main {
sub start() { sub start() {
; TODO inline a subroutine that only contains a direct call to another subroutine uword v
palette.set_all_black() v = test.get_value1()
palette.set_all_white() txt.print_uw(v)
txt.nl()
v = test.get_value2()
txt.print_uw(v)
txt.nl()
v = test.get_value3()
txt.print_uw(v)
txt.nl()
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
v = test.get_value4()
txt.print_uw(v)
txt.nl()
v = test.get_value5()
txt.print_uw(v)
txt.nl()
v = test.get_value6()
txt.print_uw(v)
txt.nl()
}
}
test {
uword[] arr = [1111,2222,3333]
uword value = 9999
sub get_value1() -> uword {
return &value
}
sub get_value2() -> uword {
return arr[2]
}
sub get_value3() -> ubyte {
return @($c000)
}
sub get_value4() -> uword {
return value
}
sub get_value5() -> uword {
return $c000
}
sub get_value6() -> uword {
return "string"
} }
} }