more codegen fixes

This commit is contained in:
Irmen de Jong 2023-01-31 21:49:40 +01:00
parent 2f5bed36b3
commit 0f5cd22bb7
7 changed files with 59 additions and 30 deletions

View File

@ -3,6 +3,7 @@ package prog8.code.ast
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.core.Position
import prog8.code.core.SourceCode
import java.nio.file.Path
// New simplified AST for the code generator.
@ -87,6 +88,7 @@ class PtBlock(name: String,
val library: Boolean,
val forceOutput: Boolean,
val alignment: BlockAlignment,
val source: SourceCode, // taken from the module the block is defined in.
position: Position
) : PtNamedNode(name, position) {
override fun printProperties() {

View File

@ -6,6 +6,7 @@ import prog8.code.ast.*
import prog8.code.core.*
import prog8.codegen.cpu6502.assignment.*
import java.util.*
import kotlin.io.path.Path
import kotlin.io.path.writeLines
@ -315,8 +316,8 @@ class AsmGen(
is PtForLoop -> forloopsAsmGen.translate(stmt)
is PtRepeatLoop -> translate(stmt)
is PtWhen -> translate(stmt)
is PtIncludeBinary -> TODO()
is PtBreakpoint -> TODO()
is PtIncludeBinary -> translate(stmt)
is PtBreakpoint -> translate(stmt)
is PtVariable, is PtConstant, is PtMemMapped -> { /* do nothing; variables are handled elsewhere */ }
is PtBlock -> throw AssemblyError("block should have been handled elsewhere")
is PtNodeGroup -> stmt.children.forEach { translate(it) }
@ -856,6 +857,27 @@ $repeatLabel lda $counterVar
assemblyLines.add(asm.assembly.trimEnd().trimStart('\r', '\n'))
}
private fun translate(incbin: PtIncludeBinary) {
val offset = if(incbin.offset!=null) ", ${incbin.offset}" else ""
val length = if(incbin.length!=null) ", ${incbin.length}" else ""
if(incbin.definingBlock()!!.source is SourceCode.Generated)
throw AssemblyError("%asmbinary inside non-library/non-filesystem module not yet supported")
val sourcePath = Path(incbin.definingBlock()!!.source.origin)
val includedPath = sourcePath.resolveSibling(incbin.file)
val pathForAssembler = options.outputDir // #54: 64tass needs the path *relative to the .asm file*
.toAbsolutePath()
.relativize(includedPath.toAbsolutePath())
.normalize() // avoid assembler warnings (-Wportable; only some, not all)
.toString().replace('\\', '/')
out(" .binary \"$pathForAssembler\" $offset $length")
}
private fun translate(brk: PtBreakpoint) {
val label = "_prog8_breakpoint_${breakpointLabels.size+1}"
breakpointLabels.add(label)
out(label)
}
internal fun signExtendAYlsb(valueDt: DataType) {
// sign extend signed byte in A to full word in AY
when(valueDt) {
@ -2853,14 +2875,13 @@ $repeatLabel lda $counterVar
}
}
/* TODO remove?:
internal fun popCpuStack(dt: DataType, target: PtVariable, scope: IPtSubroutine?) {
// note: because A is pushed first so popped last, saving A is often not required here.
val parameter: PtSubroutineParameter = TODO("search subroutine parameter that it may refer to") // target.subroutineParameter
val parameter = target.definingSub()?.parameters?.singleOrNull { it.name===target.name }
if(parameter!=null) {
val sub = parameter.definingAsmSub()!! // TODO or also regular PtSub?
val shouldKeepA = sub.asmParameterRegisters.any { it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.AY }
val reg: RegisterOrStatusflag = sub.asmParameterRegisters[sub.parameters.indexOf(parameter)]
val sub = parameter.definingAsmSub() ?: throw AssemblyError("push/pop arg passing only supported on asmsubs ${target.position}")
val shouldKeepA = sub.parameters.any { it.second.registerOrPair==RegisterOrPair.AX || it.second.registerOrPair==RegisterOrPair.AY}
val reg = sub.parameters.single { it.first === parameter }.second
if(reg.statusflag!=null) {
if(shouldKeepA)
out(" sta P8ZP_SCRATCH_REG")
@ -2951,7 +2972,6 @@ $repeatLabel lda $counterVar
else -> throw AssemblyError("can't pop $dt")
}
}
*/
internal fun pushCpuStack(dt: DataType, value: PtExpression) {
val signed = value.type.oneOf(DataType.BYTE, DataType.WORD)

View File

@ -52,15 +52,25 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
require(fcall.args[0] is PtIdentifier) {
"attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}"
}
TODO("pop cpu stack byte into ${fcall.args[0]}")
// asmgen.popCpuStack(DataType.UBYTE, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingISub())
val target = (fcall.args[0] as PtIdentifier).targetVarDecl(program)
val target2 = (fcall.args[0] as PtIdentifier).targetStatement(program)
if(target2==null)
TODO("huh1")
if(target==null)
TODO("huh2")
asmgen.popCpuStack(DataType.UBYTE, target!!, fcall.definingISub())
}
"popw" -> {
require(fcall.args[0] is PtIdentifier) {
"attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}"
}
TODO("pop cpu stack word into ${fcall.args[0]}")
// asmgen.popCpuStack(DataType.UWORD, (fcall.args[0] as PtIdentifier).targetVarDecl(program)!!, fcall.definingISub())
val target = (fcall.args[0] as PtIdentifier).targetVarDecl(program)
val target2 = (fcall.args[0] as PtIdentifier).targetStatement(program)
if(target2==null)
TODO("huh1")
if(target==null)
TODO("huh2")
asmgen.popCpuStack(DataType.UWORD, target!!, fcall.definingISub())
}
"rsave" -> funcRsave()
"rsavex" -> funcRsaveX()
@ -319,7 +329,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun funcMemory(fcall: PtBuiltinFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
if(discardResult || fcall !is PtBuiltinFunctionCall) // TODO huh, is always this class??
if(discardResult)
throw AssemblyError("should not discard result of memory allocation at $fcall")
val name = (fcall.args[0] as PtString).value
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name ${fcall.position}"}

View File

@ -56,7 +56,6 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
identifier != null -> {
val paramName = identifier!!.targetVarDecl(program)?.name
val parameter = identifier!!.targetStatement(program).definingSub()?.parameters?.singleOrNull { it.name===paramName }
println("assign to ${identifier!!.name} param=$parameter") // TODO WEG
if (parameter!=null) {
val sub = parameter.definingAsmSub()
if (sub!=null) {
@ -137,7 +136,6 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
is PtIdentifier -> {
val paramName = value.targetVarDecl(program)?.name
val parameter = value.targetStatement(program).definingSub()?.parameters?.singleOrNull { it.name===paramName }
println("assign to ${value.name} param=$parameter") // TODO WEG
if(parameter?.definingAsmSub() != null)
throw AssemblyError("can't assign from a asmsub register parameter $value ${value.position}")
val varName=asmgen.asmVariableName(value)

View File

@ -130,7 +130,8 @@ class IntermediateAstMaker(private val program: Program, private val symbolTable
}
}
val (vardecls, statements) = srcBlock.statements.partition { it is VarDecl }
val block = PtBlock(srcBlock.name, srcBlock.address, srcBlock.isInLibrary, forceOutput, alignment, srcBlock.position)
val src = srcBlock.definingModule.source
val block = PtBlock(srcBlock.name, srcBlock.address, srcBlock.isInLibrary, forceOutput, alignment, src, srcBlock.position)
makeScopeVarsDecls(vardecls).forEach { block.add(it) }
for (stmt in statements)
block.add(transformStatement(stmt))

View File

@ -63,9 +63,7 @@ class TestIntermediateAst: FunSpec({
arraydecl.name shouldBe "array"
arraydecl.type shouldBe DataType.ARRAY_UB
val containmentCast = (entry.children[3] as PtAssignment).value as PtTypeCast
containmentCast.type shouldBe DataType.UBYTE
val containment = containmentCast.value as PtContainmentCheck
val containment = (entry.children[3] as PtAssignment).value as PtContainmentCheck
(containment.element as PtNumber).number shouldBe 11.0
val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall
fcall.void shouldBe false

View File

@ -98,15 +98,15 @@ class TestAsmGenSymbols: StringSpec({
val sub = asmgen.program.entrypoint()!!
val localvarIdent = sub.children.asSequence().filterIsInstance<PtAssignment>().first { it.value is PtIdentifier }.value as PtIdentifier
asmgen.asmSymbolName(localvarIdent) shouldBe "localvar"
asmgen.asmVariableName(localvarIdent) shouldBe "localvar"
asmgen.asmSymbolName(localvarIdent) shouldBe "main.start.localvar"
asmgen.asmVariableName(localvarIdent) shouldBe "main.start.localvar"
val localvarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.localvar" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(localvarIdentScoped) shouldBe "main.start.localvar"
asmgen.asmVariableName(localvarIdentScoped) shouldBe "main.start.localvar"
val scopedVarIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="var_outside" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(scopedVarIdent) shouldBe "var_outside"
asmgen.asmVariableName(scopedVarIdent) shouldBe "var_outside"
val scopedVarIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(scopedVarIdent) shouldBe "main.var_outside"
asmgen.asmVariableName(scopedVarIdent) shouldBe "main.var_outside"
val scopedVarIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.var_outside" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(scopedVarIdentScoped) shouldBe "main.var_outside"
asmgen.asmVariableName(scopedVarIdentScoped) shouldBe "main.var_outside"
@ -117,16 +117,16 @@ class TestAsmGenSymbols: StringSpec({
val asmgen = createTestAsmGen(program)
val sub = asmgen.program.entrypoint()!!
val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="locallabel" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(localLabelIdent) shouldBe "locallabel"
asmgen.asmVariableName(localLabelIdent) shouldBe "locallabel"
val localLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(localLabelIdent) shouldBe "main.start.locallabel"
asmgen.asmVariableName(localLabelIdent) shouldBe "main.start.locallabel"
val localLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.start.locallabel" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(localLabelIdentScoped) shouldBe "main.start.locallabel"
asmgen.asmVariableName(localLabelIdentScoped) shouldBe "main.start.locallabel"
val scopedLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="label_outside" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(scopedLabelIdent) shouldBe "label_outside"
asmgen.asmVariableName(scopedLabelIdent) shouldBe "label_outside"
val scopedLabelIdent = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(scopedLabelIdent) shouldBe "main.label_outside"
asmgen.asmVariableName(scopedLabelIdent) shouldBe "main.label_outside"
val scopedLabelIdentScoped = (sub.children.asSequence().filterIsInstance<PtAssignment>().first { (it.value as? PtAddressOf)?.identifier?.name=="main.label_outside" }.value as PtAddressOf).identifier
asmgen.asmSymbolName(scopedLabelIdentScoped) shouldBe "main.label_outside"
asmgen.asmVariableName(scopedLabelIdentScoped) shouldBe "main.label_outside"