mirror of
https://github.com/irmen/prog8.git
synced 2025-01-23 15:30:10 +00:00
fix subroutine inlining symbol scope error
This commit is contained in:
parent
ead8aa7800
commit
ddf990296b
@ -51,9 +51,9 @@ GNU GPL 3.0 (see file LICENSE), with exception for generated code:
|
||||
What does Prog8 provide?
|
||||
------------------------
|
||||
|
||||
- can produce smaller and faster running programs than equivalent C code compiled with CC65 or even LLVM-MOS
|
||||
- all advantages of a higher level language over having to write assembly code manually
|
||||
- programs run very fast because compilation to native machine code
|
||||
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
|
||||
- modularity, symbol scoping, subroutines
|
||||
- various data types other than just bytes (16-bit words, floats, strings)
|
||||
- floating point math is supported if the target system provides floating point library routines (C64 and Cx16 both do)
|
||||
|
@ -104,7 +104,7 @@ class ExpressionSimplifier(private val program: Program, private val options: Co
|
||||
val leftIDt = expr.left.inferType(program)
|
||||
val rightIDt = expr.right.inferType(program)
|
||||
if (!leftIDt.isKnown || !rightIDt.isKnown)
|
||||
throw FatalAstException("can't determine datatype of both expression operands $expr")
|
||||
return noModifications
|
||||
|
||||
// X + (-A) --> X - A
|
||||
if (expr.operator == "+" && (expr.right as? PrefixExpression)?.operator == "-") {
|
||||
|
@ -30,11 +30,11 @@ class Inliner(private val program: Program, private val options: CompilationOpti
|
||||
}
|
||||
|
||||
override fun visit(subroutine: Subroutine) {
|
||||
if(!subroutine.isAsmSubroutine && !subroutine.inline && subroutine.parameters.isEmpty()) {
|
||||
val containsSubsOrVariables = subroutine.statements.any { it is VarDecl || it is Subroutine}
|
||||
if(!containsSubsOrVariables) {
|
||||
if(subroutine.statements.size==1 || (subroutine.statements.size==2 && isEmptyReturn(subroutine.statements[1]))) {
|
||||
if(subroutine !== program.entrypoint) {
|
||||
if (!subroutine.isAsmSubroutine && !subroutine.inline && subroutine.parameters.isEmpty()) {
|
||||
val containsSubsOrVariables = subroutine.statements.any { it is VarDecl || it is Subroutine }
|
||||
if (!containsSubsOrVariables) {
|
||||
if (subroutine.statements.size == 1 || (subroutine.statements.size == 2 && isEmptyReturn(subroutine.statements[1]))) {
|
||||
if (subroutine !== program.entrypoint) {
|
||||
// subroutine is possible candidate to be inlined
|
||||
subroutine.inline =
|
||||
when (val stmt = subroutine.statements[0]) {
|
||||
@ -87,9 +87,9 @@ class Inliner(private val program: Program, private val options: CompilationOpti
|
||||
} else
|
||||
false
|
||||
targetInline || valueInline
|
||||
} else if(stmt.target.identifier!=null && stmt.isAugmentable) {
|
||||
} else if (stmt.target.identifier != null && stmt.isAugmentable) {
|
||||
val binExpr = stmt.value as BinaryExpression
|
||||
if(binExpr.operator in "+-" && binExpr.right.constValue(program)?.number==1.0) {
|
||||
if (binExpr.operator in "+-" && binExpr.right.constValue(program)?.number == 1.0) {
|
||||
makeFullyScoped(stmt.target.identifier!!)
|
||||
makeFullyScoped(binExpr.left as IdentifierReference)
|
||||
true
|
||||
@ -121,8 +121,8 @@ class Inliner(private val program: Program, private val options: CompilationOpti
|
||||
}
|
||||
}
|
||||
|
||||
if(subroutine.inline && subroutine.statements.size>1) {
|
||||
require(subroutine.statements.size==2 && isEmptyReturn(subroutine.statements[1]))
|
||||
if (subroutine.inline && subroutine.statements.size > 1) {
|
||||
require(subroutine.statements.size == 2 && isEmptyReturn(subroutine.statements[1]))
|
||||
subroutine.statements.removeLast() // get rid of the Return, to be able to inline the (single) statement preceding it.
|
||||
}
|
||||
}
|
||||
@ -147,6 +147,7 @@ class Inliner(private val program: Program, private val options: CompilationOpti
|
||||
}
|
||||
|
||||
private fun makeFullyScoped(call: FunctionCallStatement) {
|
||||
makeFullyScoped(call.target)
|
||||
call.target.targetSubroutine(program)?.let { sub ->
|
||||
val scopedName = IdentifierReference(sub.scopedName, call.target.position)
|
||||
val scopedArgs = makeScopedArgs(call.args)
|
||||
@ -169,6 +170,7 @@ class Inliner(private val program: Program, private val options: CompilationOpti
|
||||
}
|
||||
|
||||
private fun makeFullyScoped(call: FunctionCallExpression) {
|
||||
makeFullyScoped(call.target)
|
||||
call.target.targetSubroutine(program)?.let { sub ->
|
||||
val scopedName = IdentifierReference(sub.scopedName, call.target.position)
|
||||
val scopedArgs = makeScopedArgs(call.args)
|
||||
|
@ -1060,23 +1060,25 @@ main {
|
||||
compileText(C64Target(), true, src, writeAssembly = true) shouldNotBe null
|
||||
}
|
||||
|
||||
xtest("optimizing inlined functions must reference proper scopes") {
|
||||
test("optimizing inlined functions must reference proper scopes") {
|
||||
val src="""
|
||||
main {
|
||||
sub start() {
|
||||
other.sub1()
|
||||
void other.sub1()
|
||||
cx16.r0L = other.sub1()+other.sub1()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
other {
|
||||
sub sub2() {
|
||||
sub sub2() -> ubyte{
|
||||
cx16.r0++
|
||||
cx16.r1++
|
||||
return cx16.r0L
|
||||
}
|
||||
|
||||
sub sub1() {
|
||||
sub2()
|
||||
sub sub1() -> ubyte {
|
||||
return sub2()
|
||||
}
|
||||
}"""
|
||||
|
||||
|
@ -70,9 +70,9 @@ Features
|
||||
--------
|
||||
|
||||
- it is a cross-compiler running on modern machines (Linux, MacOS, Windows, ...)
|
||||
- can produce smaller and faster running programs than equivalent C code compiled with CC65 or even LLVM-MOS
|
||||
- the compiled programs run very fast, because compilation to highly efficient native machine code.
|
||||
- Provides a convenient and fast edit/compile/run cycle by being able to directly launch
|
||||
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
|
||||
- provides a convenient and fast edit/compile/run cycle by being able to directly launch
|
||||
the compiled program in an emulator and provide debugging information to this emulator.
|
||||
- the language looks like a mix of Python and C so should be quite easy to learn
|
||||
- Modular programming, scoping via modules, code blocks, and subroutines. No need for forward declarations.
|
||||
|
@ -1,11 +1,9 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
optimizer bug, see "optimizing inlined functions must reference proper scopes" unittest (skipped for now)
|
||||
causes compiler error for virtual: just calling txt.cls() gives compile error undefined symbol clear_screen
|
||||
|
||||
https://github.com/irmen/prog8/issues/136 (string.find register order issue)
|
||||
|
||||
other issues on github.
|
||||
|
||||
optimize signed byte/word division by powers of 2 (and shift right?), it's now using divmod routine. (also % ?)
|
||||
see inplacemodificationByteVariableWithLiteralval() and inplacemodificationSomeWordWithLiteralval()
|
||||
|
Loading…
x
Reference in New Issue
Block a user