more cleanups to the allocator

This commit is contained in:
Irmen de Jong 2022-02-08 21:38:27 +01:00
parent 8c2e6971fc
commit 1307bdc612
13 changed files with 270 additions and 265 deletions

View File

@ -25,20 +25,18 @@ class AsmGen(internal val program: Program,
internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100) internal val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
internal val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640) internal val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640)
internal val zeropage = options.compTarget.machine.zeropage
internal val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
internal val loopEndLabels = ArrayDeque<String>() internal val loopEndLabels = ArrayDeque<String>()
private val memorySlabs = mutableMapOf<String, Pair<UInt, UInt>>() private val zeropage = options.compTarget.machine.zeropage
private val allocator = VariableAllocator(variables, errors)
private val assemblyLines = mutableListOf<String>() private val assemblyLines = mutableListOf<String>()
private val breakpointLabels = mutableListOf<String>() private val breakpointLabels = mutableListOf<String>()
private val forloopsAsmGen = ForLoopsAsmGen(program, this) private val forloopsAsmGen = ForLoopsAsmGen(program, this, zeropage)
private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this) private val postincrdecrAsmGen = PostIncrDecrAsmGen(program, this)
private val functioncallAsmGen = FunctionCallAsmGen(program, this) private val functioncallAsmGen = FunctionCallAsmGen(program, this)
private val expressionsAsmGen = ExpressionsAsmGen(program, this, functioncallAsmGen) private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
private val assignmentAsmGen = AssignmentAsmGen(program, this) private val programGen = ProgramGen(program, variables, options, errors, functioncallAsmGen, this, allocator, zeropage)
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen) private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator)
private val programGen = ProgramGen(program, variables, options, errors, functioncallAsmGen, this) private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen, allocator)
internal val allMemorySlabs: Map<String, Pair<UInt, UInt>> = memorySlabs
override fun compileToAssembly(): IAssemblyProgram? { override fun compileToAssembly(): IAssemblyProgram? {
assemblyLines.clear() assemblyLines.clear()
@ -66,11 +64,6 @@ class AsmGen(internal val program: Program,
} }
} }
internal fun getMemorySlab(name: String) = memorySlabs[name]
internal fun allocateMemorySlab(name: String, size: UInt, align: UInt) {
memorySlabs[name] = Pair(size, align)
}
internal fun isTargetCpu(cpu: CpuType) = options.compTarget.machine.cpu == cpu internal fun isTargetCpu(cpu: CpuType) = options.compTarget.machine.cpu == cpu
internal fun haveFPWRcall() = options.compTarget.name=="cx16" internal fun haveFPWRcall() = options.compTarget.name=="cx16"
@ -101,16 +94,6 @@ class AsmGen(internal val program: Program,
} else assemblyLines.add(fragment) } else assemblyLines.add(fragment)
} }
internal fun getFloatAsmConst(number: Double): String {
val asmName = globalFloatConsts[number]
if(asmName!=null)
return asmName
val newName = "prog8_float_const_${globalFloatConsts.size}"
globalFloatConsts[number] = newName
return newName
}
fun asmSymbolName(regs: RegisterOrPair): String = fun asmSymbolName(regs: RegisterOrPair): String =
if (regs in Cx16VirtualRegisters) if (regs in Cx16VirtualRegisters)
"cx16." + regs.toString().lowercase() "cx16." + regs.toString().lowercase()
@ -247,11 +230,11 @@ class AsmGen(internal val program: Program,
} }
CpuRegister.X -> { CpuRegister.X -> {
out(" stx prog8_regsaveX") out(" stx prog8_regsaveX")
scope.asmGenInfo.usedRegsaveX = true allocator.subroutineExtra(scope).usedRegsaveX = true
} }
CpuRegister.Y -> { CpuRegister.Y -> {
out(" sty prog8_regsaveY") out(" sty prog8_regsaveY")
scope.asmGenInfo.usedRegsaveY = true allocator.subroutineExtra(scope).usedRegsaveY = true
} }
} }
} }
@ -756,7 +739,7 @@ $repeatLabel lda $counterVar
} }
private fun createRepeatCounterVar(dt: DataType, preferZeropage: Boolean, stmt: RepeatLoop): String { private fun createRepeatCounterVar(dt: DataType, preferZeropage: Boolean, stmt: RepeatLoop): String {
val asmInfo = stmt.definingSubroutine!!.asmGenInfo val asmInfo = allocator.subroutineExtra(stmt.definingSubroutine!!)
var parent = stmt.parent var parent = stmt.parent
while(parent !is ParentSentinel) { while(parent !is ParentSentinel) {
if(parent is RepeatLoop) if(parent is RepeatLoop)
@ -1443,7 +1426,7 @@ $repeatLabel lda $counterVar
} }
else if(left is IdentifierReference && rightConstVal!=null) { else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmVariableName(left) val leftName = asmVariableName(left)
val rightName = getFloatAsmConst(rightConstVal.number) val rightName = allocator.getFloatAsmConst(rightConstVal.number)
out(""" out("""
lda #<$rightName lda #<$rightName
ldy #>$rightName ldy #>$rightName
@ -1468,7 +1451,7 @@ $repeatLabel lda $counterVar
beq $jumpIfFalseLabel""") beq $jumpIfFalseLabel""")
} else { } else {
val subroutine = left.definingSubroutine!! val subroutine = left.definingSubroutine!!
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true allocator.subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
assignExpressionToRegister(left, RegisterOrPair.FAC1) assignExpressionToRegister(left, RegisterOrPair.FAC1)
out(""" out("""
@ -1488,7 +1471,7 @@ $repeatLabel lda $counterVar
} }
else if(left is IdentifierReference && rightConstVal!=null) { else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmVariableName(left) val leftName = asmVariableName(left)
val rightName = getFloatAsmConst(rightConstVal.number) val rightName = allocator.getFloatAsmConst(rightConstVal.number)
out(""" out("""
lda #<$rightName lda #<$rightName
ldy #>$rightName ldy #>$rightName
@ -1513,7 +1496,7 @@ $repeatLabel lda $counterVar
beq $jumpIfFalseLabel""") beq $jumpIfFalseLabel""")
} else { } else {
val subroutine = left.definingSubroutine!! val subroutine = left.definingSubroutine!!
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true allocator.subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
assignExpressionToRegister(left, RegisterOrPair.FAC1) assignExpressionToRegister(left, RegisterOrPair.FAC1)
out(""" out("""
@ -1530,7 +1513,7 @@ $repeatLabel lda $counterVar
} }
else if(left is IdentifierReference && rightConstVal!=null) { else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmVariableName(left) val leftName = asmVariableName(left)
val rightName = getFloatAsmConst(rightConstVal.number) val rightName = allocator.getFloatAsmConst(rightConstVal.number)
out(""" out("""
lda #<$leftName lda #<$leftName
ldy #>$leftName ldy #>$leftName
@ -1558,7 +1541,7 @@ $repeatLabel lda $counterVar
beq $jumpIfFalseLabel""") beq $jumpIfFalseLabel""")
} else { } else {
val subroutine = left.definingSubroutine!! val subroutine = left.definingSubroutine!!
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true allocator.subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
assignExpressionToRegister(left, RegisterOrPair.FAC1) assignExpressionToRegister(left, RegisterOrPair.FAC1)
out(""" out("""
@ -1575,7 +1558,7 @@ $repeatLabel lda $counterVar
} }
else if(left is IdentifierReference && rightConstVal!=null) { else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmVariableName(left) val leftName = asmVariableName(left)
val rightName = getFloatAsmConst(rightConstVal.number) val rightName = allocator.getFloatAsmConst(rightConstVal.number)
out(""" out("""
lda #<$leftName lda #<$leftName
ldy #>$leftName ldy #>$leftName
@ -1603,7 +1586,7 @@ $repeatLabel lda $counterVar
beq $jumpIfFalseLabel""") beq $jumpIfFalseLabel""")
} else { } else {
val subroutine = left.definingSubroutine!! val subroutine = left.definingSubroutine!!
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true allocator.subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
assignExpressionToRegister(left, RegisterOrPair.FAC1) assignExpressionToRegister(left, RegisterOrPair.FAC1)
out(""" out("""
@ -2518,7 +2501,7 @@ $repeatLabel lda $counterVar
} }
else if(left is IdentifierReference && rightConstVal!=null) { else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmVariableName(left) val leftName = asmVariableName(left)
val rightName = getFloatAsmConst(rightConstVal.number) val rightName = allocator.getFloatAsmConst(rightConstVal.number)
out(""" out("""
lda #<$leftName lda #<$leftName
ldy #>$leftName ldy #>$leftName
@ -2543,7 +2526,7 @@ $repeatLabel lda $counterVar
beq $jumpIfFalseLabel""") beq $jumpIfFalseLabel""")
} else { } else {
val subroutine = left.definingSubroutine!! val subroutine = left.definingSubroutine!!
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true allocator.subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
assignExpressionToRegister(left, RegisterOrPair.FAC1) assignExpressionToRegister(left, RegisterOrPair.FAC1)
out(""" out("""
@ -2603,7 +2586,7 @@ $repeatLabel lda $counterVar
} }
else if(left is IdentifierReference && rightConstVal!=null) { else if(left is IdentifierReference && rightConstVal!=null) {
val leftName = asmVariableName(left) val leftName = asmVariableName(left)
val rightName = getFloatAsmConst(rightConstVal.number) val rightName = allocator.getFloatAsmConst(rightConstVal.number)
out(""" out("""
lda #<$leftName lda #<$leftName
ldy #>$leftName ldy #>$leftName
@ -2628,7 +2611,7 @@ $repeatLabel lda $counterVar
bne $jumpIfFalseLabel""") bne $jumpIfFalseLabel""")
} else { } else {
val subroutine = left.definingSubroutine!! val subroutine = left.definingSubroutine!!
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true allocator.subroutineExtra(subroutine).usedFloatEvalResultVar1 = true
assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine) assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
assignExpressionToRegister(left, RegisterOrPair.FAC1) assignExpressionToRegister(left, RegisterOrPair.FAC1)
out(""" out("""

View File

@ -17,7 +17,10 @@ import prog8.compilerinterface.CpuType
import prog8.compilerinterface.FSignature import prog8.compilerinterface.FSignature
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) { internal class BuiltinFunctionsAsmGen(private val program: Program,
private val asmgen: AsmGen,
private val assignAsmGen: AssignmentAsmGen,
private val allocations: VariableAllocator) {
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)
@ -454,7 +457,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val size = (fcall.args[1] as NumericLiteralValue).number.toUInt() val size = (fcall.args[1] as NumericLiteralValue).number.toUInt()
val align = (fcall.args[2] as NumericLiteralValue).number.toUInt() val align = (fcall.args[2] as NumericLiteralValue).number.toUInt()
val existing = asmgen.getMemorySlab(name) val existing = allocations.getMemorySlab(name)
if(existing!=null && (existing.first!=size || existing.second!=align)) if(existing!=null && (existing.first!=size || existing.second!=align))
throw AssemblyError("memory slab '$name' already exists with a different size or alignment at ${fcall.position}") throw AssemblyError("memory slab '$name' already exists with a different size or alignment at ${fcall.position}")
@ -468,7 +471,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, null, program, asmgen) AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, null, program, asmgen)
val assign = AsmAssignment(src, target, false, program.memsizer, fcall.position) val assign = AsmAssignment(src, target, false, program.memsizer, fcall.position)
asmgen.translateNormalAssignment(assign) asmgen.translateNormalAssignment(assign)
asmgen.allocateMemorySlab(name, size, align) allocations.allocateMemorySlab(name, size, align)
} }
private fun funcSqrt16(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { private fun funcSqrt16(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) {
@ -1715,7 +1718,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
if(scope==null) if(scope==null)
throw AssemblyError("cannot use float arguments outside of a subroutine scope") throw AssemblyError("cannot use float arguments outside of a subroutine scope")
scope.asmGenInfo.usedFloatEvalResultVar2 = true allocations.subroutineExtra(scope).usedFloatEvalResultVar2 = true
val variable = IdentifierReference(listOf(subroutineFloatEvalResultVar2), value.position) val variable = IdentifierReference(listOf(subroutineFloatEvalResultVar2), value.position)
val addr = AddressOf(variable, value.position) val addr = AddressOf(variable, value.position)
addr.linkParents(value) addr.linkParents(value)

View File

@ -11,7 +11,9 @@ 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: AsmGen, private val functioncallAsmGen: FunctionCallAsmGen) { internal class ExpressionsAsmGen(private val program: Program,
private val asmgen: AsmGen,
private val allocator: VariableAllocator) {
@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) {
@ -223,7 +225,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
dex dex
""") """)
DataType.FLOAT -> { DataType.FLOAT -> {
val floatConst = asmgen.getFloatAsmConst(expr.number) val floatConst = allocator.getFloatAsmConst(expr.number)
asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float") asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float")
} }
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")

View File

@ -10,9 +10,10 @@ import prog8.ast.expressions.RangeExpression
import prog8.ast.statements.ForLoop import prog8.ast.statements.ForLoop
import prog8.ast.toHex import prog8.ast.toHex
import prog8.compilerinterface.AssemblyError import prog8.compilerinterface.AssemblyError
import prog8.compilerinterface.Zeropage
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) { internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen, private val zeropage: Zeropage) {
internal fun translate(stmt: ForLoop) { internal fun translate(stmt: ForLoop) {
val iterableDt = stmt.iterable.inferType(program) val iterableDt = stmt.iterable.inferType(program)
@ -291,7 +292,7 @@ $loopLabel sty $indexVar
} }
if(length>=16) { if(length>=16) {
// allocate index var on ZP if possible // allocate index var on ZP if possible
val result = asmgen.zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, null, stmt.position, asmgen.errors) val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, null, stmt.position, asmgen.errors)
result.fold( result.fold(
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
failure = { asmgen.out("$indexVar .byte 0") } failure = { asmgen.out("$indexVar .byte 0") }
@ -332,7 +333,7 @@ $loopLabel sty $indexVar
} }
if(length>=16) { if(length>=16) {
// allocate index var on ZP if possible // allocate index var on ZP if possible
val result = asmgen.zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, null, stmt.position, asmgen.errors) val result = zeropage.allocate(listOf(indexVar), DataType.UBYTE, null, null, stmt.position, asmgen.errors)
result.fold( result.fold(
success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") }, success = { (address,_)-> asmgen.out("""$indexVar = $address ; auto zp UBYTE""") },
failure = { asmgen.out("$indexVar .byte 0") } failure = { asmgen.out("$indexVar .byte 0") }

View File

@ -2,7 +2,6 @@ package prog8.codegen.cpu6502
import com.github.michaelbull.result.fold import com.github.michaelbull.result.fold
import prog8.ast.IFunctionCall import prog8.ast.IFunctionCall
import prog8.ast.IStatementContainer
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.antlr.escape import prog8.ast.antlr.escape
import prog8.ast.base.* import prog8.ast.base.*
@ -23,11 +22,11 @@ internal class ProgramGen(
val options: CompilationOptions, val options: CompilationOptions,
val errors: IErrorReporter, val errors: IErrorReporter,
private val functioncallAsmGen: FunctionCallAsmGen, private val functioncallAsmGen: FunctionCallAsmGen,
private val asmgen: AsmGen private val asmgen: AsmGen,
private val allocator: VariableAllocator,
private val zeropage: Zeropage
) { ) {
private val compTarget = options.compTarget private val compTarget = options.compTarget
private val removals = mutableListOf<Pair<Statement, IStatementContainer>>()
private val allocation = VariableAllocation(variables, errors)
private val callGraph = CallGraph(program) private val callGraph = CallGraph(program)
private val blockVariableInitializers = program.allBlocks.associateWith { it.statements.filterIsInstance<Assignment>() } private val blockVariableInitializers = program.allBlocks.associateWith { it.statements.filterIsInstance<Assignment>() }
@ -40,15 +39,9 @@ internal class ProgramGen(
if(allBlocks.first().name != "main") if(allBlocks.first().name != "main")
throw AssemblyError("first block should be 'main'") throw AssemblyError("first block should be 'main'")
allocation.allocateAllZeropageVariables(options) allocator.allocateZeropageVariables(options)
if(errors.noErrors()) { if(errors.noErrors()) {
program.allBlocks.forEach { block2asm(it) } program.allBlocks.forEach { block2asm(it) }
for(removal in removals.toList()) {
removal.second.remove(removal.first)
removals.remove(removal)
}
memorySlabs() memorySlabs()
footer() footer()
} }
@ -74,7 +67,7 @@ internal class ProgramGen(
compTarget.machine.BASIC_LOAD_ADDRESS else compTarget.machine.RAW_LOAD_ADDRESS compTarget.machine.BASIC_LOAD_ADDRESS else compTarget.machine.RAW_LOAD_ADDRESS
// the global prog8 variables needed // the global prog8 variables needed
val zp = compTarget.machine.zeropage val zp = zeropage
asmgen.out("P8ZP_SCRATCH_B1 = ${zp.SCRATCH_B1}") asmgen.out("P8ZP_SCRATCH_B1 = ${zp.SCRATCH_B1}")
asmgen.out("P8ZP_SCRATCH_REG = ${zp.SCRATCH_REG}") asmgen.out("P8ZP_SCRATCH_REG = ${zp.SCRATCH_REG}")
asmgen.out("P8ZP_SCRATCH_W1 = ${zp.SCRATCH_W1} ; word") asmgen.out("P8ZP_SCRATCH_W1 = ${zp.SCRATCH_W1} ; word")
@ -134,7 +127,7 @@ internal class ProgramGen(
private fun memorySlabs() { private fun memorySlabs() {
asmgen.out("; memory slabs") asmgen.out("; memory slabs")
asmgen.out("prog8_slabs\t.block") asmgen.out("prog8_slabs\t.block")
for((name, info) in asmgen.allMemorySlabs) { for((name, info) in allocator.memorySlabs) {
if(info.second>1u) if(info.second>1u)
asmgen.out("\t.align ${info.second.toHex()}") asmgen.out("\t.align ${info.second.toHex()}")
asmgen.out("$name\t.fill ${info.first}") asmgen.out("$name\t.fill ${info.first}")
@ -145,20 +138,17 @@ internal class ProgramGen(
private fun footer() { private fun footer() {
// the global list of all floating point constants for the whole program // the global list of all floating point constants for the whole program
asmgen.out("; global float constants") asmgen.out("; global float constants")
for (flt in asmgen.globalFloatConsts) { for (flt in allocator.globalFloatConsts) {
val floatFill = compTarget.machine.getFloat(flt.key).makeFloatFillAsm() val floatFill = compTarget.machine.getFloat(flt.key).makeFloatFillAsm()
val floatvalue = flt.key val floatvalue = flt.key
asmgen.out("${flt.value}\t.byte $floatFill ; float $floatvalue") asmgen.out("${flt.value}\t.byte $floatFill ; float $floatvalue")
} }
// program end
asmgen.out("prog8_program_end\t; end of program label for progend()") asmgen.out("prog8_program_end\t; end of program label for progend()")
} }
private fun block2asm(block: Block) { private fun block2asm(block: Block) {
// no longer output the initialization assignments as regular statements in the block,
// they will be part of the prog8_init_vars init routine generated below.
val initializers = blockVariableInitializers.getValue(block)
val statements = block.statements.filterNot { it in initializers }
asmgen.out("\n\n; ---- block: '${block.name}' ----") asmgen.out("\n\n; ---- block: '${block.name}' ----")
if(block.address!=null) if(block.address!=null)
asmgen.out("* = ${block.address!!.toHex()}") asmgen.out("* = ${block.address!!.toHex()}")
@ -172,18 +162,25 @@ internal class ProgramGen(
asmgen.out("${block.name}\t" + (if("force_output" in block.options()) ".block\n" else ".proc\n")) asmgen.out("${block.name}\t" + (if("force_output" in block.options()) ".block\n" else ".proc\n"))
asmgen.outputSourceLine(block) asmgen.outputSourceLine(block)
zeropagevars2asm(statements, block)
memdefs2asm(statements, block)
vardecls2asm(statements, block)
statements.asSequence().filterIsInstance<VarDecl>().forEach { val vardecls = block.statements.filterIsInstance<VarDecl>()
zeropagevars2asm(vardecls, block)
memdefs2asmVars(vardecls, block)
memdefs2asmAsmsubs(block.statements.filterIsInstance<Subroutine>(), block)
vardecls2asm(vardecls, block)
vardecls.forEach {
if(it.type== VarDeclType.VAR && it.datatype in NumericDatatypes) if(it.type== VarDeclType.VAR && it.datatype in NumericDatatypes)
it.value=null // make sure every var has no init value any longer (could be set due to 'noreinit' option) because initialization is done via explicit assignment it.value=null // make sure every var has no init value any longer (could be set due to 'noreinit' option) because initialization is done via explicit assignment
} }
asmgen.out("\n; subroutines in this block") asmgen.out("\n; subroutines in this block")
// first translate regular statements, and then put the subroutines at the end. // First translate regular statements, and then put the subroutines at the end.
// (regular statements = everything except the initialization assignments;
// these will be part of the prog8_init_vars init routine generated below)
val initializers = blockVariableInitializers.getValue(block)
val statements = block.statements.filterNot { it in initializers }
val (subroutine, stmts) = statements.partition { it is Subroutine } val (subroutine, stmts) = statements.partition { it is Subroutine }
stmts.forEach { asmgen.translate(it) } stmts.forEach { asmgen.translate(it) }
subroutine.forEach { asmgen.translate(it) } subroutine.forEach { asmgen.translate(it) }
@ -228,8 +225,10 @@ internal class ProgramGen(
} else { } else {
// regular subroutine // regular subroutine
asmgen.out("${sub.name}\t.proc") asmgen.out("${sub.name}\t.proc")
zeropagevars2asm(sub.statements, null) val vardecls = sub.statements.filterIsInstance<VarDecl>()
memdefs2asm(sub.statements, null) zeropagevars2asm(vardecls, null)
memdefs2asmVars(vardecls, null)
memdefs2asmAsmsubs(sub.statements.filterIsInstance<Subroutine>(), null)
// the main.start subroutine is the program's entrypoint and should perform some initialization logic // the main.start subroutine is the program's entrypoint and should perform some initialization logic
if(sub.name=="start" && sub.definingBlock.name=="main") if(sub.name=="start" && sub.definingBlock.name=="main")
@ -259,15 +258,9 @@ internal class ProgramGen(
sub.statements.forEach { asmgen.translate(it) } sub.statements.forEach { asmgen.translate(it) }
} }
for(removal in removals.toList()) {
if(removal.second==sub) {
removal.second.remove(removal.first)
removals.remove(removal)
}
}
asmgen.out("; variables") asmgen.out("; variables")
for((dt, name, addr) in sub.asmGenInfo.extraVars) { val asmGenInfo = allocator.subroutineExtra(sub)
for((dt, name, addr) in asmGenInfo.extraVars) {
if(addr!=null) if(addr!=null)
asmgen.out("$name = $addr") asmgen.out("$name = $addr")
else when(dt) { else when(dt) {
@ -276,17 +269,17 @@ internal class ProgramGen(
else -> throw AssemblyError("weird dt") else -> throw AssemblyError("weird dt")
} }
} }
if(sub.asmGenInfo.usedRegsaveA) // will probably never occur if(asmGenInfo.usedRegsaveA) // will probably never occur
asmgen.out("prog8_regsaveA .byte 0") asmgen.out("prog8_regsaveA .byte 0")
if(sub.asmGenInfo.usedRegsaveX) if(asmGenInfo.usedRegsaveX)
asmgen.out("prog8_regsaveX .byte 0") asmgen.out("prog8_regsaveX .byte 0")
if(sub.asmGenInfo.usedRegsaveY) if(asmGenInfo.usedRegsaveY)
asmgen.out("prog8_regsaveY .byte 0") asmgen.out("prog8_regsaveY .byte 0")
if(sub.asmGenInfo.usedFloatEvalResultVar1) if(asmGenInfo.usedFloatEvalResultVar1)
asmgen.out("$subroutineFloatEvalResultVar1 .byte 0,0,0,0,0") asmgen.out("$subroutineFloatEvalResultVar1 .byte 0,0,0,0,0")
if(sub.asmGenInfo.usedFloatEvalResultVar2) if(asmGenInfo.usedFloatEvalResultVar2)
asmgen.out("$subroutineFloatEvalResultVar2 .byte 0,0,0,0,0") asmgen.out("$subroutineFloatEvalResultVar2 .byte 0,0,0,0,0")
vardecls2asm(sub.statements, null) vardecls2asm(vardecls, null)
asmgen.out(" .pend\n") asmgen.out(" .pend\n")
} }
} }
@ -301,9 +294,10 @@ internal class ProgramGen(
} }
} }
val zp = zeropage
// string and array variables in zeropage that have initializer value, should be initialized // string and array variables in zeropage that have initializer value, should be initialized
val stringVarsWithInitInZp = asmgen.zeropage.variables.filter { it.value.dt==DataType.STR && it.value.initialStringValue!=null } val stringVarsWithInitInZp = zp.variables.filter { it.value.dt==DataType.STR && it.value.initialStringValue!=null }
val arrayVarsWithInitInZp = asmgen.zeropage.variables.filter { it.value.dt in ArrayDatatypes && it.value.initialArrayValue!=null } val arrayVarsWithInitInZp = zp.variables.filter { it.value.dt in ArrayDatatypes && it.value.initialArrayValue!=null }
if(stringVarsWithInitInZp.isNotEmpty() || arrayVarsWithInitInZp.isNotEmpty()) { if(stringVarsWithInitInZp.isNotEmpty() || arrayVarsWithInitInZp.isNotEmpty()) {
asmgen.out("; zp str and array initializations") asmgen.out("; zp str and array initializations")
stringVarsWithInitInZp.forEach { stringVarsWithInitInZp.forEach {
@ -355,21 +349,23 @@ internal class ProgramGen(
clc""") clc""")
} }
private fun zeropagevars2asm(statements: List<Statement>, inBlock: Block?) { private fun zeropagevars2asm(vardecls: List<VarDecl>, inBlock: Block?) {
val zp = zeropage
asmgen.out("; vars allocated on zeropage") asmgen.out("; vars allocated on zeropage")
val variables = statements.asSequence().filterIsInstance<VarDecl>().filter { it.type==VarDeclType.VAR } val variables = vardecls.filter { it.type==VarDeclType.VAR }
val blockname = inBlock?.name val blockname = inBlock?.name
for(variable in variables) { for(variable in variables) {
if(blockname=="prog8_lib" && variable.name.startsWith("P8ZP_SCRATCH_")) if(blockname=="prog8_lib" && variable.name.startsWith("P8ZP_SCRATCH_"))
continue // the "hooks" to the temp vars are not generated as new variables continue // the "hooks" to the temp vars are not generated as new variables
val scopedName = variable.scopedName val scopedName = variable.scopedName
val zpAlloc = asmgen.zeropage.variables[scopedName] val zpAlloc = zp.variables[scopedName]
if (zpAlloc == null) { if (zpAlloc == null) {
// TODO NO LONGER ALLOCATE HERE, IT'S ALL BEEN DONE IN THE VARIABLEALLOCATOR ALREADY
// This var is not on the ZP yet. Attempt to move it there if it's an integer type // This var is not on the ZP yet. Attempt to move it there if it's an integer type
if(variable.zeropage != ZeropageWish.NOT_IN_ZEROPAGE && if(variable.zeropage != ZeropageWish.NOT_IN_ZEROPAGE &&
variable.datatype in IntegerDatatypes variable.datatype in IntegerDatatypes
&& options.zeropage != ZeropageType.DONTUSE) { && options.zeropage != ZeropageType.DONTUSE) {
val result = asmgen.zeropage.allocate(scopedName, variable.datatype, null, null, null, errors) val result = zp.allocate(scopedName, variable.datatype, null, null, null, errors)
errors.report() errors.report()
result.fold( result.fold(
success = { (address, _) -> asmgen.out("${variable.name} = $address\t; zp ${variable.datatype}") }, success = { (address, _) -> asmgen.out("${variable.name} = $address\t; zp ${variable.datatype}") },
@ -486,37 +482,39 @@ internal class ProgramGen(
} }
} }
private fun memdefs2asm(statements: List<Statement>, inBlock: Block?) { private fun memdefs2asmVars(vardecls: List<VarDecl>, inBlock: Block?) {
val blockname = inBlock?.name val blockname = inBlock?.name
asmgen.out("\n; memdefs and kernal subroutines") asmgen.out("\n; memdefs and kernal subroutines")
val memvars = statements.asSequence().filterIsInstance<VarDecl>().filter { it.type==VarDeclType.MEMORY || it.type==VarDeclType.CONST } vardecls
for(m in memvars) { .filter { it.type==VarDeclType.MEMORY || it.type==VarDeclType.CONST }
if(blockname!="prog8_lib" || !m.name.startsWith("P8ZP_SCRATCH_")) // the "hooks" to the temp vars are not generated as new variables .forEach { mv ->
if(m.value is NumericLiteralValue) if(blockname!="prog8_lib" || !mv.name.startsWith("P8ZP_SCRATCH_")) // the "hooks" to the temp vars are not generated as new variables
asmgen.out(" ${m.name} = ${(m.value as NumericLiteralValue).number.toHex()}") if(mv.value is NumericLiteralValue)
else asmgen.out(" ${mv.name} = ${(mv.value as NumericLiteralValue).number.toHex()}")
asmgen.out(" ${m.name} = ${asmgen.asmVariableName((m.value as AddressOf).identifier)}") else
} asmgen.out(" ${mv.name} = ${asmgen.asmVariableName((mv.value as AddressOf).identifier)}")
val asmSubs = statements.asSequence().filterIsInstance<Subroutine>().filter { it.isAsmSubroutine }
for(sub in asmSubs) {
val addr = sub.asmAddress
if(addr!=null) {
if(sub.statements.isNotEmpty())
throw AssemblyError("kernal subroutine cannot have statements")
asmgen.out(" ${sub.name} = ${addr.toHex()}")
} }
}
} }
private fun vardecls2asm(statements: List<Statement>, inBlock: Block?) { private fun memdefs2asmAsmsubs(subroutines: List<Subroutine>, inBlock: Block?) {
subroutines
.filter { it.isAsmSubroutine }
.forEach { sub->
val addr = sub.asmAddress
if(addr!=null) {
if(sub.statements.isNotEmpty())
throw AssemblyError("kernal subroutine cannot have statements")
asmgen.out(" ${sub.name} = ${addr.toHex()}")
}
}
}
private fun vardecls2asm(vardecls: List<VarDecl>, inBlock: Block?) {
asmgen.out("\n; non-zeropage variables") asmgen.out("\n; non-zeropage variables")
val vars = statements.asSequence() val vars = vardecls.filter {
.filterIsInstance<VarDecl>()
.filter {
it.type==VarDeclType.VAR it.type==VarDeclType.VAR
&& it.zeropage!= ZeropageWish.REQUIRE_ZEROPAGE && it.zeropage!= ZeropageWish.REQUIRE_ZEROPAGE
&& it.scopedName !in asmgen.zeropage.variables && it.scopedName !in zeropage.variables
} }
vars.filter { it.datatype == DataType.STR && shouldActuallyOutputStringVar(it) } vars.filter { it.datatype == DataType.STR && shouldActuallyOutputStringVar(it) }

View File

@ -1,94 +0,0 @@
package prog8.codegen.cpu6502
import com.github.michaelbull.result.onFailure
import prog8.ast.base.ArrayDatatypes
import prog8.ast.base.DataType
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.ZeropageWish
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.IVariablesAndConsts
import prog8.compilerinterface.ZeropageType
internal class VariableAllocation(val vars: IVariablesAndConsts, val errors: IErrorReporter) {
fun allocateAllZeropageVariables(options: CompilationOptions) {
if(options.zeropage== ZeropageType.DONTUSE)
return
val allVariables = (
vars.blockVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName} +
vars.subroutineVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName})
.toList()
// TODO now some HACKS to get rid of some unused vars in Petaxian - otherwise the executable gets larger than $45e8
.filterNot { it.second.last() == "tbl" } // TODO HACK -- NOT REALLY NECESSARY, BUT OLD CallGraph DIDN'T CONTAIN IT EITHER
.filterNot { it.second.last() in setOf("retval_interm_w", "retval_interm_b", "retval_interm_w2", "retval_interm_b2") } // TODO HACK TO REMOVE THESE UNUSED VARS
val varsRequiringZp = allVariables
.filter { it.first.zeropage== ZeropageWish.REQUIRE_ZEROPAGE }
val varsPreferringZp = allVariables
.filter { it.first.zeropage== ZeropageWish.PREFER_ZEROPAGE }
.sortedBy { options.compTarget.memorySize(it.first.datatype) } // allocate the smallest DT first
/*
// OLD CODE CHECKING:
if(true) {
val allVariablesFoundInCallgraph = callGraphForCheck.allIdentifiers.asSequence()
.map { it.value }
.filterIsInstance<VarDecl>()
.filter { it.type == VarDeclType.VAR && it.origin != VarDeclOrigin.SUBROUTINEPARAM }
.map { it.name to it.position }
.toSet()
val newAllVars = (vars.blockVars.flatMap { it.value }
.map { it.name to it.position } + vars.subroutineVars.flatMap { it.value }
.map { it.name to it.position }).toSet()
val extraVarsInCallgraph = allVariablesFoundInCallgraph - newAllVars
val extraVarsInNew = newAllVars - allVariablesFoundInCallgraph
if (extraVarsInCallgraph.any() || extraVarsInNew.any()) {
println("EXTRA VARS IN CALLGRAPH: ${extraVarsInCallgraph.size}")
extraVarsInCallgraph.forEach {
println(" $it")
}
println("EXTRA VARS IN VARIABLESOBJ: ${extraVarsInNew.size}")
extraVarsInNew.forEach {
println(" $it")
}
//TODO("fix differences")
}
}
*/
val zeropage = options.compTarget.machine.zeropage
for ((vardecl, scopedname) in varsRequiringZp) {
val numElements: Int? = when(vardecl.datatype) {
DataType.STR -> {
(vardecl.value as StringLiteralValue).value.length
}
in ArrayDatatypes -> {
vardecl.arraysize!!.constIndex()
}
else -> null
}
val result = zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
result.onFailure { errors.err(it.message!!, vardecl.position) }
}
if(errors.noErrors()) {
varsPreferringZp.forEach { (vardecl, scopedname) ->
val arraySize: Int? = when (vardecl.datatype) {
DataType.STR -> {
(vardecl.value as StringLiteralValue).value.length
}
in ArrayDatatypes -> {
vardecl.arraysize!!.constIndex()
}
else -> null
}
zeropage.allocate(scopedname, vardecl.datatype, arraySize, vardecl.value, vardecl.position, errors)
// no need to check for error, if there is one, just allocate in normal system ram later.
}
}
}
}

View File

@ -0,0 +1,150 @@
package prog8.codegen.cpu6502
import com.github.michaelbull.result.onFailure
import prog8.ast.base.ArrayDatatypes
import prog8.ast.base.DataType
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.ast.statements.ZeropageWish
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.IVariablesAndConsts
import prog8.compilerinterface.ZeropageType
internal class VariableAllocator(val vars: IVariablesAndConsts, val errors: IErrorReporter) {
private val subroutineExtras = mutableMapOf<Subroutine, SubroutineExtraAsmInfo>()
private val memorySlabsInternal = mutableMapOf<String, Pair<UInt, UInt>>()
internal val memorySlabs: Map<String, Pair<UInt, UInt>> = memorySlabsInternal
internal val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
internal fun getMemorySlab(name: String) = memorySlabsInternal[name]
internal fun allocateMemorySlab(name: String, size: UInt, align: UInt) {
memorySlabsInternal[name] = Pair(size, align)
}
fun allocateZeropageVariables(options: CompilationOptions) {
if(options.zeropage== ZeropageType.DONTUSE)
return
val allVariables = (
vars.blockVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName} +
vars.subroutineVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName})
.toList()
// TODO now some HACKS to get rid of some unused vars in Petaxian - otherwise the executable gets larger than $45e8
.filterNot { it.second.last() == "tbl" } // TODO HACK -- NOT REALLY NECESSARY, BUT OLD CallGraph DIDN'T CONTAIN IT EITHER
.filterNot { it.second.last() in setOf("retval_interm_w", "retval_interm_b", "retval_interm_w2", "retval_interm_b2") } // TODO HACK TO REMOVE THESE UNUSED VARS
val varsRequiringZp = allVariables
.filter { it.first.zeropage == ZeropageWish.REQUIRE_ZEROPAGE }
val varsPreferringZp = allVariables
.filter { it.first.zeropage == ZeropageWish.PREFER_ZEROPAGE }
.sortedBy { options.compTarget.memorySize(it.first.datatype) } // allocate the smallest DT first
val varsDontCare = allVariables
.filter { it.first.zeropage == ZeropageWish.DONTCARE }
.sortedBy { options.compTarget.memorySize(it.first.datatype) } // allocate the smallest DT first
/*
// OLD CODE CHECKING:
if(true) {
val allVariablesFoundInCallgraph = callGraphForCheck.allIdentifiers.asSequence()
.map { it.value }
.filterIsInstance<VarDecl>()
.filter { it.type == VarDeclType.VAR && it.origin != VarDeclOrigin.SUBROUTINEPARAM }
.map { it.name to it.position }
.toSet()
val newAllVars = (vars.blockVars.flatMap { it.value }
.map { it.name to it.position } + vars.subroutineVars.flatMap { it.value }
.map { it.name to it.position }).toSet()
val extraVarsInCallgraph = allVariablesFoundInCallgraph - newAllVars
val extraVarsInNew = newAllVars - allVariablesFoundInCallgraph
if (extraVarsInCallgraph.any() || extraVarsInNew.any()) {
println("EXTRA VARS IN CALLGRAPH: ${extraVarsInCallgraph.size}")
extraVarsInCallgraph.forEach {
println(" $it")
}
println("EXTRA VARS IN VARIABLESOBJ: ${extraVarsInNew.size}")
extraVarsInNew.forEach {
println(" $it")
}
//TODO("fix differences")
}
}
*/
val zeropage = options.compTarget.machine.zeropage
fun numArrayElements(vardecl: VarDecl): Int? = when(vardecl.datatype) {
DataType.STR -> {
(vardecl.value as StringLiteralValue).value.length
}
in ArrayDatatypes -> {
vardecl.arraysize!!.constIndex()
}
else -> null
}
varsRequiringZp.forEach { (vardecl, scopedname) ->
val numElements = numArrayElements(vardecl)
val result = zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
result.onFailure { errors.err(it.message!!, vardecl.position) }
}
if(errors.noErrors()) {
varsPreferringZp.forEach { (vardecl, scopedname) ->
val numElements = numArrayElements(vardecl)
zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
// no need to check for allocation error, if there is one, just allocate in normal system ram.
}
// TODO enable zp allocation here and remove it from other places
// if(errors.noErrors()) {
// varsDontCare.forEach { (vardecl, scopedname) ->
// val numElements = numArrayElements(vardecl)
// zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
// // no need to check for allocation error, if there is one, just allocate in normal system ram.
// }
// }
}
}
fun subroutineExtra(sub: Subroutine): SubroutineExtraAsmInfo {
var extra = subroutineExtras[sub]
return if(extra==null) {
extra = SubroutineExtraAsmInfo()
subroutineExtras[sub] = extra
extra
}
else
extra
}
fun getFloatAsmConst(number: Double): String {
val asmName = globalFloatConsts[number]
if(asmName!=null)
return asmName
val newName = "prog8_float_const_${globalFloatConsts.size}"
globalFloatConsts[number] = newName
return newName
}
}
/**
* This class contains various attributes that influence the assembly code generator.
* Conceptually it should be part of any INameScope.
* But because the resulting code only creates "real" scopes on a subroutine level,
* it's more consistent to only define these attributes on a Subroutine node.
*/
internal class SubroutineExtraAsmInfo {
var usedRegsaveA = false
var usedRegsaveX = false
var usedRegsaveY = false
var usedFloatEvalResultVar1 = false
var usedFloatEvalResultVar2 = false
val extraVars = mutableListOf<Triple<DataType, String, UInt?>>()
}

View File

@ -6,15 +6,17 @@ import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.ast.toHex import prog8.ast.toHex
import prog8.codegen.cpu6502.AsmGen import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.cpu6502.VariableAllocator
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: AsmGen) { internal class AssignmentAsmGen(private val program: Program,
private val asmgen: AsmGen,
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen) private val allocator: VariableAllocator) {
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, asmgen, allocator)
fun translate(assignment: Assignment) { fun translate(assignment: Assignment) {
val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen) val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen)
@ -2119,7 +2121,7 @@ $containsLabel lda #1
} }
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to memory byte") TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to memory byte")
TargetStorageKind.REGISTER -> { TargetStorageKind.REGISTER -> {
val floatConst = asmgen.getFloatAsmConst(float) val floatConst = allocator.getFloatAsmConst(float)
when(target.register!!) { when(target.register!!) {
RegisterOrPair.FAC1 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.MOVFM") RegisterOrPair.FAC1 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.MOVFM")
RegisterOrPair.FAC2 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.CONUPK") RegisterOrPair.FAC2 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.CONUPK")
@ -2127,13 +2129,13 @@ $containsLabel lda #1
} }
} }
TargetStorageKind.STACK -> { TargetStorageKind.STACK -> {
val floatConst = asmgen.getFloatAsmConst(float) val floatConst = allocator.getFloatAsmConst(float)
asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float") asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float")
} }
} }
} else { } else {
// non-zero value // non-zero value
val constFloat = asmgen.getFloatAsmConst(float) val constFloat = allocator.getFloatAsmConst(float)
when(target.kind) { when(target.kind) {
TargetStorageKind.VARIABLE -> { TargetStorageKind.VARIABLE -> {
asmgen.out(""" asmgen.out("""
@ -2176,7 +2178,7 @@ $containsLabel lda #1
} }
TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to memory byte") TargetStorageKind.MEMORY -> throw AssemblyError("can't assign float to memory byte")
TargetStorageKind.REGISTER -> { TargetStorageKind.REGISTER -> {
val floatConst = asmgen.getFloatAsmConst(float) val floatConst = allocator.getFloatAsmConst(float)
when(target.register!!) { when(target.register!!) {
RegisterOrPair.FAC1 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.MOVFM") RegisterOrPair.FAC1 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.MOVFM")
RegisterOrPair.FAC2 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.CONUPK") RegisterOrPair.FAC2 -> asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.CONUPK")
@ -2184,7 +2186,7 @@ $containsLabel lda #1
} }
} }
TargetStorageKind.STACK -> { TargetStorageKind.STACK -> {
val floatConst = asmgen.getFloatAsmConst(float) val floatConst = allocator.getFloatAsmConst(float)
asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float") asmgen.out(" lda #<$floatConst | ldy #>$floatConst | jsr floats.push_float")
} }
} }

View File

@ -6,13 +6,15 @@ 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.AsmGen import prog8.codegen.cpu6502.AsmGen
import prog8.codegen.cpu6502.VariableAllocator
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: AsmGen private val asmgen: AsmGen,
private val allocator: VariableAllocator
) { ) {
fun translate(assign: AsmAssignment) { fun translate(assign: AsmAssignment) {
require(assign.isAugmentable) require(assign.isAugmentable)
@ -1718,7 +1720,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: Subroutine) { private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: Subroutine) {
val constValueName = asmgen.getFloatAsmConst(value) val constValueName = allocator.getFloatAsmConst(value)
asmgen.saveRegisterLocal(CpuRegister.X, scope) asmgen.saveRegisterLocal(CpuRegister.X, scope)
when (operator) { when (operator) {
"**" -> { "**" -> {

View File

@ -1,20 +0,0 @@
; just for tests - DISFUNCTIONAL!
math_store_reg .byte 0 ; temporary storage
multiply_bytes .proc
; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned)
sta P8ZP_SCRATCH_B1 ; num1
sty P8ZP_SCRATCH_REG ; num2
lda #0
beq _enterloop
_doAdd clc
adc P8ZP_SCRATCH_B1
_loop asl P8ZP_SCRATCH_B1
_enterloop lsr P8ZP_SCRATCH_REG
bcs _doAdd
bne _loop
rts
.pend

View File

@ -1,7 +0,0 @@
; Internal Math library routines - always included by the compiler
;
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
math {
%asminclude "library:math.asm"
}

View File

@ -631,20 +631,6 @@ class AnonymousScope(override var statements: MutableList<Statement>,
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
} }
class AsmGenInfo {
// This class contains various attributes that influence the assembly code generator.
// Conceptually it should be part of any INameScope.
// But because the resulting code only creates "real" scopes on a subroutine level,
// it's more consistent to only define these attributes on a Subroutine node.
var usedRegsaveA = false
var usedRegsaveX = false
var usedRegsaveY = false
var usedFloatEvalResultVar1 = false
var usedFloatEvalResultVar2 = false
val extraVars = mutableListOf<Triple<DataType, String, UInt?>>()
}
// the subroutine class covers both the normal user-defined subroutines, // the subroutine class covers both the normal user-defined subroutines,
// and also the predefined/ROM/register-based subroutines. // and also the predefined/ROM/register-based subroutines.
// (multiple return types can only occur for the latter type) // (multiple return types can only occur for the latter type)
@ -677,8 +663,6 @@ class Subroutine(override val name: String,
} }
override lateinit var parent: Node override lateinit var parent: Node
val asmGenInfo = AsmGenInfo()
override fun copy() = throw NotImplementedError("no support for duplicating a Subroutine") override fun copy() = throw NotImplementedError("no support for duplicating a Subroutine")
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {

View File

@ -3,8 +3,9 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- programGen: don't generate variables from the VarDecl nodes, use allocator/zeropage tables
- (newvaralloc) UnusedCodeRemover after(decl: VarDecl): fix that vars defined in a library can also safely be removed if unused. Currently this breaks programs such as textelite (due to diskio.save().end_address ?) - (newvaralloc) UnusedCodeRemover after(decl: VarDecl): fix that vars defined in a library can also safely be removed if unused. Currently this breaks programs such as textelite (due to diskio.save().end_address ?)
- remove hacks in VariableAllocation - remove hacks in VariableAllocator
Need help with Need help with