printing 2-letter strings is now only optimized into direct CHROUT if it's a const string literal

This commit is contained in:
Irmen de Jong 2021-05-16 15:00:40 +02:00
parent 68d7b4649e
commit ca61248861
6 changed files with 25 additions and 17 deletions

View File

@ -48,6 +48,7 @@ internal class StatementOptimizer(private val program: Program,
} }
// printing a literal string of just 2 or 1 characters is replaced by directly outputting those characters // printing a literal string of just 2 or 1 characters is replaced by directly outputting those characters
// only do this optimization if the arg is a known-constant string literal instead of a user defined variable.
if(functionCallStatement.target.nameInSource==listOf("txt", "print")) { if(functionCallStatement.target.nameInSource==listOf("txt", "print")) {
val arg = functionCallStatement.args.single() val arg = functionCallStatement.args.single()
val stringVar: IdentifierReference? = if(arg is AddressOf) { val stringVar: IdentifierReference? = if(arg is AddressOf) {
@ -55,10 +56,7 @@ internal class StatementOptimizer(private val program: Program,
} else { } else {
arg as? IdentifierReference arg as? IdentifierReference
} }
if(stringVar!=null) { if(stringVar!=null && stringVar.wasStringLiteral(program)) {
// TODO: only do this optimization if the arg is a known-constant string literal instead of a user defined variable. We can't see the difference here yet.
val string = stringVar.targetVarDecl(program)?.value as? StringLiteralValue val string = stringVar.targetVarDecl(program)?.value as? StringLiteralValue
if(string!=null) { if(string!=null) {
val pos = functionCallStatement.position val pos = functionCallStatement.position

View File

@ -1,9 +1,6 @@
package prog8.optimizer package prog8.optimizer
import prog8.ast.INameScope import prog8.ast.*
import prog8.ast.Module
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.VarDeclType import prog8.ast.base.VarDeclType
import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.FunctionCall import prog8.ast.expressions.FunctionCall
@ -65,7 +62,7 @@ internal class UnusedCodeRemover(private val program: Program,
override fun after(block: Block, parent: Node): Iterable<IAstModification> { override fun after(block: Block, parent: Node): Iterable<IAstModification> {
if("force_output" !in block.options()) { if("force_output" !in block.options()) {
if (block.containsNoCodeNorVars()) { if (block.containsNoCodeNorVars()) {
if(block.name != program.internedStringsModuleName) if(block.name != internedStringsModuleName)
errors.warn("removing unused block '${block.name}'", block.position) errors.warn("removing unused block '${block.name}'", block.position)
return listOf(IAstModification.Remove(block, parent as INameScope)) return listOf(IAstModification.Remove(block, parent as INameScope))
} }

View File

@ -8,6 +8,8 @@ import prog8.ast.walk.IAstVisitor
import java.nio.file.Path import java.nio.file.Path
import kotlin.math.abs import kotlin.math.abs
const val internedStringsModuleName = "prog8_interned_strings"
interface IStringEncoding { interface IStringEncoding {
fun encodeString(str: String, altEncoding: Boolean): List<Short> fun encodeString(str: String, altEncoding: Boolean): List<Short>
fun decodeString(bytes: List<Short>, altEncoding: Boolean): String fun decodeString(bytes: List<Short>, altEncoding: Boolean): String
@ -257,7 +259,6 @@ class Program(val name: String,
var actualLoadAddress: Int = 0 var actualLoadAddress: Int = 0
private val internedStringsUnique = mutableMapOf<Pair<String, Boolean>, List<String>>() private val internedStringsUnique = mutableMapOf<Pair<String, Boolean>, List<String>>()
val internedStringsModuleName = "prog8_interned_strings"
init { init {
// insert a container module for all interned strings later // insert a container module for all interned strings later

View File

@ -788,6 +788,15 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
else -> InferredTypes.InferredType.unknown() else -> InferredTypes.InferredType.unknown()
} }
} }
fun wasStringLiteral(program: Program): Boolean {
val decl = targetVarDecl(program)
if(decl == null || !decl.autogeneratedDontRemove)
return false
val scope=decl.definingModule()
return scope.name==internedStringsModuleName
}
} }
class FunctionCall(override var target: IdentifierReference, class FunctionCall(override var target: IdentifierReference,

View File

@ -4,8 +4,9 @@ TODO
- possible idea: option to mark vardecls 'shared' to indicate they should not be optimized away because they're shared with assembly code? - possible idea: option to mark vardecls 'shared' to indicate they should not be optimized away because they're shared with assembly code?
However: who even needs variables declared in prog8 code that are only used by assembly??? However: who even needs variables declared in prog8 code that are only used by assembly???
- github issue about strings and their immutability: - github issue about strings and their immutability:
StatementOptimizer line 60: only optimize when it's a known constant literal Can we make deduplication the default again? (only string literals are considered...) remove cli option for it again?
IMPROVE DOCUMENTATION ABOUT STRINGS AND DEDUP and (NON)IMMUTABILITY. IMPROVE DOCUMENTATION ABOUT STRINGS AND DEDUP and (NON)IMMUTABILITY.
- test all examples (including imgviewer, assembler and petaxian) before release of the new version - test all examples (including imgviewer, assembler and petaxian) before release of the new version

View File

@ -1,24 +1,26 @@
%import textio ; txt.* %import textio ; txt.*
%zeropage basicsafe %zeropage basicsafe
main { main {
sub start() { sub start() {
str string1 = "stringvalue" str string1 = "stringvalue\n"
str string2 = "stringvalue" str string2 = "stringvalue\n"
str string3 = "stringvalue" str string3 = "stringvalue\n"
str string4 = "a"
str string5 = "bb"
txt.print("a") txt.print("a")
txt.print("a") txt.print("a")
txt.print(string4)
txt.print("bb") txt.print("bb")
txt.print("bb") txt.print("bb")
txt.print(string5)
txt.print("\n") txt.print("\n")
txt.print("\n\n") txt.print("\n\n")
txt.print(string1) txt.print(string1)
txt.nl()
txt.print(string2) txt.print(string2)
txt.nl()
txt.print(string3) txt.print(string3)
txt.nl()
txt.print("hello\n") txt.print("hello\n")
txt.print("hello\n") txt.print("hello\n")
txt.print("hello\n") txt.print("hello\n")