some naming changes and cleanups

This commit is contained in:
Irmen de Jong 2022-02-06 22:56:17 +01:00
parent 10de7dc1f9
commit 101fb0b8aa
20 changed files with 140 additions and 143 deletions

View File

@ -23,8 +23,9 @@ const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2" const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
class AsmGen6502(internal val program: Program, class AsmGen(internal val program: Program,
internal val errors: IErrorReporter, internal val errors: IErrorReporter,
internal val variables: IVariablesAndConsts,
internal val options: CompilationOptions): IAssemblyGenerator { internal val options: CompilationOptions): IAssemblyGenerator {
// for expressions and augmented assignments: // for expressions and augmented assignments:
@ -54,6 +55,8 @@ class AsmGen6502(internal val program: Program,
println("Generating assembly code... ") println("Generating assembly code... ")
// TODO variables.dump(program.memsizer)
val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value } val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value }
require(allInitializers.all { it.origin==AssignmentOrigin.VARINIT }) {"all block-level assignments must be a variable initializer"} require(allInitializers.all { it.origin==AssignmentOrigin.VARINIT }) {"all block-level assignments must be a variable initializer"}
@ -285,7 +288,7 @@ class AsmGen6502(internal val program: Program,
// first translate regular statements, and then put the subroutines at the end. // first translate regular statements, and then put the subroutines at the end.
val (subroutine, stmts) = statements.partition { it is Subroutine } val (subroutine, stmts) = statements.partition { it is Subroutine }
stmts.forEach { translate(it) } stmts.forEach { translate(it) }
subroutine.forEach { translateSubroutine(it as Subroutine) } subroutine.forEach { translate(it) }
if(!options.dontReinitGlobals) { if(!options.dontReinitGlobals) {
// generate subroutine to initialize block-level (global) variables // generate subroutine to initialize block-level (global) variables

View File

@ -17,7 +17,7 @@ import prog8.compilerinterface.CpuType
import prog8.compilerinterface.FSignature import prog8.compilerinterface.FSignature
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen6502, private val assignAsmGen: AssignmentAsmGen) { internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) {
internal fun translateFunctioncallExpression(fcall: FunctionCallExpression, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?) { internal fun translateFunctioncallExpression(fcall: FunctionCallExpression, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister) translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister)

View File

@ -11,7 +11,7 @@ import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.CpuType import prog8.compilerinterface.CpuType
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
internal class ExpressionsAsmGen(private val program: Program, private val asmgen: AsmGen6502, private val functioncallAsmGen: FunctionCallAsmGen) { internal class ExpressionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val functioncallAsmGen: FunctionCallAsmGen) {
@Deprecated("avoid calling this as it generates slow evalstack based code") @Deprecated("avoid calling this as it generates slow evalstack based code")
internal fun translateExpression(expression:Expression) { internal fun translateExpression(expression:Expression) {

View File

@ -12,7 +12,7 @@ import prog8.ast.toHex
import prog8.compilerinterface.AssemblyError import prog8.compilerinterface.AssemblyError
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen6502) { internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translate(stmt: ForLoop) { internal fun translate(stmt: ForLoop) {
val iterableDt = stmt.iterable.inferType(program) val iterableDt = stmt.iterable.inferType(program)

View File

@ -17,7 +17,7 @@ import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.CpuType import prog8.compilerinterface.CpuType
internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen6502) { internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translateFunctionCallStatement(stmt: IFunctionCall) { internal fun translateFunctionCallStatement(stmt: IFunctionCall) {
saveXbeforeCall(stmt) saveXbeforeCall(stmt)

View File

@ -9,7 +9,7 @@ import prog8.ast.toHex
import prog8.compilerinterface.AssemblyError import prog8.compilerinterface.AssemblyError
internal class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen6502) { internal class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translate(stmt: PostIncrDecr) { internal fun translate(stmt: PostIncrDecr) {
val incr = stmt.operator=="++" val incr = stmt.operator=="++"
val targetIdent = stmt.target.identifier val targetIdent = stmt.target.identifier

View File

@ -4,7 +4,7 @@ import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.codegen.cpu6502.AsmGen6502 import prog8.codegen.cpu6502.AsmGen
import prog8.compilerinterface.AssemblyError import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.IMemSizer import prog8.compilerinterface.IMemSizer
@ -29,7 +29,7 @@ internal enum class SourceStorageKind {
internal class AsmAssignTarget(val kind: TargetStorageKind, internal class AsmAssignTarget(val kind: TargetStorageKind,
private val program: Program, private val program: Program,
private val asmgen: AsmGen6502, private val asmgen: AsmGen,
val datatype: DataType, val datatype: DataType,
val scope: Subroutine?, val scope: Subroutine?,
private val variableAsmName: String? = null, private val variableAsmName: String? = null,
@ -56,7 +56,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
} }
companion object { companion object {
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen6502): AsmAssignTarget { fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget {
with(assign.target) { with(assign.target) {
val idt = inferType(program) val idt = inferType(program)
val dt = idt.getOrElse { throw AssemblyError("unknown dt") } val dt = idt.getOrElse { throw AssemblyError("unknown dt") }
@ -82,7 +82,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
} }
} }
fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: Subroutine?, program: Program, asmgen: AsmGen6502): AsmAssignTarget = fun fromRegisters(registers: RegisterOrPair, signed: Boolean, scope: Subroutine?, program: Program, asmgen: AsmGen): AsmAssignTarget =
when(registers) { when(registers) {
RegisterOrPair.A, RegisterOrPair.A,
RegisterOrPair.X, RegisterOrPair.X,
@ -114,7 +114,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
internal class AsmAssignSource(val kind: SourceStorageKind, internal class AsmAssignSource(val kind: SourceStorageKind,
private val program: Program, private val program: Program,
private val asmgen: AsmGen6502, private val asmgen: AsmGen,
val datatype: DataType, val datatype: DataType,
private val variableAsmName: String? = null, private val variableAsmName: String? = null,
val array: ArrayIndexedExpression? = null, val array: ArrayIndexedExpression? = null,
@ -134,9 +134,9 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
asmgen.asmVariableName(array.arrayvar) asmgen.asmVariableName(array.arrayvar)
companion object { companion object {
fun fromAstSource(indexer: ArrayIndex, program: Program, asmgen: AsmGen6502): AsmAssignSource = fromAstSource(indexer.indexExpr, program, asmgen) fun fromAstSource(indexer: ArrayIndex, program: Program, asmgen: AsmGen): AsmAssignSource = fromAstSource(indexer.indexExpr, program, asmgen)
fun fromAstSource(value: Expression, program: Program, asmgen: AsmGen6502): AsmAssignSource { fun fromAstSource(value: Expression, program: Program, asmgen: AsmGen): AsmAssignSource {
val cv = value.constValue(program) val cv = value.constValue(program)
if(cv!=null) if(cv!=null)
return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv) return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv)

View File

@ -5,14 +5,14 @@ import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.ast.toHex import prog8.ast.toHex
import prog8.codegen.cpu6502.AsmGen6502 import prog8.codegen.cpu6502.AsmGen
import prog8.compilerinterface.AssemblyError import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.BuiltinFunctions import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.CpuType import prog8.compilerinterface.CpuType
import prog8.compilerinterface.builtinFunctionReturnType import prog8.compilerinterface.builtinFunctionReturnType
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen6502) { internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen) private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen)

View File

@ -5,14 +5,14 @@ import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
import prog8.ast.toHex import prog8.ast.toHex
import prog8.codegen.cpu6502.AsmGen6502 import prog8.codegen.cpu6502.AsmGen
import prog8.compilerinterface.AssemblyError import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.CpuType import prog8.compilerinterface.CpuType
internal class AugmentableAssignmentAsmGen(private val program: Program, internal class AugmentableAssignmentAsmGen(private val program: Program,
private val assignmentAsmGen: AssignmentAsmGen, private val assignmentAsmGen: AssignmentAsmGen,
private val asmgen: AsmGen6502 private val asmgen: AsmGen
) { ) {
fun translate(assign: AsmAssignment) { fun translate(assign: AsmAssignment) {
require(assign.isAugmentable) require(assign.isAugmentable)

View File

@ -0,0 +1,18 @@
package prog8.codegen.experimental6502
import prog8.ast.Program
import prog8.compilerinterface.*
class AsmGen(internal val program: Program,
internal val errors: IErrorReporter,
internal val variables: IVariablesAndConsts,
internal val options: CompilationOptions): IAssemblyGenerator {
override fun compileToAssembly(): IAssemblyProgram? {
println("\n** experimental 65(c)02 code generator **\n")
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
return AssemblyProgram("dummy")
}
}

View File

@ -1,20 +0,0 @@
package prog8.codegen.experimental6502
import prog8.ast.Program
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IAssemblyGenerator
import prog8.compilerinterface.IAssemblyProgram
import prog8.compilerinterface.IErrorReporter
class ExperimentalAsmGen6502(internal val program: Program,
internal val errors: IErrorReporter,
internal val options: CompilationOptions
): IAssemblyGenerator {
override fun compileToAssembly(): IAssemblyProgram? {
println("\n** experimental 65(c)02 code generator **\n")
println("..todo: create assembly code into ${options.outputDir.toAbsolutePath()}..")
return AssemblyProgram("dummy")
}
}

View File

@ -9,8 +9,6 @@ import prog8.ast.base.Position
import prog8.ast.expressions.Expression import prog8.ast.expressions.Expression
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.Directive import prog8.ast.statements.Directive
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.experimental6502.ExperimentalAsmGen6502
import prog8.codegen.target.C128Target import prog8.codegen.target.C128Target
import prog8.codegen.target.C64Target import prog8.codegen.target.C64Target
import prog8.codegen.target.Cx16Target import prog8.codegen.target.Cx16Target
@ -21,6 +19,7 @@ import prog8.parser.ParseError
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.Path import kotlin.io.path.Path
import kotlin.io.path.nameWithoutExtension import kotlin.io.path.nameWithoutExtension
import kotlin.math.round
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
@ -109,7 +108,8 @@ fun compileProgram(args: CompilerArguments): CompilationResult {
} }
System.out.flush() System.out.flush()
System.err.flush() System.err.flush()
println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.") val seconds = totalTime/1000.0
println("\nTotal compilation+assemble time: ${round(seconds*100.0)/100.0} sec.")
return CompilationResult(true, program, programName, compTarget, importedFiles) return CompilationResult(true, program, programName, compTarget, importedFiles)
} catch (px: ParseError) { } catch (px: ParseError) {
System.err.print("\u001b[91m") // bright red System.err.print("\u001b[91m") // bright red
@ -344,14 +344,13 @@ private fun writeAssembly(program: Program,
): WriteAssemblyResult { ): WriteAssemblyResult {
// asm generation directly from the Ast // asm generation directly from the Ast
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions) compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
program.processAstBeforeAsmGeneration(compilerOptions, errors) val variables = program.processAstBeforeAsmGeneration(compilerOptions, errors)
errors.report() errors.report()
// TODO do something with the VariableAllocation, pass it to the asmgenerator
// println("*********** AST RIGHT BEFORE ASM GENERATION *************") // println("*********** AST RIGHT BEFORE ASM GENERATION *************")
// printProgram(program) // printProgram(program)
val assembly = asmGeneratorFor(program, errors, compilerOptions).compileToAssembly() val assembly = asmGeneratorFor(program, errors, variables, compilerOptions).compileToAssembly()
errors.report() errors.report()
return if(assembly!=null && errors.noErrors()) { return if(assembly!=null && errors.noErrors()) {
@ -371,18 +370,14 @@ fun printProgram(program: Program) {
println() println()
} }
internal fun asmGeneratorFor( internal fun asmGeneratorFor(program: Program, errors: IErrorReporter, variables: IVariablesAndConsts, options: CompilationOptions): IAssemblyGenerator
program: Program,
errors: IErrorReporter,
options: CompilationOptions,
): IAssemblyGenerator
{ {
if(options.experimentalCodegen) { if(options.experimentalCodegen) {
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
return ExperimentalAsmGen6502(program, errors, options) return prog8.codegen.experimental6502.AsmGen(program, errors, variables, options)
} else { } else {
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
return AsmGen6502(program, errors, options) return prog8.codegen.cpu6502.AsmGen(program, errors, variables, options)
} }
throw NotImplementedError("no asm generator for cpu ${options.compTarget.machine.cpu}") throw NotImplementedError("no asm generator for cpu ${options.compTarget.machine.cpu}")

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,7 +24,7 @@ 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, errors: IErrorReporter): IVariablesAndConsts {
val fixer = BeforeAsmAstChanger(this, compilerOptions, errors) val fixer = BeforeAsmAstChanger(this, compilerOptions, errors)
fixer.visit(this) fixer.visit(this)
while(errors.noErrors() && fixer.applyModifications()>0) { while(errors.noErrors() && fixer.applyModifications()>0) {
@ -34,6 +35,7 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
while(errors.noErrors() && cleaner.applyModifications()>0) { while(errors.noErrors() && cleaner.applyModifications()>0) {
cleaner.visit(this) cleaner.visit(this)
} }
return fixer.variables
} }
internal fun Program.reorderStatements(errors: IErrorReporter, options: CompilationOptions) { internal fun Program.reorderStatements(errors: IErrorReporter, options: CompilationOptions) {

View File

@ -20,17 +20,14 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
private val allSubroutineVars = mutableMapOf<Subroutine, MutableSet<VarDecl>>() private val allSubroutineVars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
private val allSubroutineConsts = mutableMapOf<Subroutine, MutableSet<VarDecl>>() private val allSubroutineConsts = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
private val allSubroutineMemoryvars = mutableMapOf<Subroutine, MutableSet<VarDecl>>() private val allSubroutineMemoryvars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
internal lateinit var allocation: IVariableAllocation internal lateinit var variables: IVariablesAndConsts
/* TODO complete the use of VariableAllocation and get rid of it from the AsmGen (and that should no longer use vardecl either):
override fun after(program: Program): Iterable<IAstModification> { override fun after(program: Program): Iterable<IAstModification> {
allocation = VariableAllocation(options, variables = VariablesAndConsts(
allBlockVars, allBlockConsts, allBlockMemoryvars, allBlockVars, allBlockConsts, allBlockMemoryvars,
allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars) allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars)
allocation.dump(program.memsizer)
return super.after(program) return super.after(program)
} }
*/
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> { override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
throw FatalAstException("break should have been replaced by goto $breakStmt") throw FatalAstException("break should have been replaced by goto $breakStmt")
@ -446,46 +443,39 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
} }
internal class VariableAllocation ( internal class VariablesAndConsts (
options: CompilationOptions,
astBlockVars: Map<Block, Set<VarDecl>>, astBlockVars: Map<Block, Set<VarDecl>>,
astBlockConsts: Map<Block, Set<VarDecl>>, astBlockConsts: Map<Block, Set<VarDecl>>,
astBlockMemvars: Map<Block, Set<VarDecl>>, astBlockMemvars: Map<Block, Set<VarDecl>>,
astSubroutineVars: Map<Subroutine, Set<VarDecl>>, astSubroutineVars: Map<Subroutine, Set<VarDecl>>,
astSubroutineConsts: Map<Subroutine, Set<VarDecl>>, astSubroutineConsts: Map<Subroutine, Set<VarDecl>>,
astSubroutineMemvars: Map<Subroutine, Set<VarDecl>> astSubroutineMemvars: Map<Subroutine, Set<VarDecl>>
) : IVariableAllocation ) : IVariablesAndConsts
{ {
override val zeropageVars: Set<IVariableAllocation.ZeropageVariable> override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
override val blockVars: Map<Block, Set<IVariableAllocation.StaticBlockVariable>> override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val blockConsts: Map<Block, Set<IVariableAllocation.ConstantNumberSymbol>> override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
override val blockMemvars: Map<Block, Set<IVariableAllocation.MemoryMappedSymbol>> override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariableAllocation.StaticSubroutineVariable>> override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineConsts: Map<Subroutine, Set<IVariableAllocation.ConstantNumberSymbol>> override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
override val subroutineMemvars: Map<Subroutine, Set<IVariableAllocation.MemoryMappedSymbol>>
init { init {
if(options.zeropage!=ZeropageType.DONTUSE) val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticBlockVariable>() }
allocateVarsInZeropage(options.compTarget.machine.zeropage) val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
val zpv = mutableSetOf<IVariableAllocation.ZeropageVariable>() val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticSubroutineVariable>() }
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariableAllocation.StaticBlockVariable>() } val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariableAllocation.ConstantNumberSymbol>() } val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariableAllocation.MemoryMappedSymbol>() }
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariableAllocation.StaticSubroutineVariable>() }
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariableAllocation.ConstantNumberSymbol>() }
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariableAllocation.MemoryMappedSymbol>() }
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 {
// TODO make sure the zp-allocated variables are not added here IVariablesAndConsts.StaticBlockVariable(it.datatype, it.name, it.value, it.position, it)
IVariableAllocation.StaticBlockVariable(it.datatype, it.name, it.value, it.position, it)
}) })
} }
astBlockConsts.forEach { (block, decls) -> astBlockConsts.forEach { (block, decls) ->
bc.getValue(block).addAll( bc.getValue(block).addAll(
decls.map { decls.map {
IVariableAllocation.ConstantNumberSymbol( IVariablesAndConsts.ConstantNumberSymbol(
it.datatype, it.datatype,
it.name, it.name,
(it.value as NumericLiteralValue).number, (it.value as NumericLiteralValue).number,
@ -496,7 +486,7 @@ internal class VariableAllocation (
astBlockMemvars.forEach { (block, decls) -> astBlockMemvars.forEach { (block, decls) ->
bmv.getValue(block).addAll( bmv.getValue(block).addAll(
decls.map { decls.map {
IVariableAllocation.MemoryMappedSymbol( IVariablesAndConsts.MemoryMappedVariable(
it.datatype, it.datatype,
it.name, it.name,
(it.value as NumericLiteralValue).number.toUInt(), (it.value as NumericLiteralValue).number.toUInt(),
@ -507,14 +497,13 @@ internal class VariableAllocation (
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 {
// TODO make sure the zp-allocated variables are not added here IVariablesAndConsts.StaticSubroutineVariable(it.datatype, it.name, it.position, it)
IVariableAllocation.StaticSubroutineVariable(it.datatype, it.name, it.position, it)
}) })
} }
astSubroutineConsts.forEach { (sub, decls) -> astSubroutineConsts.forEach { (sub, decls) ->
sc.getValue(sub).addAll( sc.getValue(sub).addAll(
decls.map { decls.map {
IVariableAllocation.ConstantNumberSymbol( IVariablesAndConsts.ConstantNumberSymbol(
it.datatype, it.datatype,
it.name, it.name,
(it.value as NumericLiteralValue).number, (it.value as NumericLiteralValue).number,
@ -525,7 +514,7 @@ internal class VariableAllocation (
astSubroutineMemvars.forEach { (sub, decls) -> astSubroutineMemvars.forEach { (sub, decls) ->
smv.getValue(sub).addAll( smv.getValue(sub).addAll(
decls.map { decls.map {
IVariableAllocation.MemoryMappedSymbol( IVariablesAndConsts.MemoryMappedVariable(
it.datatype, it.datatype,
it.name, it.name,
(it.value as NumericLiteralValue).number.toUInt(), (it.value as NumericLiteralValue).number.toUInt(),
@ -533,7 +522,6 @@ internal class VariableAllocation (
) )
}) })
} }
zeropageVars = zpv
blockVars = bv blockVars = bv
blockConsts = bc blockConsts = bc
blockMemvars = bmv blockMemvars = bmv
@ -542,15 +530,7 @@ internal class VariableAllocation (
subroutineMemvars = smv subroutineMemvars = smv
} }
private fun allocateVarsInZeropage(zeropage: Zeropage) {
println("TODO: allocate vars on zeropage") // TODO
}
override fun dump(memsizer: IMemSizer) { override fun dump(memsizer: IMemSizer) {
println("\nALL ZEROPAGE VARS:")
zeropageVars.forEach {
println(" ${it.type} ${it.scopedname} ${it.position}")
}
println("\nALL BLOCK VARS:") println("\nALL BLOCK VARS:")
blockVars.forEach { (block, vars) -> blockVars.forEach { (block, vars) ->
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) } val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }

View File

@ -301,7 +301,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()) val allocation = result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
// assignment is now split into: // assignment is now split into:
// bb = not bb // bb = not bb
@ -326,7 +326,7 @@ class TestOptimization: FunSpec({
((bbAssigns1expr.right as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww") ((bbAssigns1expr.right as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww")
bbAssigns1expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE bbAssigns1expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
val asm = generateAssembly(result.program, options) val asm = generateAssembly(result.program, allocation, options)
asm shouldNotBe null asm shouldNotBe null
asm!!.name.shouldNotBeBlank() asm!!.name.shouldNotBeBlank()
} }
@ -366,7 +366,7 @@ class TestOptimization: FunSpec({
test("asmgen correctly deals with float typecasting in augmented assignment") { test("asmgen correctly deals with float typecasting in augmented assignment") {
val src=""" val src="""
%option enable_floats %import floats
main { main {
sub start() { sub start() {
@ -385,9 +385,7 @@ class TestOptimization: FunSpec({
(value.left as? IdentifierReference)?.nameInSource shouldBe listOf("ff") (value.left as? IdentifierReference)?.nameInSource shouldBe listOf("ff")
value.right shouldBe instanceOf<TypecastExpression>() value.right shouldBe instanceOf<TypecastExpression>()
val asm = generateAssembly(result.program) compileText(C64Target(), optimize=false, src, writeAssembly = true).assertSuccess()
asm shouldNotBe null
asm!!.name.shouldNotBeBlank()
} }
test("unused variable removal") { test("unused variable removal") {

View File

@ -12,22 +12,18 @@ import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.codegen.cpu6502.AsmGen6502 import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.target.C64Target import prog8.codegen.target.C64Target
import prog8.codegen.target.c64.C64Zeropage import prog8.codegen.target.c64.C64Zeropage
import prog8.compilerinterface.CompilationOptions import prog8.compilerinterface.*
import prog8.compilerinterface.LauncherType
import prog8.compilerinterface.OutputType
import prog8.compilerinterface.ZeropageType
import prog8.parser.SourceCode import prog8.parser.SourceCode
import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder import prog8tests.helpers.DummyStringEncoder
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
import java.nio.file.Path
class TestAsmGenSymbols: StringSpec({ class TestAsmGenSymbols: StringSpec({
fun createTestProgram(): Program { fun createTestProgram(): Pair<Program, IVariablesAndConsts> {
/* /*
main { main {
@ -72,20 +68,42 @@ class TestAsmGenSymbols: StringSpec({
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY) val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test")) val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
return Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder).addModule(module) val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder).addModule(module)
val variables = object : IVariablesAndConsts {
override fun dump(memsizer: IMemSizer) { }
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
init {
blockVars = mutableMapOf()
blockVars[block] = mutableSetOf(IVariablesAndConsts.StaticBlockVariable(varInBlock.datatype, varInBlock.name, varInBlock.value, varInBlock.position, varInBlock))
blockConsts = mutableMapOf()
blockMemvars = mutableMapOf()
subroutineVars = mutableMapOf()
subroutineVars[subroutine] = mutableSetOf(
IVariablesAndConsts.StaticSubroutineVariable(varInSub.datatype, varInSub.name, varInSub.position, varInSub),
IVariablesAndConsts.StaticSubroutineVariable(var2InSub.datatype, var2InSub.name, var2InSub.position, var2InSub)
)
subroutineConsts = mutableMapOf()
subroutineMemvars = mutableMapOf()
}
}
return Pair(program, variables)
} }
fun createTestAsmGen(program: Program): AsmGen6502 { fun createTestAsmGen(program: Program, allocation: IVariablesAndConsts): AsmGen {
val errors = ErrorReporterForTests() val errors = ErrorReporterForTests()
val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target()) val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target())
options.compTarget.machine.zeropage = C64Zeropage(options) options.compTarget.machine.zeropage = C64Zeropage(options)
val asmgen = AsmGen6502(program, errors, options) return AsmGen(program, errors, allocation, options)
return asmgen
} }
"symbol and variable names from strings" { "symbol and variable names from strings" {
val program = createTestProgram() val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen(program, variables)
asmgen.asmSymbolName("name") shouldBe "name" asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("name") shouldBe "name" asmgen.asmSymbolName("name") shouldBe "name"
asmgen.asmSymbolName("<name>") shouldBe "prog8_name" asmgen.asmSymbolName("<name>") shouldBe "prog8_name"
@ -97,8 +115,8 @@ class TestAsmGenSymbols: StringSpec({
} }
"symbol and variable names from variable identifiers" { "symbol and variable names from variable identifiers" {
val program = createTestProgram() val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen(program, variables)
val sub = program.entrypoint val sub = program.entrypoint
val localvarIdent = sub.statements.asSequence().filterIsInstance<Assignment>().first { it.value is IdentifierReference }.value as IdentifierReference val localvarIdent = sub.statements.asSequence().filterIsInstance<Assignment>().first { it.value is IdentifierReference }.value as IdentifierReference
@ -117,8 +135,8 @@ class TestAsmGenSymbols: StringSpec({
} }
"symbol and variable names from label identifiers" { "symbol and variable names from label identifiers" {
val program = createTestProgram() val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen(program, variables)
val sub = program.entrypoint val sub = program.entrypoint
val localLabelIdent = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("locallabel") }.value as AddressOf).identifier val localLabelIdent = (sub.statements.asSequence().filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("locallabel") }.value as AddressOf).identifier
@ -146,8 +164,8 @@ main {
prog8_lib.P8ZP_SCRATCH_W1 = 1 prog8_lib.P8ZP_SCRATCH_W1 = 1
prog8_lib.P8ZP_SCRATCH_W2 = 1 prog8_lib.P8ZP_SCRATCH_W2 = 1
*/ */
val program = createTestProgram() val (program, variables) = createTestProgram()
val asmgen = createTestAsmGen(program) val asmgen = createTestAsmGen(program, variables)
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_REG") shouldBe "P8ZP_SCRATCH_REG" asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_REG") shouldBe "P8ZP_SCRATCH_REG"
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_W2") shouldBe "P8ZP_SCRATCH_W2" asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_W2") shouldBe "P8ZP_SCRATCH_W2"
asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG" asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG"

View File

@ -11,7 +11,7 @@ import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
import prog8.compilerinterface.* import prog8.compilerinterface.*
internal val DummyFunctions = object : IBuiltinFunctions { internal object DummyFunctions : IBuiltinFunctions {
override val names: Set<String> = emptySet() override val names: Set<String> = emptySet()
override val purefunctionNames: Set<String> = emptySet() override val purefunctionNames: Set<String> = emptySet()
override fun constValue( override fun constValue(
@ -23,12 +23,12 @@ internal val DummyFunctions = object : IBuiltinFunctions {
override fun returnType(name: String, args: MutableList<Expression>) = InferredTypes.InferredType.unknown() override fun returnType(name: String, args: MutableList<Expression>) = InferredTypes.InferredType.unknown()
} }
internal val DummyMemsizer = object : IMemSizer { internal object DummyMemsizer : IMemSizer {
override fun memorySize(dt: DataType) = 0 override fun memorySize(dt: DataType) = 0
override fun memorySize(decl: VarDecl) = 0 override fun memorySize(decl: VarDecl) = 0
} }
internal val DummyStringEncoder = object : IStringEncoding { internal object DummyStringEncoder : IStringEncoding {
override fun encodeString(str: String, encoding: Encoding): List<UByte> { override fun encodeString(str: String, encoding: Encoding): List<UByte> {
return emptyList() return emptyList()
} }
@ -38,7 +38,7 @@ internal val DummyStringEncoder = object : IStringEncoding {
} }
} }
internal val AsciiStringEncoder = object : IStringEncoding { internal object AsciiStringEncoder : IStringEncoding {
override fun encodeString(str: String, encoding: Encoding): List<UByte> = str.map { it.code.toUByte() } override fun encodeString(str: String, encoding: Encoding): List<UByte> = str.map { it.code.toUByte() }
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String { override fun decodeString(bytes: List<UByte>, encoding: Encoding): String {
@ -46,7 +46,7 @@ internal val AsciiStringEncoder = object : IStringEncoding {
} }
} }
internal val DummyCompilationTarget = object : ICompilationTarget { internal object DummyCompilationTarget : ICompilationTarget {
override val name: String = "dummy" override val name: String = "dummy"
override val machine: IMachineDefinition override val machine: IMachineDefinition
get() = throw NotImplementedError("dummy") get() = throw NotImplementedError("dummy")

View File

@ -3,7 +3,7 @@ package prog8tests.helpers
import io.kotest.assertions.withClue import io.kotest.assertions.withClue
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import prog8.ast.Program import prog8.ast.Program
import prog8.codegen.cpu6502.AsmGen6502 import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.target.C64Target import prog8.codegen.target.C64Target
import prog8.codegen.target.c64.C64Zeropage import prog8.codegen.target.c64.C64Zeropage
import prog8.compiler.CompilationResult import prog8.compiler.CompilationResult
@ -83,10 +83,11 @@ internal fun compileText(
internal fun generateAssembly( internal fun generateAssembly(
program: Program, program: Program,
allocation: IVariablesAndConsts,
options: CompilationOptions? = null options: CompilationOptions? = null
): IAssemblyProgram? { ): IAssemblyProgram? {
val coptions = options ?: CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir) val coptions = options ?: CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir)
coptions.compTarget.machine.zeropage = C64Zeropage(coptions) coptions.compTarget.machine.zeropage = C64Zeropage(coptions)
val asmgen = AsmGen6502(program, ErrorReporterForTests(), coptions) val asmgen = AsmGen(program, ErrorReporterForTests(), allocation, coptions)
return asmgen.compileToAssembly() return asmgen.compileToAssembly()
} }

View File

@ -7,21 +7,24 @@ import prog8.ast.statements.Block
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
/**
interface IVariableAllocation { * Experimental attempt for:
* A more convenient way to pass variable (and constant values) definitions to the code generator,
* so that it doesn't have to scavenge all VerDecl nodes in the AST for this information.
*/
interface IVariablesAndConsts {
data class ConstantNumberSymbol(val type: DataType, val name: String, val value: Double, val position: Position) data class ConstantNumberSymbol(val type: DataType, val name: String, val value: Double, val position: Position)
data class MemoryMappedSymbol(val type: DataType, val name: String, val address: UInt, val position: Position) data class MemoryMappedVariable(val type: DataType, val name: String, val address: UInt, val position: Position)
data class StaticBlockVariable(val type: DataType, val name: String, val initialValue: Expression?, val position: Position, val origVar: VarDecl) // TODO should get rid of origVar altogether // TODO should get rid of origVar altogether in the following two:
data class StaticSubroutineVariable(val type: DataType, val name: String, val position: Position, val origVar: VarDecl) // TODO should get rid of origVar altogether data class StaticBlockVariable(val type: DataType, val name: String, val initialValue: Expression?, val position: Position, val origVar: VarDecl)
data class ZeropageVariable(val type: DataType, val scopedname: List<String>, val position: Position) data class StaticSubroutineVariable(val type: DataType, val name: String, val position: Position, val origVar: VarDecl)
fun dump(memsizer: IMemSizer) fun dump(memsizer: IMemSizer)
val zeropageVars: Set<ZeropageVariable> // also present in the Zeropage object after this allocation
val blockVars: Map<Block, Set<StaticBlockVariable>> val blockVars: Map<Block, Set<StaticBlockVariable>>
val blockConsts: Map<Block, Set<ConstantNumberSymbol>> val blockConsts: Map<Block, Set<ConstantNumberSymbol>>
val blockMemvars: Map<Block, Set<MemoryMappedSymbol>> val blockMemvars: Map<Block, Set<MemoryMappedVariable>>
val subroutineVars: Map<Subroutine, Set<StaticSubroutineVariable>> val subroutineVars: Map<Subroutine, Set<StaticSubroutineVariable>>
val subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>> val subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>>
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedSymbol>> val subroutineMemvars: Map<Subroutine, Set<MemoryMappedVariable>>
} }

View File

@ -20,12 +20,10 @@ Blocked by an official Commander-x16 r39 release
Future Things and Ideas Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
Ast modifications done in AsmGen, that should be done BEFORE calling asmgen (so that it doesn't have to modify the Ast any longer): Ast modifications done in AsmGen that perhaps should not be necessary:
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
- block2asm: after vardecls2asm it clears the vardecl.value of all variables - block2asm: after vardecls2asm it clears the vardecl.value of all variables
- Maybe don't rely on vardecls at all any longer but figure out the variable allocations (including ZP allocations) beforehand --> Don't rely on vardecls at all any longer but use the new IVariablesAndConsts object passed to the AsmGen, this will solve this item.
and pass that via a new datastructure to asmgen? So that asmgen is no longer tasked with doing the allocations. - block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
This could perhaps make it easer for the codegen as well to deal with sections, if any, in the future.
- remove support for old @"screencodes" string encoding syntax (parser+code+docs) - remove support for old @"screencodes" string encoding syntax (parser+code+docs)
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type - allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type
@ -54,6 +52,7 @@ Ast modifications done in AsmGen, that should be done BEFORE calling asmgen (so
Perhaps replace all uses of .proc/.pend by .block/.bend will fix that? Perhaps replace all uses of .proc/.pend by .block/.bend will fix that?
(but we lose the optimizing aspect of the assembler where it strips out unused code. (but we lose the optimizing aspect of the assembler where it strips out unused code.
There's not really a dynamic switch possible as all assembly lib code is static and uses one or the other) There's not really a dynamic switch possible as all assembly lib code is static and uses one or the other)
- zig try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for this)
- get rid of all TODO's in the code ;) - get rid of all TODO's in the code ;)