reduce dependencies on global compilaiontarget

This commit is contained in:
Irmen de Jong 2021-02-18 23:44:26 +01:00
parent 2412f8c531
commit 9bb5b454e4
18 changed files with 55 additions and 53 deletions

View File

@ -19,7 +19,7 @@
; mode 3 = bitmap 320 x 240 x 16c (unsupported TODO not yet implemented)
; mode 4 = bitmap 320 x 240 x 256c
; mode 5 = bitmap 640 x 480 monochrome
; mode 6 = bitmap 640 x 480 x 4c (unsupported TODO being implemented)
; mode 6 = bitmap 640 x 480 x 4c
; mode 7 = bitmap 640 x 480 x 16c (unsupported due to lack of VRAM)
; mode 8 = bitmap 640 x 480 x 256c (unsupported due to lack of VRAM)

View File

@ -8,7 +8,6 @@ import prog8.ast.base.AstException
import prog8.compiler.CompilationResult
import prog8.compiler.compileProgram
import prog8.compiler.target.C64Target
import prog8.compiler.target.ICompilationTarget
import prog8.compiler.target.Cx16Target
import prog8.parser.ParsingFailedError
import java.nio.file.FileSystems
@ -117,7 +116,7 @@ private fun compileMain(args: Array<String>) {
if (compilationResult.programName.isEmpty())
println("\nCan't start emulator because no program was assembled.")
else {
ICompilationTarget.instance.machine.launchEmulator(compilationResult.programName)
compilationResult.compTarget.machine.launchEmulator(compilationResult.programName)
}
}
}

View File

@ -59,6 +59,7 @@ class CompilerException(message: String?) : Exception(message)
class CompilationResult(val success: Boolean,
val programAst: Program,
val programName: String,
val compTarget: ICompilationTarget,
val importedFiles: List<Path>)
@ -92,7 +93,7 @@ fun compileProgram(filepath: Path,
importedFiles = imported
processAst(programAst, errors, compilationOptions, ICompilationTarget.instance)
if (compilationOptions.optimize)
optimizeAst(programAst, errors, BuiltinFunctionsFacade(BuiltinFunctions))
optimizeAst(programAst, errors, BuiltinFunctionsFacade(BuiltinFunctions), ICompilationTarget.instance)
postprocessAst(programAst, errors, compilationOptions, ICompilationTarget.instance)
// printAst(programAst)
@ -103,7 +104,7 @@ fun compileProgram(filepath: Path,
System.out.flush()
System.err.flush()
println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.")
return CompilationResult(true, programAst, programName, importedFiles)
return CompilationResult(true, programAst, programName, ICompilationTarget.instance, importedFiles)
} catch (px: ParsingFailedError) {
System.err.print("\u001b[91m") // bright red
@ -128,7 +129,7 @@ fun compileProgram(filepath: Path,
}
val failedProgram = Program("failed", mutableListOf(), BuiltinFunctionsFacade(BuiltinFunctions))
return CompilationResult(false, failedProgram, programName, emptyList())
return CompilationResult(false, failedProgram, programName, ICompilationTarget.instance, emptyList())
}
private class BuiltinFunctionsFacade(functions: Map<String, FSignature>): IBuiltinFunctions {
@ -242,7 +243,7 @@ private fun processAst(programAst: Program, errors: ErrorReporter, compilerOptio
println("Processing for target ${compTarget.name}...")
programAst.checkIdentifiers(errors, compTarget)
errors.handle()
programAst.constantFold(errors)
programAst.constantFold(errors, compTarget)
errors.handle()
programAst.reorderStatements(errors)
errors.handle()
@ -255,21 +256,21 @@ private fun processAst(programAst: Program, errors: ErrorReporter, compilerOptio
errors.handle()
}
private fun optimizeAst(programAst: Program, errors: ErrorReporter, functions: IBuiltinFunctions) {
private fun optimizeAst(programAst: Program, errors: ErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget) {
// optimize the parse tree
println("Optimizing...")
while (true) {
// keep optimizing expressions and statements until no more steps remain
val optsDone1 = programAst.simplifyExpressions()
val optsDone2 = programAst.splitBinaryExpressions()
val optsDone3 = programAst.optimizeStatements(errors, functions)
programAst.constantFold(errors) // because simplified statements and expressions can result in more constants that can be folded away
val optsDone2 = programAst.splitBinaryExpressions(compTarget)
val optsDone3 = programAst.optimizeStatements(errors, functions, compTarget)
programAst.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away
errors.handle()
if (optsDone1 + optsDone2 + optsDone3 == 0)
break
}
val remover = UnusedCodeRemover(programAst, errors)
val remover = UnusedCodeRemover(programAst, errors, compTarget)
remover.visit(programAst)
remover.applyModifications()
errors.handle()

View File

@ -16,7 +16,7 @@ import prog8.compiler.target.cx16.CX16MachineDefinition
import java.nio.file.Path
internal interface ICompilationTarget: IStringEncoding {
interface ICompilationTarget: IStringEncoding {
val name: String
val machine: IMachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short>

View File

@ -4,17 +4,17 @@ import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage
internal interface IMachineFloat {
interface IMachineFloat {
fun toDouble(): Double
fun makeFloatFillAsm(): String
}
internal enum class CpuType {
enum class CpuType {
CPU6502,
CPU65c02
}
internal interface IMachineDefinition {
interface IMachineDefinition {
val FLOAT_MAX_NEGATIVE: Double
val FLOAT_MAX_POSITIVE: Double
val FLOAT_MEM_SIZE: Int

View File

@ -68,7 +68,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcMemory(fcall: IFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
if(discardResult || fcall !is FunctionCall)
throw AssemblyError("should not discard result of memory allocation at $fcall")
val scope = fcall.definingScope()
val nameRef = fcall.args[0] as IdentifierReference
val name = (nameRef.targetVarDecl(program)!!.value as StringLiteralValue).value
val size = (fcall.args[1] as NumericLiteralValue).number.toInt()
@ -85,7 +84,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
AsmAssignTarget(TargetStorageKind.STACK, program, asmgen, DataType.UWORD, null)
else
AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, null, program, asmgen)
val assign = AsmAssignment(src, target, false, fcall.position)
val assign = AsmAssignment(src, target, false, asmgen.compTarget, fcall.position)
asmgen.translateNormalAssignment(assign)
asmgen.slabs[name] = size
}
@ -647,12 +646,12 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val assignFirst = AsmAssignment(
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W2"),
targetFromExpr(first, datatype),
false, first.position
false, asmgen.compTarget, first.position
)
val assignSecond = AsmAssignment(
AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, datatype, variableAsmName = "P8ZP_SCRATCH_W1"),
targetFromExpr(second, datatype),
false, second.position
false, asmgen.compTarget, second.position
)
asmgen.translateNormalAssignment(assignFirst)
asmgen.translateNormalAssignment(assignSecond)
@ -664,12 +663,12 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val assignFirst = AsmAssignment(
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, DataType.FLOAT),
targetFromExpr(first, datatype),
false, first.position
false, asmgen.compTarget, first.position
)
val assignSecond = AsmAssignment(
AsmAssignSource(SourceStorageKind.STACK, program, asmgen, DataType.FLOAT),
targetFromExpr(second, datatype),
false, second.position
false, asmgen.compTarget, second.position
)
asmgen.translateNormalAssignment(assignFirst)
asmgen.translateNormalAssignment(assignSecond)
@ -1288,7 +1287,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
}
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, conv.dt, null, variableAsmName = varname)
val assign = AsmAssignment(src, tgt, false, value.position)
val assign = AsmAssignment(src, tgt, false, asmgen.compTarget, value.position)
asmgen.translateNormalAssignment(assign)
}
conv.reg != null -> {
@ -1304,7 +1303,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
}
}
val tgt = AsmAssignTarget.fromRegisters(conv.reg, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, value.position)
val assign = AsmAssignment(src, tgt, false, asmgen.compTarget, value.position)
asmgen.translateNormalAssignment(assign)
}
else -> throw AssemblyError("callconv")

View File

@ -318,7 +318,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
} else {
AsmAssignSource.fromAstSource(value, program, asmgen).adjustSignedUnsigned(target)
}
asmgen.translateNormalAssignment(AsmAssignment(src, target, false, Position.DUMMY))
asmgen.translateNormalAssignment(AsmAssignment(src, target, false, asmgen.compTarget, Position.DUMMY))
}
}
}

View File

@ -207,12 +207,13 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
internal class AsmAssignment(val source: AsmAssignSource,
val target: AsmAssignTarget,
val isAugmentable: Boolean,
compTarget: ICompilationTarget,
val position: Position) {
init {
if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY))
require(source.datatype != DataType.STRUCT) { "must not be placeholder datatype" }
require(ICompilationTarget.instance.memorySize(source.datatype) <= ICompilationTarget.instance.memorySize(target.datatype)) {
require(compTarget.memorySize(source.datatype) <= compTarget.memorySize(target.datatype)) {
"source storage size must be less or equal to target datatype storage size"
}
}

View File

@ -22,7 +22,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen)
val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target)
val assign = AsmAssignment(source, target, assignment.isAugmentable, assignment.position)
val assign = AsmAssignment(source, target, assignment.isAugmentable, asmgen.compTarget, assignment.position)
target.origAssign = assign
if(assign.isAugmentable)
@ -441,7 +441,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
val lsb = FunctionCall(IdentifierReference(listOf("lsb"), value.position), mutableListOf(value), value.position)
lsb.linkParents(value.parent)
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb)
val assign = AsmAssignment(src, target, false, value.position)
val assign = AsmAssignment(src, target, false, asmgen.compTarget, value.position)
translateNormalAssignment(assign)
}
@ -2109,21 +2109,21 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair) {
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
val tgt = AsmAssignTarget.fromRegisters(register, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, expr.position)
val assign = AsmAssignment(src, tgt, false, asmgen.compTarget, expr.position)
translateNormalAssignment(assign)
}
internal fun assignExpressionToVariable(expr: Expression, asmVarName: String, dt: DataType, scope: Subroutine?) {
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, scope, variableAsmName = asmVarName)
val assign = AsmAssignment(src, tgt, false, expr.position)
val assign = AsmAssignment(src, tgt, false, asmgen.compTarget, expr.position)
translateNormalAssignment(assign)
}
internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair) {
val tgt = AsmAssignTarget.fromRegisters(register, null, program, asmgen)
val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName)
val assign = AsmAssignment(src, tgt, false, Position.DUMMY)
val assign = AsmAssignment(src, tgt, false, asmgen.compTarget, Position.DUMMY)
translateNormalAssignment(assign)
}
}

View File

@ -245,19 +245,19 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
when(target.datatype) {
in ByteDatatypes -> {
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.A, null, program, asmgen)
val assign = AsmAssignment(target.origAssign.source, tgt, false, value.position)
val assign = AsmAssignment(target.origAssign.source, tgt, false, asmgen.compTarget, value.position)
assignmentAsmGen.translateNormalAssignment(assign)
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A)
}
in WordDatatypes -> {
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
val assign = AsmAssignment(target.origAssign.source, tgt, false, value.position)
val assign = AsmAssignment(target.origAssign.source, tgt, false, asmgen.compTarget, value.position)
assignmentAsmGen.translateNormalAssignment(assign)
assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY)
}
DataType.FLOAT -> {
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.FAC1, null, program, asmgen)
val assign = AsmAssignment(target.origAssign.source, tgt, false, value.position)
val assign = AsmAssignment(target.origAssign.source, tgt, false, asmgen.compTarget, value.position)
assignmentAsmGen.translateNormalAssignment(assign)
assignmentAsmGen.assignFAC1float(target)
}

View File

@ -10,7 +10,7 @@ import prog8.ast.walk.IAstModification
import prog8.compiler.target.ICompilationTarget
internal class BinExprSplitter(private val program: Program) : AstWalker() {
internal class BinExprSplitter(private val program: Program, private val compTarget: ICompilationTarget) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
// override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
@ -80,7 +80,7 @@ X = BinExpr X = LeftExpr
private fun isSimpleTarget(target: AssignTarget, program: Program) =
if (target.identifier!=null || target.memoryAddress!=null)
ICompilationTarget.instance.isInRegularRAM(target, program)
compTarget.isInRegularRAM(target, program)
else
false

View File

@ -13,7 +13,7 @@ import prog8.compiler.target.ICompilationTarget
import kotlin.math.pow
internal class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
internal class ConstantFoldingOptimizer(private val program: Program, private val compTarget: ICompilationTarget) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
override fun before(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> {
@ -224,7 +224,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
range.step
}
return RangeExpr(fromCast.valueOrZero(), toCast.valueOrZero(), newStep, ICompilationTarget.instance, range.position)
return RangeExpr(fromCast.valueOrZero(), toCast.valueOrZero(), newStep, compTarget, range.position)
}
// adjust the datatype of a range expression in for loops to the loop variable.

View File

@ -39,7 +39,7 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat
// Replace all constant identifiers with their actual value,
// and the array var initializer values and sizes.
// This is needed because further constant optimizations depend on those.
internal class ConstantIdentifierReplacer(private val program: Program, private val errors: ErrorReporter) : AstWalker() {
internal class ConstantIdentifierReplacer(private val program: Program, private val errors: ErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
override fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> {
@ -192,7 +192,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
if(rangeExpr==null && litval!=null) {
// arraysize initializer is a single int, and we know the size.
val fillvalue = litval.number.toDouble()
if (fillvalue < ICompilationTarget.instance.machine.FLOAT_MAX_NEGATIVE || fillvalue > ICompilationTarget.instance.machine.FLOAT_MAX_POSITIVE)
if (fillvalue < compTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > compTarget.machine.FLOAT_MAX_POSITIVE)
errors.err("float value overflow", litval.position)
else {
// create the array itself, filled with the fillvalue.

View File

@ -3,15 +3,16 @@ package prog8.optimizer
import prog8.ast.IBuiltinFunctions
import prog8.ast.Program
import prog8.compiler.ErrorReporter
import prog8.compiler.target.ICompilationTarget
internal fun Program.constantFold(errors: ErrorReporter) {
internal fun Program.constantFold(errors: ErrorReporter, compTarget: ICompilationTarget) {
val valuetypefixer = VarConstantValueTypeAdjuster(this, errors)
valuetypefixer.visit(this)
if(errors.isEmpty()) {
valuetypefixer.applyModifications()
val replacer = ConstantIdentifierReplacer(this, errors)
val replacer = ConstantIdentifierReplacer(this, errors, compTarget)
replacer.visit(this)
if (errors.isEmpty()) {
replacer.applyModifications()
@ -20,7 +21,7 @@ internal fun Program.constantFold(errors: ErrorReporter) {
if(errors.isEmpty()) {
valuetypefixer.applyModifications()
val optimizer = ConstantFoldingOptimizer(this)
val optimizer = ConstantFoldingOptimizer(this, compTarget)
optimizer.visit(this)
while (errors.isEmpty() && optimizer.applyModifications() > 0) {
optimizer.visit(this)
@ -39,8 +40,8 @@ internal fun Program.constantFold(errors: ErrorReporter) {
}
internal fun Program.optimizeStatements(errors: ErrorReporter, functions: IBuiltinFunctions): Int {
val optimizer = StatementOptimizer(this, errors, functions)
internal fun Program.optimizeStatements(errors: ErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget): Int {
val optimizer = StatementOptimizer(this, errors, functions, compTarget)
optimizer.visit(this)
val optimizationCount = optimizer.applyModifications()
@ -55,8 +56,8 @@ internal fun Program.simplifyExpressions() : Int {
return opti.applyModifications()
}
internal fun Program.splitBinaryExpressions() : Int {
val opti = BinExprSplitter(this)
internal fun Program.splitBinaryExpressions(compTarget: ICompilationTarget) : Int {
val opti = BinExprSplitter(this, compTarget)
opti.visit(this)
return opti.applyModifications()
}

View File

@ -17,7 +17,8 @@ import kotlin.math.floor
internal class StatementOptimizer(private val program: Program,
private val errors: ErrorReporter,
private val functions: IBuiltinFunctions
private val functions: IBuiltinFunctions,
private val compTarget: ICompilationTarget
) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
@ -96,7 +97,7 @@ internal class StatementOptimizer(private val program: Program,
if(string!=null) {
val pos = functionCallStatement.position
if (string.value.length == 1) {
val firstCharEncoded = ICompilationTarget.instance.encodeString(string.value, string.altEncoding)[0]
val firstCharEncoded = compTarget.encodeString(string.value, string.altEncoding)[0]
val chrout = FunctionCallStatement(
IdentifierReference(listOf("txt", "chrout"), pos),
mutableListOf(NumericLiteralValue(DataType.UBYTE, firstCharEncoded.toInt(), pos)),
@ -104,7 +105,7 @@ internal class StatementOptimizer(private val program: Program,
)
return listOf(IAstModification.ReplaceNode(functionCallStatement, chrout, parent))
} else if (string.value.length == 2) {
val firstTwoCharsEncoded = ICompilationTarget.instance.encodeString(string.value.take(2), string.altEncoding)
val firstTwoCharsEncoded = compTarget.encodeString(string.value.take(2), string.altEncoding)
val chrout1 = FunctionCallStatement(
IdentifierReference(listOf("txt", "chrout"), pos),
mutableListOf(NumericLiteralValue(DataType.UBYTE, firstTwoCharsEncoded[0].toInt(), pos)),
@ -212,7 +213,7 @@ internal class StatementOptimizer(private val program: Program,
val size = sv.value.length
if(size==1) {
// loop over string of length 1 -> just assign the single character
val character = ICompilationTarget.instance.encodeString(sv.value, sv.altEncoding)[0]
val character = compTarget.encodeString(sv.value, sv.altEncoding)[0]
val byte = NumericLiteralValue(DataType.UBYTE, character, iterable.position)
val scope = AnonymousScope(mutableListOf(), forLoop.position)
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, forLoop.position), byte, forLoop.position))

View File

@ -14,7 +14,7 @@ import prog8.ast.walk.IAstModification
import prog8.compiler.target.ICompilationTarget
internal class UnusedCodeRemover(private val program: Program, private val errors: ErrorReporter): AstWalker() {
internal class UnusedCodeRemover(private val program: Program, private val errors: ErrorReporter, private val compTarget: ICompilationTarget): AstWalker() {
override fun before(program: Program, parent: Node): Iterable<IAstModification> {
val callgraph = CallGraph(program)
@ -96,7 +96,7 @@ internal class UnusedCodeRemover(private val program: Program, private val error
val assign1 = stmtPairs[0] as? Assignment
val assign2 = stmtPairs[1] as? Assignment
if (assign1 != null && assign2 != null && !assign2.isAugmentable) {
if (assign1.target.isSameAs(assign2.target, program) && ICompilationTarget.instance.isInRegularRAM(assign1.target, program)) {
if (assign1.target.isSameAs(assign2.target, program) && compTarget.isInRegularRAM(assign1.target, program)) {
if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(*(assign2.target.identifier!!.nameInSource.toTypedArray())))
// only remove the second assignment if its value is a simple expression!
when(assign2.value) {

Binary file not shown.

Binary file not shown.