temp vars are now dynamically added to AST as needed

This commit is contained in:
Irmen de Jong 2022-02-10 02:47:46 +01:00
parent 41b1c80492
commit 08bacdd090
20 changed files with 125 additions and 76 deletions

View File

@ -4,11 +4,11 @@ import prog8.ast.IStatementContainer
import prog8.ast.Node import prog8.ast.Node
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.AugmentAssignmentOperators import prog8.ast.expressions.AugmentAssignmentOperators
import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.TypecastExpression import prog8.ast.expressions.TypecastExpression
import prog8.ast.getTempVar
import prog8.ast.statements.AssignTarget import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment import prog8.ast.statements.Assignment
import prog8.ast.statements.AssignmentOrigin import prog8.ast.statements.AssignmentOrigin
@ -98,14 +98,7 @@ X = BinExpr X = LeftExpr
// we can see if we can unwrap the binary expression by working on a new temporary variable // we can see if we can unwrap the binary expression by working on a new temporary variable
// (that has the type of the expression), and then finally doing the typecast. // (that has the type of the expression), and then finally doing the typecast.
// Once it's outside the typecast, the regular splitting can commence. // Once it's outside the typecast, the regular splitting can commence.
val tempVar = when(val tempDt = origExpr.inferType(program).getOr(DataType.UNDEFINED)) { val tempVar = program.getTempVar(origExpr.inferType(program).getOr(DataType.UNDEFINED))
DataType.UBYTE -> listOf("prog8_lib", "retval_interm_ub")
DataType.BYTE -> listOf("prog8_lib", "retval_interm_b")
DataType.UWORD -> listOf("prog8_lib", "retval_interm_uw")
DataType.WORD -> listOf("prog8_lib", "retval_interm_w")
DataType.FLOAT -> listOf("floats", "tempvar_swap_float")
else -> throw FatalAstException("invalid dt $tempDt")
}
val assignTempVar = Assignment( val assignTempVar = Assignment(
AssignTarget(IdentifierReference(tempVar, typecast.position), null, null, typecast.position), AssignTarget(IdentifierReference(tempVar, typecast.position), null, null, typecast.position),
typecast.expression, AssignmentOrigin.OPTIMIZER, typecast.position typecast.expression, AssignmentOrigin.OPTIMIZER, typecast.position

View File

@ -4,7 +4,12 @@ import prog8.ast.IBuiltinFunctions
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.ast.base.FatalAstException import prog8.ast.base.FatalAstException
import prog8.ast.base.Position
import prog8.ast.base.VarDeclType
import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.InferredTypes
import prog8.ast.statements.VarDecl
import prog8.ast.statements.VarDeclOrigin
import prog8.ast.statements.ZeropageWish
import prog8.compilerinterface.CompilationOptions import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.ICompilationTarget import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter import prog8.compilerinterface.IErrorReporter
@ -69,7 +74,7 @@ fun Program.splitBinaryExpressions(options: CompilationOptions, compTarget: ICom
return opti.applyModifications() return opti.applyModifications()
} }
fun getTempVarName(dt: InferredTypes.InferredType): List<String> { fun getTempRegisterName(dt: InferredTypes.InferredType): List<String> {
return when { return when {
// TODO assume (hope) cx16.r9 isn't used for anything else during the use of this temporary variable... // TODO assume (hope) cx16.r9 isn't used for anything else during the use of this temporary variable...
dt istype DataType.UBYTE -> listOf("cx16", "r9L") dt istype DataType.UBYTE -> listOf("cx16", "r9L")

View File

@ -130,7 +130,7 @@ class StatementOptimizer(private val program: Program,
if(functionCallStatement.target.nameInSource !in listOf(listOf("pop"), listOf("popw")) && functionCallStatement.args.size==1) { if(functionCallStatement.target.nameInSource !in listOf(listOf("pop"), listOf("popw")) && functionCallStatement.args.size==1) {
val arg = functionCallStatement.args[0] val arg = functionCallStatement.args[0]
if(!arg.isSimple && arg !is TypecastExpression && arg !is IFunctionCall) { if(!arg.isSimple && arg !is TypecastExpression && arg !is IFunctionCall) {
val name = getTempVarName(arg.inferType(program)) val name = getTempRegisterName(arg.inferType(program))
val tempvar = IdentifierReference(name, functionCallStatement.position) val tempvar = IdentifierReference(name, functionCallStatement.position)
val assignTempvar = Assignment(AssignTarget(tempvar.copy(), null, null, functionCallStatement.position), arg, AssignmentOrigin.OPTIMIZER, functionCallStatement.position) val assignTempvar = Assignment(AssignTarget(tempvar.copy(), null, null, functionCallStatement.position), arg, AssignmentOrigin.OPTIMIZER, functionCallStatement.position)
return listOf( return listOf(
@ -474,14 +474,8 @@ class StatementOptimizer(private val program: Program,
val returnDt = subr.returntypes.single() val returnDt = subr.returntypes.single()
if (returnDt in IntegerDatatypes) { if (returnDt in IntegerDatatypes) {
// first assign to intermediary variable, then return that // first assign to intermediary variable, then return that
val returnVarName = "retval_interm_" + when(returnDt) { val returnVarName = program.getTempVar(returnDt)
DataType.UBYTE -> "ub" val returnValueIntermediary = IdentifierReference(returnVarName, returnStmt.position)
DataType.BYTE -> "b"
DataType.UWORD -> "uw"
DataType.WORD -> "w"
else -> "<undefined>"
}
val returnValueIntermediary = IdentifierReference(listOf("prog8_lib", returnVarName), returnStmt.position)
val tgt = AssignTarget(returnValueIntermediary, null, null, returnStmt.position) val tgt = AssignTarget(returnValueIntermediary, null, null, returnStmt.position)
val assign = Assignment(tgt, value, AssignmentOrigin.OPTIMIZER, returnStmt.position) val assign = Assignment(tgt, value, AssignmentOrigin.OPTIMIZER, returnStmt.position)
val returnReplacement = Return(returnValueIntermediary.copy(), returnStmt.position) val returnReplacement = Return(returnValueIntermediary.copy(), returnStmt.position)

View File

@ -10,8 +10,6 @@ floats {
const float PI = 3.141592653589793 const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586 const float TWOPI = 6.283185307179586
float tempvar_swap_float ; used for some swap() operations
; ---- ROM float functions ---- ; ---- ROM float functions ----

View File

@ -13,8 +13,6 @@ floats {
const float PI = 3.141592653589793 const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586 const float TWOPI = 6.283185307179586
float tempvar_swap_float ; used for some swap() operations
; ---- ROM float functions ---- ; ---- ROM float functions ----

View File

@ -6,24 +6,6 @@ prog8_lib {
%asminclude "library:prog8_lib.asm" %asminclude "library:prog8_lib.asm"
%asminclude "library:prog8_funcs.asm" %asminclude "library:prog8_funcs.asm"
; to store intermediary expression results for return values:
; NOTE: these variables can be used in the StatementReorderer and StatementOptimizer
uword @zp retval_interm_uw
word @zp retval_interm_w
ubyte @zp retval_interm_ub
byte @zp retval_interm_b
word retval_interm_w2
byte retval_interm_b2
; prog8 "hooks" to be able to access the temporary scratch variables
; YOU SHOULD NOT USE THESE IN USER CODE - THESE ARE MEANT FOR INTERNAL COMPILER USE
; NOTE: the assembly code generator will match these names and not generate
; new variables/memdefs for them, rather, they'll point to the scratch variables directly.
&ubyte P8ZP_SCRATCH_REG = $ff
&byte P8ZP_SCRATCH_B1 = $ff
&uword P8ZP_SCRATCH_W1 = $ff
&word P8ZP_SCRATCH_W2 = $ff
asmsub pattern_match(str string @AY, str pattern @R0) clobbers(Y) -> ubyte @A { asmsub pattern_match(str string @AY, str pattern @R0) clobbers(Y) -> ubyte @A {
%asm {{ %asm {{

View File

@ -345,7 +345,7 @@ private fun writeAssembly(program: Program,
// asm generation directly from the Ast // asm generation directly from the Ast
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions) compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
val variables = VariableExtractor().extractVars(program) val variables = VariableExtractor().extractVars(program)
program.processAstBeforeAsmGeneration(compilerOptions, errors) program.processAstBeforeAsmGeneration(compilerOptions, variables, errors)
errors.report() errors.report()
// println("*********** AST RIGHT BEFORE ASM GENERATION *************") // println("*********** AST RIGHT BEFORE ASM GENERATION *************")

View File

@ -13,6 +13,7 @@ import prog8.ast.walk.IAstModification
import prog8.compilerinterface.CompilationOptions import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IErrorReporter import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.IStringEncoding import prog8.compilerinterface.IStringEncoding
import prog8.compilerinterface.IVariablesAndConsts
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) { internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
@ -23,8 +24,8 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
checker.visit(this) checker.visit(this)
} }
internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, errors: IErrorReporter) { internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationOptions, variables: IVariablesAndConsts, errors: IErrorReporter) {
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors) val fixer = BeforeAsmAstChanger(this, compilerOptions, variables, errors)
fixer.visit(this) fixer.visit(this)
while(errors.noErrors() && fixer.applyModifications()>0) { while(errors.noErrors() && fixer.applyModifications()>0) {
fixer.visit(this) fixer.visit(this)

View File

@ -8,10 +8,11 @@ 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.compilerinterface.* import prog8.compilerinterface.*
import prog8.optimizer.getTempVarName import prog8.optimizer.getTempRegisterName
internal class BeforeAsmAstChanger(val program: Program, internal class BeforeAsmAstChanger(val program: Program,
private val options: CompilationOptions, private val options: CompilationOptions,
private val variables: IVariablesAndConsts,
private val errors: IErrorReporter private val errors: IErrorReporter
) : AstWalker() { ) : AstWalker() {
@ -243,7 +244,7 @@ internal class BeforeAsmAstChanger(val program: Program,
} }
if(separateLeftExpr) { if(separateLeftExpr) {
val name = getTempVarName(leftDt) val name = getTempRegisterName(leftDt)
leftOperandReplacement = IdentifierReference(name, expr.position) leftOperandReplacement = IdentifierReference(name, expr.position)
leftAssignment = Assignment( leftAssignment = Assignment(
AssignTarget(IdentifierReference(name, expr.position), null, null, expr.position), AssignTarget(IdentifierReference(name, expr.position), null, null, expr.position),
@ -252,13 +253,9 @@ internal class BeforeAsmAstChanger(val program: Program,
) )
} }
if(separateRightExpr) { if(separateRightExpr) {
val name = when { val name = program.getTempVar(rightDt.getOrElse { throw FatalAstException("invalid dt") }, true)
rightDt istype DataType.UBYTE -> listOf("prog8_lib","retval_interm_ub") val tempvardecl = program.toplevelModule.lookup(name) as VarDecl
rightDt istype DataType.UWORD -> listOf("prog8_lib","retval_interm_uw") variables.addIfUnknown(tempvardecl.definingBlock, tempvardecl)
rightDt istype DataType.BYTE -> listOf("prog8_lib","retval_interm_b2")
rightDt istype DataType.WORD -> listOf("prog8_lib","retval_interm_w2")
else -> throw AssemblyError("invalid dt")
}
rightOperandReplacement = IdentifierReference(name, expr.position) rightOperandReplacement = IdentifierReference(name, expr.position)
rightAssignment = Assignment( rightAssignment = Assignment(
AssignTarget(IdentifierReference(name, expr.position), null, null, expr.position), AssignTarget(IdentifierReference(name, expr.position), null, null, expr.position),
@ -354,7 +351,9 @@ internal class BeforeAsmAstChanger(val program: Program,
val modifications = mutableListOf<IAstModification>() val modifications = mutableListOf<IAstModification>()
val statement = expr.containingStatement val statement = expr.containingStatement
val dt = expr.indexer.indexExpr.inferType(program) val dt = expr.indexer.indexExpr.inferType(program)
val tempvar = if(dt.isBytes) listOf("prog8_lib","retval_interm_ub") else listOf("prog8_lib","retval_interm_b") val tempvar = program.getTempVar(dt.getOrElse { throw FatalAstException("invalid dt") })
val tempvardecl = program.toplevelModule.lookup(tempvar) as VarDecl
variables.addIfUnknown(tempvardecl.definingBlock, tempvardecl)
val target = AssignTarget(IdentifierReference(tempvar, expr.indexer.position), null, null, expr.indexer.position) val target = AssignTarget(IdentifierReference(tempvar, expr.indexer.position), null, null, expr.indexer.position)
val assign = Assignment(target, expr.indexer.indexExpr, AssignmentOrigin.BEFOREASMGEN, expr.indexer.position) val assign = Assignment(target, expr.indexer.indexExpr, AssignmentOrigin.BEFOREASMGEN, expr.indexer.position)
modifications.add(IAstModification.InsertBefore(statement, assign, statement.parent as IStatementContainer)) modifications.add(IAstModification.InsertBefore(statement, assign, statement.parent as IStatementContainer))

View File

@ -55,8 +55,8 @@ internal class StatementReorderer(val program: Program,
// This allows you to restart the program and have the same starting values of the variables // This allows you to restart the program and have the same starting values of the variables
// So basically consider 'ubyte xx' as a short form for 'ubyte xx; xx=0' // So basically consider 'ubyte xx' as a short form for 'ubyte xx; xx=0'
decl.value = null decl.value = null
if(decl.name.startsWith("retval_interm_") && decl.definingScope.name=="prog8_lib") { if(decl.name.startsWith("tempvar_") && decl.definingScope.name=="prog8_lib") {
// no need to zero out the special internal returnvalue intermediates. // no need to zero out the special internal temporary variables.
return noModifications return noModifications
} }
if(decl.findInitializer(program)!=null) if(decl.findInitializer(program)!=null)

View File

@ -104,18 +104,17 @@ internal class VariablesAndConsts (
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>> override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>> override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
private val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticVariable>() }.toMutableMap()
private val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
private val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
private val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticVariable>() }
private val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
private val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
init { init {
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticVariable>() }
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticVariable>() }
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
astBlockVars.forEach { (block, decls) -> astBlockVars.forEach { (block, decls) ->
val vars = bv.getValue(block) val vars = bv.getValue(block)
vars.addAll(decls.map { vars.addAll(decls.map { toStatic(it) })
IVariablesAndConsts.StaticVariable(it.datatype, it.scopedName, it.definingScope, it.value, it.arraysize?.constIndex(), it.zeropage, it.position)
})
} }
astBlockConsts.forEach { (block, decls) -> astBlockConsts.forEach { (block, decls) ->
bc.getValue(block).addAll( bc.getValue(block).addAll(
@ -146,9 +145,7 @@ internal class VariablesAndConsts (
} }
astSubroutineVars.forEach { (sub, decls) -> astSubroutineVars.forEach { (sub, decls) ->
val vars = sv.getValue(sub) val vars = sv.getValue(sub)
vars.addAll(decls.map { vars.addAll(decls.map { toStatic(it) })
IVariablesAndConsts.StaticVariable(it.datatype, it.scopedName, it.definingScope, it.value, it.arraysize?.constIndex(), it.zeropage, it.position)
})
} }
astSubroutineConsts.forEach { (sub, decls) -> astSubroutineConsts.forEach { (sub, decls) ->
sc.getValue(sub).addAll( sc.getValue(sub).addAll(
@ -179,4 +176,16 @@ internal class VariablesAndConsts (
subroutineConsts = sc subroutineConsts = sc
subroutineMemvars = smv subroutineMemvars = smv
} }
private fun toStatic(decl: VarDecl) =
IVariablesAndConsts.StaticVariable(decl.datatype, decl.scopedName, decl.definingScope, decl.value, decl.arraysize?.constIndex(), decl.zeropage, decl.position)
override fun addIfUnknown(definingBlock: Block, variable: VarDecl) {
var blockvars = bv[definingBlock]
if(blockvars==null) {
blockvars = mutableSetOf()
bv[definingBlock] = blockvars
}
blockvars.add(toStatic(variable))
}
} }

View File

@ -303,7 +303,7 @@ class TestOptimization: FunSpec({
expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, true, C64Target(), outputDir= outputDir) val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, true, C64Target(), outputDir= outputDir)
result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests()) result.program.processAstBeforeAsmGeneration(options, DummyVarsAndConsts, ErrorReporterForTests())
// assignment is now split into: // assignment is now split into:
// bb = not bb // bb = not bb
@ -357,11 +357,11 @@ class TestOptimization: FunSpec({
st.size shouldBe 8 st.size shouldBe 8
st.last() shouldBe instanceOf<Return>() st.last() shouldBe instanceOf<Return>()
var assign = st[3] as Assignment var assign = st[3] as Assignment
assign.target.identifier!!.nameInSource shouldBe listOf("prog8_lib","retval_interm_b") assign.target.identifier!!.nameInSource shouldBe listOf("prog8_lib","tempvar_b")
assign = st[4] as Assignment assign = st[4] as Assignment
assign.target.identifier!!.nameInSource shouldBe listOf("prog8_lib","retval_interm_b") assign.target.identifier!!.nameInSource shouldBe listOf("prog8_lib","tempvar_b")
assign = st[5] as Assignment assign = st[5] as Assignment
assign.target.identifier!!.nameInSource shouldBe listOf("prog8_lib","retval_interm_b") assign.target.identifier!!.nameInSource shouldBe listOf("prog8_lib","tempvar_b")
assign = st[6] as Assignment assign = st[6] as Assignment
assign.target.identifier!!.nameInSource shouldBe listOf("bb") assign.target.identifier!!.nameInSource shouldBe listOf("bb")
} }

View File

@ -76,6 +76,11 @@ class TestAsmGenSymbols: StringSpec({
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticVariable>> override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticVariable>>
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>> override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>> override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
override fun addIfUnknown(definingBlock: Block, variable: VarDecl) {
throw NotImplementedError("dummy")
}
init { init {
blockVars = mutableMapOf() blockVars = mutableMapOf()
blockVars[block] = mutableSetOf(IVariablesAndConsts.StaticVariable(varInBlock.datatype, varInBlock.scopedName, varInBlock.definingScope, varInBlock.value, varInBlock.arraysize?.constIndex(), varInBlock.zeropage, varInBlock.position)) blockVars[block] = mutableSetOf(IVariablesAndConsts.StaticVariable(varInBlock.datatype, varInBlock.scopedName, varInBlock.definingScope, varInBlock.value, varInBlock.arraysize?.constIndex(), varInBlock.zeropage, varInBlock.position))

View File

@ -6,6 +6,7 @@ import prog8.ast.base.Position
import prog8.ast.expressions.Expression import prog8.ast.expressions.Expression
import prog8.ast.expressions.InferredTypes import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.Block
import prog8.ast.statements.RegisterOrStatusflag import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
@ -76,3 +77,23 @@ internal object DummyCompilationTarget : ICompilationTarget {
throw NotImplementedError("dummy") throw NotImplementedError("dummy")
} }
} }
internal object DummyVarsAndConsts : IVariablesAndConsts {
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticVariable>>
get() = throw NotImplementedError("dummy")
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
get() = throw NotImplementedError("dummy")
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
get() = throw NotImplementedError("dummy")
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticVariable>>
get() = throw NotImplementedError("dummy")
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
get() = throw NotImplementedError("dummy")
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
get() = throw NotImplementedError("dummy")
override fun addIfUnknown(definingBlock: Block, variable: VarDecl) {
throw NotImplementedError("dummy")
}
}

View File

@ -1,5 +1,12 @@
package prog8.ast package prog8.ast
import prog8.ast.base.DataType
import prog8.ast.base.FatalAstException
import prog8.ast.base.Position
import prog8.ast.base.VarDeclType
import prog8.ast.statements.VarDecl
import prog8.ast.statements.VarDeclOrigin
import prog8.ast.statements.ZeropageWish
import kotlin.math.abs import kotlin.math.abs
fun Number.toHex(): String { fun Number.toHex(): String {
@ -29,3 +36,37 @@ fun UInt.toHex(): String {
else -> throw IllegalArgumentException("number too large for 16 bits $this") else -> throw IllegalArgumentException("number too large for 16 bits $this")
} }
} }
fun Program.getTempVar(dt: DataType, altNames: Boolean=false): List<String> {
val tmpvarName = if(altNames) {
when (dt) {
DataType.UBYTE -> listOf("prog8_lib", "tempvar_ub2")
DataType.BYTE -> listOf("prog8_lib", "tempvar_b2")
DataType.UWORD -> listOf("prog8_lib", "tempvar_uw2")
DataType.WORD -> listOf("prog8_lib", "tempvar_w2")
DataType.FLOAT -> listOf("floats", "tempvar_swap_float2")
else -> throw FatalAstException("invalid dt")
}
} else {
when (dt) {
DataType.UBYTE -> listOf("prog8_lib", "tempvar_ub")
DataType.BYTE -> listOf("prog8_lib", "tempvar_b")
DataType.UWORD -> listOf("prog8_lib", "tempvar_uw")
DataType.WORD -> listOf("prog8_lib", "tempvar_w")
DataType.FLOAT -> listOf("floats", "tempvar_swap_float")
else -> throw FatalAstException("invalid dt")
}
}
val block = this.allBlocks.first { it.name==tmpvarName[0] }
if(block.statements.filterIsInstance<VarDecl>().any { it.name == tmpvarName[1] })
return tmpvarName
// add new temp variable to the ast directly (we can do this here because we're not iterating inside those container blocks)
val decl = VarDecl(
VarDeclType.VAR, VarDeclOrigin.AUTOGENERATED, dt, ZeropageWish.DONTCARE,
null, tmpvarName[1], null, false, false, null, Position.DUMMY)
block.statements.add(decl)
decl.linkParents(block)
return tmpvarName
}

View File

@ -56,7 +56,7 @@ class Program(val name: String,
} }
val allBlocks: List<Block> val allBlocks: List<Block>
get() = modules.flatMap { it.statements.filterIsInstance<Block>() } get() = modules.flatMap { it.statements.asSequence().filterIsInstance<Block>() }
val entrypoint: Subroutine val entrypoint: Subroutine
get() { get() {

View File

@ -175,7 +175,8 @@ enum class VarDeclOrigin {
USERCODE, USERCODE,
SUBROUTINEPARAM, SUBROUTINEPARAM,
STRINGLITERAL, STRINGLITERAL,
ARRAYLITERAL ARRAYLITERAL,
AUTOGENERATED
} }

View File

@ -38,7 +38,8 @@ fun AssignTarget.isIOAddress(machine: IMachineDefinition): Boolean {
} else false } else false
} }
ident != null -> { ident != null -> {
val decl = ident.targetVarDecl(definingModule.program) ?: throw FatalAstException("invalid identifier ${ident.nameInSource}") val decl = ident.targetVarDecl(definingModule.program) ?:
throw FatalAstException("invalid identifier ${ident.nameInSource}")
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue) return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue)
machine.isIOAddress((decl.value as NumericLiteralValue).number.toUInt()) machine.isIOAddress((decl.value as NumericLiteralValue).number.toUInt())
else else

View File

@ -27,4 +27,6 @@ interface IVariablesAndConsts {
val subroutineVars: Map<Subroutine, Set<StaticVariable>> val subroutineVars: Map<Subroutine, Set<StaticVariable>>
val subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>> val subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>>
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedVariable>> val subroutineMemvars: Map<Subroutine, Set<MemoryMappedVariable>>
fun addIfUnknown(definingBlock: Block, variable: VarDecl)
} }

View File

@ -4,7 +4,6 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- (newvaralloc) UnusedCodeRemover after(decl: VarDecl): fix that vars defined in a library can also safely be removed if unused. Currently this breaks programs such as textelite (due to diskio.save().end_address ?) - (newvaralloc) UnusedCodeRemover after(decl: VarDecl): fix that vars defined in a library can also safely be removed if unused. Currently this breaks programs such as textelite (due to diskio.save().end_address ?)
- check that retval_interm_* are not in the varallocation if they're not used
- make it so that subroutine parameters as variables can again be allocated in ZP, if there's still space - make it so that subroutine parameters as variables can again be allocated in ZP, if there's still space