mirror of
https://github.com/irmen/prog8.git
synced 2024-07-05 06:29:02 +00:00
optimizer: avoid symbol name clash when inlining subroutine
This commit is contained in:
parent
07c606bfc9
commit
b4e94ae4dd
@ -54,8 +54,8 @@ fun Program.optimizeStatements(errors: IErrorReporter,
|
|||||||
return optimizationCount
|
return optimizationCount
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Program.inlineSubroutines(): Int {
|
fun Program.inlineSubroutines(options: CompilationOptions): Int {
|
||||||
val inliner = Inliner(this)
|
val inliner = Inliner(this, options)
|
||||||
inliner.visit(this)
|
inliner.visit(this)
|
||||||
return inliner.applyModifications()
|
return inliner.applyModifications()
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,9 @@ import prog8.ast.statements.*
|
|||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.ast.walk.IAstVisitor
|
import prog8.ast.walk.IAstVisitor
|
||||||
|
import prog8.code.core.CompilationOptions
|
||||||
import prog8.code.core.InternalCompilerException
|
import prog8.code.core.InternalCompilerException
|
||||||
|
import prog8.code.target.VMTarget
|
||||||
|
|
||||||
|
|
||||||
private fun isEmptyReturn(stmt: Statement): Boolean = stmt is Return && stmt.value==null
|
private fun isEmptyReturn(stmt: Statement): Boolean = stmt is Return && stmt.value==null
|
||||||
@ -16,7 +18,7 @@ private fun isEmptyReturn(stmt: Statement): Boolean = stmt is Return && stmt.va
|
|||||||
|
|
||||||
// inliner potentially enables *ONE LINED* subroutines, wihtout to be inlined.
|
// inliner potentially enables *ONE LINED* subroutines, wihtout to be inlined.
|
||||||
|
|
||||||
class Inliner(val program: Program): AstWalker() {
|
class Inliner(private val program: Program, private val options: CompilationOptions): AstWalker() {
|
||||||
|
|
||||||
class DetermineInlineSubs(val program: Program): IAstVisitor {
|
class DetermineInlineSubs(val program: Program): IAstVisitor {
|
||||||
private val modifications = mutableListOf<IAstModification>()
|
private val modifications = mutableListOf<IAstModification>()
|
||||||
@ -211,7 +213,7 @@ class Inliner(val program: Program): AstWalker() {
|
|||||||
|
|
||||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
val sub = functionCallStatement.target.targetStatement(program) as? Subroutine
|
val sub = functionCallStatement.target.targetStatement(program) as? Subroutine
|
||||||
return if(sub==null)
|
return if(sub==null || !canInline(sub, functionCallStatement))
|
||||||
noModifications
|
noModifications
|
||||||
else
|
else
|
||||||
possibleInlineFcallStmt(sub, functionCallStatement, parent)
|
possibleInlineFcallStmt(sub, functionCallStatement, parent)
|
||||||
@ -219,7 +221,7 @@ class Inliner(val program: Program): AstWalker() {
|
|||||||
|
|
||||||
override fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
override fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
||||||
val sub = functionCallExpr.target.targetStatement(program) as? Subroutine
|
val sub = functionCallExpr.target.targetStatement(program) as? Subroutine
|
||||||
if(sub!=null && sub.inline && sub.parameters.isEmpty()) {
|
if(sub!=null && sub.inline && sub.parameters.isEmpty() && canInline(sub, functionCallExpr)) {
|
||||||
require(sub.statements.size == 1 || (sub.statements.size == 2 && isEmptyReturn(sub.statements[1]))) {
|
require(sub.statements.size == 1 || (sub.statements.size == 2 && isEmptyReturn(sub.statements[1]))) {
|
||||||
"invalid inline sub at ${sub.position}"
|
"invalid inline sub at ${sub.position}"
|
||||||
}
|
}
|
||||||
@ -246,5 +248,17 @@ class Inliner(val program: Program): AstWalker() {
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun canInline(sub: Subroutine, fcall: IFunctionCall): Boolean {
|
||||||
|
if(!sub.inline)
|
||||||
|
return false
|
||||||
|
if(options.compTarget.name!=VMTarget.NAME) {
|
||||||
|
val stmt = sub.statements.single()
|
||||||
|
if (stmt is IFunctionCall) {
|
||||||
|
val existing = (fcall as Node).definingScope.lookup(stmt.target.nameInSource.take(1))
|
||||||
|
return existing !is VarDecl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
|
|||||||
val optsDone1 = program.simplifyExpressions(errors, compTarget)
|
val optsDone1 = program.simplifyExpressions(errors, compTarget)
|
||||||
val optsDone2 = program.splitBinaryExpressions(compilerOptions)
|
val optsDone2 = program.splitBinaryExpressions(compilerOptions)
|
||||||
val optsDone3 = program.optimizeStatements(errors, functions, compilerOptions)
|
val optsDone3 = program.optimizeStatements(errors, functions, compilerOptions)
|
||||||
val optsDone4 = program.inlineSubroutines()
|
val optsDone4 = program.inlineSubroutines(compilerOptions)
|
||||||
program.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away
|
program.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away
|
||||||
errors.report()
|
errors.report()
|
||||||
if (optsDone1 + optsDone2 + optsDone3 + optsDone4 == 0)
|
if (optsDone1 + optsDone2 + optsDone3 + optsDone4 == 0)
|
||||||
|
@ -257,4 +257,31 @@ mylabel:
|
|||||||
"""
|
"""
|
||||||
compileText(Cx16Target(), true, src, writeAssembly = true) shouldNotBe null
|
compileText(Cx16Target(), true, src, writeAssembly = true) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("duplicate symbols okay other block and variable") {
|
||||||
|
val src = """
|
||||||
|
main {
|
||||||
|
ubyte derp
|
||||||
|
sub start() {
|
||||||
|
derp++
|
||||||
|
foo.bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foo {
|
||||||
|
sub bar() {
|
||||||
|
derp.print()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
derp {
|
||||||
|
sub print() {
|
||||||
|
cx16.r0++
|
||||||
|
cx16.r1++
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
|
||||||
|
compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null
|
||||||
|
compileText(Cx16Target(), true, src, writeAssembly = true) shouldNotBe null
|
||||||
|
}
|
||||||
})
|
})
|
@ -1,9 +1,6 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
- check for name clash: variable vs block name
|
|
||||||
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user