mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
temp vars are now dynamically added to AST as needed
This commit is contained in:
parent
41b1c80492
commit
08bacdd090
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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 ----
|
||||||
|
|
||||||
|
@ -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 ----
|
||||||
|
|
||||||
|
@ -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 {{
|
||||||
|
@ -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 *************")
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -175,7 +175,8 @@ enum class VarDeclOrigin {
|
|||||||
USERCODE,
|
USERCODE,
|
||||||
SUBROUTINEPARAM,
|
SUBROUTINEPARAM,
|
||||||
STRINGLITERAL,
|
STRINGLITERAL,
|
||||||
ARRAYLITERAL
|
ARRAYLITERAL,
|
||||||
|
AUTOGENERATED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user