mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
some naming changes and cleanups
This commit is contained in:
parent
10de7dc1f9
commit
101fb0b8aa
@ -23,9 +23,10 @@ const val subroutineFloatEvalResultVar1 = "prog8_float_eval_result1"
|
||||
const val subroutineFloatEvalResultVar2 = "prog8_float_eval_result2"
|
||||
|
||||
|
||||
class AsmGen6502(internal val program: Program,
|
||||
internal val errors: IErrorReporter,
|
||||
internal val options: CompilationOptions): IAssemblyGenerator {
|
||||
class AsmGen(internal val program: Program,
|
||||
internal val errors: IErrorReporter,
|
||||
internal val variables: IVariablesAndConsts,
|
||||
internal val options: CompilationOptions): IAssemblyGenerator {
|
||||
|
||||
// for expressions and augmented assignments:
|
||||
val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
|
||||
@ -54,6 +55,8 @@ class AsmGen6502(internal val program: Program,
|
||||
|
||||
println("Generating assembly code... ")
|
||||
|
||||
// TODO variables.dump(program.memsizer)
|
||||
|
||||
val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value }
|
||||
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.
|
||||
val (subroutine, stmts) = statements.partition { it is Subroutine }
|
||||
stmts.forEach { translate(it) }
|
||||
subroutine.forEach { translateSubroutine(it as Subroutine) }
|
||||
subroutine.forEach { translate(it) }
|
||||
|
||||
if(!options.dontReinitGlobals) {
|
||||
// generate subroutine to initialize block-level (global) variables
|
@ -17,7 +17,7 @@ import prog8.compilerinterface.CpuType
|
||||
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?) {
|
||||
translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister)
|
||||
|
@ -11,7 +11,7 @@ import prog8.compilerinterface.BuiltinFunctions
|
||||
import prog8.compilerinterface.CpuType
|
||||
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")
|
||||
internal fun translateExpression(expression:Expression) {
|
||||
|
@ -12,7 +12,7 @@ import prog8.ast.toHex
|
||||
import prog8.compilerinterface.AssemblyError
|
||||
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) {
|
||||
val iterableDt = stmt.iterable.inferType(program)
|
||||
|
@ -17,7 +17,7 @@ import prog8.compilerinterface.AssemblyError
|
||||
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) {
|
||||
saveXbeforeCall(stmt)
|
||||
|
@ -9,7 +9,7 @@ import prog8.ast.toHex
|
||||
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) {
|
||||
val incr = stmt.operator=="++"
|
||||
val targetIdent = stmt.target.identifier
|
||||
|
@ -4,7 +4,7 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.codegen.cpu6502.AsmGen6502
|
||||
import prog8.codegen.cpu6502.AsmGen
|
||||
import prog8.compilerinterface.AssemblyError
|
||||
import prog8.compilerinterface.IMemSizer
|
||||
|
||||
@ -29,7 +29,7 @@ internal enum class SourceStorageKind {
|
||||
|
||||
internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
private val program: Program,
|
||||
private val asmgen: AsmGen6502,
|
||||
private val asmgen: AsmGen,
|
||||
val datatype: DataType,
|
||||
val scope: Subroutine?,
|
||||
private val variableAsmName: String? = null,
|
||||
@ -56,7 +56,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen6502): AsmAssignTarget {
|
||||
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget {
|
||||
with(assign.target) {
|
||||
val idt = inferType(program)
|
||||
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) {
|
||||
RegisterOrPair.A,
|
||||
RegisterOrPair.X,
|
||||
@ -114,7 +114,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
|
||||
internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
private val program: Program,
|
||||
private val asmgen: AsmGen6502,
|
||||
private val asmgen: AsmGen,
|
||||
val datatype: DataType,
|
||||
private val variableAsmName: String? = null,
|
||||
val array: ArrayIndexedExpression? = null,
|
||||
@ -134,9 +134,9 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
asmgen.asmVariableName(array.arrayvar)
|
||||
|
||||
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)
|
||||
if(cv!=null)
|
||||
return AsmAssignSource(SourceStorageKind.LITERALNUMBER, program, asmgen, cv.type, number = cv)
|
||||
|
@ -5,14 +5,14 @@ import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.toHex
|
||||
import prog8.codegen.cpu6502.AsmGen6502
|
||||
import prog8.codegen.cpu6502.AsmGen
|
||||
import prog8.compilerinterface.AssemblyError
|
||||
import prog8.compilerinterface.BuiltinFunctions
|
||||
import prog8.compilerinterface.CpuType
|
||||
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)
|
||||
|
||||
|
@ -5,14 +5,14 @@ import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.toHex
|
||||
import prog8.codegen.cpu6502.AsmGen6502
|
||||
import prog8.codegen.cpu6502.AsmGen
|
||||
import prog8.compilerinterface.AssemblyError
|
||||
import prog8.compilerinterface.CpuType
|
||||
|
||||
|
||||
internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
private val assignmentAsmGen: AssignmentAsmGen,
|
||||
private val asmgen: AsmGen6502
|
||||
private val asmgen: AsmGen
|
||||
) {
|
||||
fun translate(assign: AsmAssignment) {
|
||||
require(assign.isAugmentable)
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
@ -9,8 +9,6 @@ import prog8.ast.base.Position
|
||||
import prog8.ast.expressions.Expression
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.statements.Directive
|
||||
import prog8.codegen.cpu6502.AsmGen6502
|
||||
import prog8.codegen.experimental6502.ExperimentalAsmGen6502
|
||||
import prog8.codegen.target.C128Target
|
||||
import prog8.codegen.target.C64Target
|
||||
import prog8.codegen.target.Cx16Target
|
||||
@ -21,6 +19,7 @@ import prog8.parser.ParseError
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.nameWithoutExtension
|
||||
import kotlin.math.round
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
|
||||
@ -109,7 +108,8 @@ fun compileProgram(args: CompilerArguments): CompilationResult {
|
||||
}
|
||||
System.out.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)
|
||||
} catch (px: ParseError) {
|
||||
System.err.print("\u001b[91m") // bright red
|
||||
@ -344,14 +344,13 @@ private fun writeAssembly(program: Program,
|
||||
): WriteAssemblyResult {
|
||||
// asm generation directly from the Ast
|
||||
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
||||
program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||
val variables = program.processAstBeforeAsmGeneration(compilerOptions, errors)
|
||||
errors.report()
|
||||
// TODO do something with the VariableAllocation, pass it to the asmgenerator
|
||||
|
||||
// println("*********** AST RIGHT BEFORE ASM GENERATION *************")
|
||||
// printProgram(program)
|
||||
|
||||
val assembly = asmGeneratorFor(program, errors, compilerOptions).compileToAssembly()
|
||||
val assembly = asmGeneratorFor(program, errors, variables, compilerOptions).compileToAssembly()
|
||||
errors.report()
|
||||
|
||||
return if(assembly!=null && errors.noErrors()) {
|
||||
@ -371,18 +370,14 @@ fun printProgram(program: Program) {
|
||||
println()
|
||||
}
|
||||
|
||||
internal fun asmGeneratorFor(
|
||||
program: Program,
|
||||
errors: IErrorReporter,
|
||||
options: CompilationOptions,
|
||||
): IAssemblyGenerator
|
||||
internal fun asmGeneratorFor(program: Program, errors: IErrorReporter, variables: IVariablesAndConsts, options: CompilationOptions): IAssemblyGenerator
|
||||
{
|
||||
if(options.experimentalCodegen) {
|
||||
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 {
|
||||
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}")
|
||||
|
@ -13,6 +13,7 @@ import prog8.ast.walk.IAstModification
|
||||
import prog8.compilerinterface.CompilationOptions
|
||||
import prog8.compilerinterface.IErrorReporter
|
||||
import prog8.compilerinterface.IStringEncoding
|
||||
import prog8.compilerinterface.IVariablesAndConsts
|
||||
|
||||
|
||||
internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) {
|
||||
@ -23,7 +24,7 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
|
||||
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)
|
||||
fixer.visit(this)
|
||||
while(errors.noErrors() && fixer.applyModifications()>0) {
|
||||
@ -34,6 +35,7 @@ internal fun Program.processAstBeforeAsmGeneration(compilerOptions: CompilationO
|
||||
while(errors.noErrors() && cleaner.applyModifications()>0) {
|
||||
cleaner.visit(this)
|
||||
}
|
||||
return fixer.variables
|
||||
}
|
||||
|
||||
internal fun Program.reorderStatements(errors: IErrorReporter, options: CompilationOptions) {
|
||||
|
@ -20,17 +20,14 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
||||
private val allSubroutineVars = mutableMapOf<Subroutine, MutableSet<VarDecl>>()
|
||||
private val allSubroutineConsts = 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> {
|
||||
allocation = VariableAllocation(options,
|
||||
variables = VariablesAndConsts(
|
||||
allBlockVars, allBlockConsts, allBlockMemoryvars,
|
||||
allSubroutineVars, allSubroutineConsts, allSubroutineMemoryvars)
|
||||
allocation.dump(program.memsizer)
|
||||
return super.after(program)
|
||||
}
|
||||
*/
|
||||
|
||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||
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 (
|
||||
options: CompilationOptions,
|
||||
internal class VariablesAndConsts (
|
||||
astBlockVars: Map<Block, Set<VarDecl>>,
|
||||
astBlockConsts: Map<Block, Set<VarDecl>>,
|
||||
astBlockMemvars: Map<Block, Set<VarDecl>>,
|
||||
astSubroutineVars: Map<Subroutine, Set<VarDecl>>,
|
||||
astSubroutineConsts: Map<Subroutine, Set<VarDecl>>,
|
||||
astSubroutineMemvars: Map<Subroutine, Set<VarDecl>>
|
||||
) : IVariableAllocation
|
||||
) : IVariablesAndConsts
|
||||
{
|
||||
override val zeropageVars: Set<IVariableAllocation.ZeropageVariable>
|
||||
override val blockVars: Map<Block, Set<IVariableAllocation.StaticBlockVariable>>
|
||||
override val blockConsts: Map<Block, Set<IVariableAllocation.ConstantNumberSymbol>>
|
||||
override val blockMemvars: Map<Block, Set<IVariableAllocation.MemoryMappedSymbol>>
|
||||
override val subroutineVars: Map<Subroutine, Set<IVariableAllocation.StaticSubroutineVariable>>
|
||||
override val subroutineConsts: Map<Subroutine, Set<IVariableAllocation.ConstantNumberSymbol>>
|
||||
override val subroutineMemvars: Map<Subroutine, Set<IVariableAllocation.MemoryMappedSymbol>>
|
||||
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 {
|
||||
if(options.zeropage!=ZeropageType.DONTUSE)
|
||||
allocateVarsInZeropage(options.compTarget.machine.zeropage)
|
||||
|
||||
val zpv = mutableSetOf<IVariableAllocation.ZeropageVariable>()
|
||||
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariableAllocation.StaticBlockVariable>() }
|
||||
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariableAllocation.ConstantNumberSymbol>() }
|
||||
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>() }
|
||||
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticBlockVariable>() }
|
||||
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
|
||||
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
|
||||
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticSubroutineVariable>() }
|
||||
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
|
||||
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
|
||||
astBlockVars.forEach { (block, decls) ->
|
||||
val vars = bv.getValue(block)
|
||||
vars.addAll(decls.map {
|
||||
// TODO make sure the zp-allocated variables are not added here
|
||||
IVariableAllocation.StaticBlockVariable(it.datatype, it.name, it.value, it.position, it)
|
||||
IVariablesAndConsts.StaticBlockVariable(it.datatype, it.name, it.value, it.position, it)
|
||||
})
|
||||
}
|
||||
astBlockConsts.forEach { (block, decls) ->
|
||||
bc.getValue(block).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.ConstantNumberSymbol(
|
||||
IVariablesAndConsts.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
@ -496,7 +486,7 @@ internal class VariableAllocation (
|
||||
astBlockMemvars.forEach { (block, decls) ->
|
||||
bmv.getValue(block).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.MemoryMappedSymbol(
|
||||
IVariablesAndConsts.MemoryMappedVariable(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number.toUInt(),
|
||||
@ -507,14 +497,13 @@ internal class VariableAllocation (
|
||||
astSubroutineVars.forEach { (sub, decls) ->
|
||||
val vars = sv.getValue(sub)
|
||||
vars.addAll(decls.map {
|
||||
// TODO make sure the zp-allocated variables are not added here
|
||||
IVariableAllocation.StaticSubroutineVariable(it.datatype, it.name, it.position, it)
|
||||
IVariablesAndConsts.StaticSubroutineVariable(it.datatype, it.name, it.position, it)
|
||||
})
|
||||
}
|
||||
astSubroutineConsts.forEach { (sub, decls) ->
|
||||
sc.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.ConstantNumberSymbol(
|
||||
IVariablesAndConsts.ConstantNumberSymbol(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number,
|
||||
@ -525,7 +514,7 @@ internal class VariableAllocation (
|
||||
astSubroutineMemvars.forEach { (sub, decls) ->
|
||||
smv.getValue(sub).addAll(
|
||||
decls.map {
|
||||
IVariableAllocation.MemoryMappedSymbol(
|
||||
IVariablesAndConsts.MemoryMappedVariable(
|
||||
it.datatype,
|
||||
it.name,
|
||||
(it.value as NumericLiteralValue).number.toUInt(),
|
||||
@ -533,7 +522,6 @@ internal class VariableAllocation (
|
||||
)
|
||||
})
|
||||
}
|
||||
zeropageVars = zpv
|
||||
blockVars = bv
|
||||
blockConsts = bc
|
||||
blockMemvars = bmv
|
||||
@ -542,15 +530,7 @@ internal class VariableAllocation (
|
||||
subroutineMemvars = smv
|
||||
}
|
||||
|
||||
private fun allocateVarsInZeropage(zeropage: Zeropage) {
|
||||
println("TODO: allocate vars on zeropage") // TODO
|
||||
}
|
||||
|
||||
override fun dump(memsizer: IMemSizer) {
|
||||
println("\nALL ZEROPAGE VARS:")
|
||||
zeropageVars.forEach {
|
||||
println(" ${it.type} ${it.scopedname} ${it.position}")
|
||||
}
|
||||
println("\nALL BLOCK VARS:")
|
||||
blockVars.forEach { (block, vars) ->
|
||||
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }
|
||||
|
@ -301,7 +301,7 @@ class TestOptimization: FunSpec({
|
||||
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)
|
||||
result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
|
||||
val allocation = result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
|
||||
|
||||
// assignment is now split into:
|
||||
// bb = not bb
|
||||
@ -326,7 +326,7 @@ class TestOptimization: FunSpec({
|
||||
((bbAssigns1expr.right as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww")
|
||||
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!!.name.shouldNotBeBlank()
|
||||
}
|
||||
@ -366,7 +366,7 @@ class TestOptimization: FunSpec({
|
||||
|
||||
test("asmgen correctly deals with float typecasting in augmented assignment") {
|
||||
val src="""
|
||||
%option enable_floats
|
||||
%import floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
@ -385,9 +385,7 @@ class TestOptimization: FunSpec({
|
||||
(value.left as? IdentifierReference)?.nameInSource shouldBe listOf("ff")
|
||||
value.right shouldBe instanceOf<TypecastExpression>()
|
||||
|
||||
val asm = generateAssembly(result.program)
|
||||
asm shouldNotBe null
|
||||
asm!!.name.shouldNotBeBlank()
|
||||
compileText(C64Target(), optimize=false, src, writeAssembly = true).assertSuccess()
|
||||
}
|
||||
|
||||
test("unused variable removal") {
|
||||
|
@ -12,22 +12,18 @@ import prog8.ast.expressions.AddressOf
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.statements.*
|
||||
import prog8.codegen.cpu6502.AsmGen6502
|
||||
import prog8.codegen.cpu6502.AsmGen
|
||||
import prog8.codegen.target.C64Target
|
||||
import prog8.codegen.target.c64.C64Zeropage
|
||||
import prog8.compilerinterface.CompilationOptions
|
||||
import prog8.compilerinterface.LauncherType
|
||||
import prog8.compilerinterface.OutputType
|
||||
import prog8.compilerinterface.ZeropageType
|
||||
import prog8.compilerinterface.*
|
||||
import prog8.parser.SourceCode
|
||||
import prog8tests.helpers.DummyFunctions
|
||||
import prog8tests.helpers.DummyMemsizer
|
||||
import prog8tests.helpers.DummyStringEncoder
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
import java.nio.file.Path
|
||||
|
||||
class TestAsmGenSymbols: StringSpec({
|
||||
fun createTestProgram(): Program {
|
||||
fun createTestProgram(): Pair<Program, IVariablesAndConsts> {
|
||||
/*
|
||||
main {
|
||||
|
||||
@ -72,20 +68,42 @@ class TestAsmGenSymbols: StringSpec({
|
||||
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
|
||||
|
||||
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 options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target())
|
||||
options.compTarget.machine.zeropage = C64Zeropage(options)
|
||||
val asmgen = AsmGen6502(program, errors, options)
|
||||
return asmgen
|
||||
return AsmGen(program, errors, allocation, options)
|
||||
}
|
||||
|
||||
"symbol and variable names from strings" {
|
||||
val program = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program)
|
||||
val (program, variables) = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program, variables)
|
||||
asmgen.asmSymbolName("name") shouldBe "name"
|
||||
asmgen.asmSymbolName("name") shouldBe "name"
|
||||
asmgen.asmSymbolName("<name>") shouldBe "prog8_name"
|
||||
@ -97,8 +115,8 @@ class TestAsmGenSymbols: StringSpec({
|
||||
}
|
||||
|
||||
"symbol and variable names from variable identifiers" {
|
||||
val program = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program)
|
||||
val (program, variables) = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program, variables)
|
||||
val sub = program.entrypoint
|
||||
|
||||
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" {
|
||||
val program = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program)
|
||||
val (program, variables) = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program, variables)
|
||||
val sub = program.entrypoint
|
||||
|
||||
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_W2 = 1
|
||||
*/
|
||||
val program = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program)
|
||||
val (program, variables) = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program, variables)
|
||||
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_REG") shouldBe "P8ZP_SCRATCH_REG"
|
||||
asmgen.asmSymbolName("prog8_lib.P8ZP_SCRATCH_W2") shouldBe "P8ZP_SCRATCH_W2"
|
||||
asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_REG")) shouldBe "P8ZP_SCRATCH_REG"
|
||||
|
@ -11,7 +11,7 @@ import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.VarDecl
|
||||
import prog8.compilerinterface.*
|
||||
|
||||
internal val DummyFunctions = object : IBuiltinFunctions {
|
||||
internal object DummyFunctions : IBuiltinFunctions {
|
||||
override val names: Set<String> = emptySet()
|
||||
override val purefunctionNames: Set<String> = emptySet()
|
||||
override fun constValue(
|
||||
@ -23,12 +23,12 @@ internal val DummyFunctions = object : IBuiltinFunctions {
|
||||
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(decl: VarDecl) = 0
|
||||
}
|
||||
|
||||
internal val DummyStringEncoder = object : IStringEncoding {
|
||||
internal object DummyStringEncoder : IStringEncoding {
|
||||
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
|
||||
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 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 machine: IMachineDefinition
|
||||
get() = throw NotImplementedError("dummy")
|
||||
@ -75,4 +75,4 @@ internal val DummyCompilationTarget = object : ICompilationTarget {
|
||||
override fun memorySize(decl: VarDecl): Int {
|
||||
throw NotImplementedError("dummy")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package prog8tests.helpers
|
||||
import io.kotest.assertions.withClue
|
||||
import io.kotest.matchers.shouldBe
|
||||
import prog8.ast.Program
|
||||
import prog8.codegen.cpu6502.AsmGen6502
|
||||
import prog8.codegen.cpu6502.AsmGen
|
||||
import prog8.codegen.target.C64Target
|
||||
import prog8.codegen.target.c64.C64Zeropage
|
||||
import prog8.compiler.CompilationResult
|
||||
@ -83,10 +83,11 @@ internal fun compileText(
|
||||
|
||||
internal fun generateAssembly(
|
||||
program: Program,
|
||||
allocation: IVariablesAndConsts,
|
||||
options: CompilationOptions? = null
|
||||
): IAssemblyProgram? {
|
||||
val coptions = options ?: CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, true, C64Target(), outputDir = outputDir)
|
||||
coptions.compTarget.machine.zeropage = C64Zeropage(coptions)
|
||||
val asmgen = AsmGen6502(program, ErrorReporterForTests(), coptions)
|
||||
val asmgen = AsmGen(program, ErrorReporterForTests(), allocation, coptions)
|
||||
return asmgen.compileToAssembly()
|
||||
}
|
||||
|
@ -7,21 +7,24 @@ import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Subroutine
|
||||
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 MemoryMappedSymbol(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
|
||||
data class StaticSubroutineVariable(val type: DataType, val name: String, val position: Position, val origVar: VarDecl) // TODO should get rid of origVar altogether
|
||||
data class ZeropageVariable(val type: DataType, val scopedname: List<String>, val position: Position)
|
||||
data class MemoryMappedVariable(val type: DataType, val name: String, val address: UInt, val position: Position)
|
||||
// TODO should get rid of origVar altogether in the following two:
|
||||
data class StaticBlockVariable(val type: DataType, val name: String, val initialValue: Expression?, val position: Position, val origVar: VarDecl)
|
||||
data class StaticSubroutineVariable(val type: DataType, val name: String, val position: Position, val origVar: VarDecl)
|
||||
|
||||
fun dump(memsizer: IMemSizer)
|
||||
|
||||
val zeropageVars: Set<ZeropageVariable> // also present in the Zeropage object after this allocation
|
||||
val blockVars: Map<Block, Set<StaticBlockVariable>>
|
||||
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 subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>>
|
||||
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedSymbol>>
|
||||
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedVariable>>
|
||||
}
|
@ -20,12 +20,10 @@ Blocked by an official Commander-x16 r39 release
|
||||
|
||||
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):
|
||||
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
|
||||
Ast modifications done in AsmGen that perhaps should not be necessary:
|
||||
- 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
|
||||
and pass that via a new datastructure to asmgen? So that asmgen is no longer tasked with doing the allocations.
|
||||
This could perhaps make it easer for the codegen as well to deal with sections, if any, in the future.
|
||||
--> Don't rely on vardecls at all any longer but use the new IVariablesAndConsts object passed to the AsmGen, this will solve this item.
|
||||
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
|
||||
|
||||
- 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
|
||||
@ -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?
|
||||
(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)
|
||||
- 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 ;)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user