get rid of newexpr compiler option

This commit is contained in:
Irmen de Jong 2023-07-02 15:26:04 +02:00
parent bb95484c8a
commit bdf8aa9168
19 changed files with 58 additions and 306 deletions

View File

@ -37,16 +37,17 @@ class PtNodeGroup : PtNode(Position.DUMMY)
sealed class PtNamedNode(var name: String, position: Position): PtNode(position) { sealed class PtNamedNode(var name: String, position: Position): PtNode(position) {
// Note that as an exception, the 'name' is not read-only // Note that as an exception, the 'name' is not read-only
// but a var. This is to allow for cheap node renames. // but a var. This is to allow for cheap node renames.
val scopedName: String by lazy { val scopedName: String
var namedParent: PtNode = this.parent get() {
if(namedParent is PtProgram) var namedParent: PtNode = this.parent
name return if(namedParent is PtProgram)
else { name
while (namedParent !is PtNamedNode) else {
namedParent = namedParent.parent while (namedParent !is PtNamedNode)
namedParent.scopedName + "." + name namedParent = namedParent.parent
namedParent.scopedName + "." + name
}
} }
}
} }
@ -63,9 +64,9 @@ class PtProgram(
children.asSequence().filterIsInstance<PtBlock>() children.asSequence().filterIsInstance<PtBlock>()
fun entrypoint(): PtSub? = fun entrypoint(): PtSub? =
allBlocks().firstOrNull { it.name == "main" } allBlocks().firstOrNull { it.name == "main" || it.name=="p8_main" }
?.children ?.children
?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start") } as PtSub? ?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start" || it.name=="p8_start" || it.name=="p8_main.p8_start") } as PtSub?
} }

View File

@ -20,7 +20,6 @@ class CompilationOptions(val output: OutputType,
var asmListfile: Boolean = false, var asmListfile: Boolean = false,
var experimentalCodegen: Boolean = false, var experimentalCodegen: Boolean = false,
var varsHighBank: Int? = null, var varsHighBank: Int? = null,
var useNewExprCode: Boolean = false,
var splitWordArrays: Boolean = false, var splitWordArrays: Boolean = false,
var evalStackBaseAddress: UInt? = null, var evalStackBaseAddress: UInt? = null,
var outputDir: Path = Path(""), var outputDir: Path = Path(""),

View File

@ -31,7 +31,8 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
printAst(program, true, ::println) printAst(program, true, ::println)
val nodesToPrefix = mutableListOf<Pair<PtNode, Int>>() val nodesToPrefix = mutableListOf<Pair<PtNode, Int>>() // parent + index
val functionCallsToPrefix = mutableListOf<Pair<PtNode, Int>>() // parent + index
fun prefixNamedNode(node: PtNamedNode) { fun prefixNamedNode(node: PtNamedNode) {
node.name = "p8_${node.name}" node.name = "p8_${node.name}"
@ -51,7 +52,7 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
val stNode = st.lookup(node.name)!! val stNode = st.lookup(node.name)!!
if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) { if(stNode.astNode.definingBlock()?.noSymbolPrefixing!=true) {
val index = node.parent.children.indexOf(node) val index = node.parent.children.indexOf(node)
nodesToPrefix += node.parent to index functionCallsToPrefix += node.parent to index
} }
} }
is PtIdentifier -> { is PtIdentifier -> {
@ -105,13 +106,22 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
val node = parent.children[index] val node = parent.children[index]
when(node) { when(node) {
is PtIdentifier -> parent.children[index] = node.prefix(parent) is PtIdentifier -> parent.children[index] = node.prefix(parent)
is PtFunctionCall -> parent.children[index] = node.prefix(parent) is PtFunctionCall -> throw AssemblyError("PtFunctionCall should be processed in their own list, last")
is PtJump -> parent.children[index] = node.prefix(parent) is PtJump -> parent.children[index] = node.prefix(parent)
is PtVariable -> parent.children[index] = node.prefix(parent) is PtVariable -> parent.children[index] = node.prefix(parent)
else -> throw AssemblyError("weird node to prefix $node") else -> throw AssemblyError("weird node to prefix $node")
} }
} }
functionCallsToPrefix.forEach { (parent, index) ->
val node = parent.children[index]
if(node is PtFunctionCall) {
parent.children[index] = node.prefix(parent)
} else {
throw AssemblyError("expected PtFunctionCall")
}
}
return SymbolTableMaker(program, options).make() return SymbolTableMaker(program, options).make()
} }
} }
@ -658,7 +668,6 @@ class AsmGen6502Internal (
private fun translate(stmt: PtIfElse) { private fun translate(stmt: PtIfElse) {
val condition = stmt.condition as? PtBinaryExpression val condition = stmt.condition as? PtBinaryExpression
if(condition!=null) { if(condition!=null) {
require(!options.useNewExprCode)
requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>' requireComparisonExpression(condition) // IfStatement: condition must be of form 'x <comparison> <value>'
if (stmt.elseScope.children.isEmpty()) { if (stmt.elseScope.children.isEmpty()) {
val jump = stmt.ifScope.children.singleOrNull() val jump = stmt.ifScope.children.singleOrNull()
@ -1118,18 +1127,10 @@ $repeatLabel""")
} }
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression): Pair<PtExpression, PtExpression>? { internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: PtExpression): Pair<PtExpression, PtExpression>? {
val left: PtExpression if (pointerOffsetExpr !is PtBinaryExpression) return null
val right: PtExpression val operator = pointerOffsetExpr.operator
val operator: String val left = pointerOffsetExpr.left
val right = pointerOffsetExpr.right
if (pointerOffsetExpr is PtBinaryExpression) {
require(!options.useNewExprCode)
operator = pointerOffsetExpr.operator
left = pointerOffsetExpr.left
right = pointerOffsetExpr.right
}
else return null
if (operator != "+") return null if (operator != "+") return null
val leftDt = left.type val leftDt = left.type
val rightDt = right.type val rightDt = right.type
@ -1241,10 +1242,7 @@ $repeatLabel""")
} }
internal fun findSubroutineParameter(name: String, asmgen: AsmGen6502Internal): PtSubroutineParameter? { internal fun findSubroutineParameter(name: String, asmgen: AsmGen6502Internal): PtSubroutineParameter? {
val stScope = asmgen.symbolTable.lookup(name) val stScope = asmgen.symbolTable.lookup(name) ?: return null
require(stScope!=null) {
"invalid name lookup $name"
}
val node = stScope.astNode val node = stScope.astNode
if(node is PtSubroutineParameter) if(node is PtSubroutineParameter)
return node return node
@ -2892,7 +2890,6 @@ $repeatLabel""")
out(" sta P8ESTACK_LO,x | dex") out(" sta P8ESTACK_LO,x | dex")
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!options.useNewExprCode)
val addrExpr = expr.address as PtBinaryExpression val addrExpr = expr.address as PtBinaryExpression
if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { if(tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
if(pushResultOnEstack) if(pushResultOnEstack)

View File

@ -751,7 +751,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} }
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr) val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier val pointer = result?.first as? PtIdentifier
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) { if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {
@ -813,7 +812,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} else fallback() } else fallback()
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val result = asmgen.pointerViaIndexRegisterPossible(addrExpr) val result = asmgen.pointerViaIndexRegisterPossible(addrExpr)
val pointer = result?.first as? PtIdentifier val pointer = result?.first as? PtIdentifier
if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) { if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) {

View File

@ -248,8 +248,6 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
} }
private fun translateExpression(expr: PtBinaryExpression) { private fun translateExpression(expr: PtBinaryExpression) {
require(!asmgen.options.useNewExprCode)
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED! // Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
if(translateSomewhatOptimized(expr.left, expr.operator, expr.right)) if(translateSomewhatOptimized(expr.left, expr.operator, expr.right))
return return

View File

@ -313,7 +313,9 @@ internal class ProgramAndVarsGen(
asmgen.out("${sub.name}\t$asmStartScope") asmgen.out("${sub.name}\t$asmStartScope")
val scope = symboltable.lookupOrElse(sub.scopedName) { throw AssemblyError("lookup") } val scope = symboltable.lookupOrElse(sub.scopedName) {
throw AssemblyError("lookup ${sub.scopedName}")
}
require(scope.type==StNodeType.SUBROUTINE) require(scope.type==StNodeType.SUBROUTINE)
val varsInSubroutine = getVars(scope) val varsInSubroutine = getVars(scope)

View File

@ -158,7 +158,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignMemoryByte(assign.target, null, value.address as PtIdentifier) assignMemoryByte(assign.target, null, value.address as PtIdentifier)
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val addrExpr = value.address as PtBinaryExpression val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
assignRegisterByte(assign.target, CpuRegister.A, false) assignRegisterByte(assign.target, CpuRegister.A, false)
@ -313,7 +312,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignRegisterByte(assign.target, CpuRegister.A, false) assignRegisterByte(assign.target, CpuRegister.A, false)
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
if(!attemptAssignOptimizedBinexpr(value, assign)) { if(!attemptAssignOptimizedBinexpr(value, assign)) {
// All remaining binary expressions just evaluate via the stack for now. // All remaining binary expressions just evaluate via the stack for now.
// (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here, // (we can't use the assignment helper functions (assignExpressionTo...) to do it via registers here,
@ -359,7 +357,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
require(!asmgen.options.useNewExprCode)
if(expr.operator in ComparisonOperators) { if(expr.operator in ComparisonOperators) {
if(expr.right.asConstInteger() == 0) { if(expr.right.asConstInteger() == 0) {
if(expr.operator == "==" || expr.operator=="!=") { if(expr.operator == "==" || expr.operator=="!=") {
@ -1155,7 +1152,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
require(!asmgen.options.useNewExprCode)
when (expr.operator) { when (expr.operator) {
"==" -> { "==" -> {
when(val dt = expr.left.type) { when(val dt = expr.left.type) {
@ -1335,7 +1331,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignMemoryByteIntoWord(target, null, value.address as PtIdentifier) assignMemoryByteIntoWord(target, null, value.address as PtIdentifier)
} }
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
val addrExpr = value.address as PtBinaryExpression val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) { if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
asmgen.out(" ldy #0") asmgen.out(" ldy #0")
@ -3487,7 +3482,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.storeAIntoPointerVar(addressExpr) asmgen.storeAIntoPointerVar(addressExpr)
} }
addressExpr is PtBinaryExpression -> { addressExpr is PtBinaryExpression -> {
require(!asmgen.options.useNewExprCode)
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true)) if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
storeViaExprEval() storeViaExprEval()
} }

View File

@ -105,27 +105,10 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
value.add(origAssign.value) value.add(origAssign.value)
} else { } else {
require(origAssign.operator.endsWith('=')) require(origAssign.operator.endsWith('='))
if(codeGen.options.useNewExprCode) { value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
// X += Y -> temp = X, temp += Y, X = temp val left: PtExpression = origAssign.target.children.single() as PtExpression
val tempvar = codeGen.getReusableTempvar(origAssign.definingSub()!!, origAssign.target.type) value.add(left)
val assign = PtAssignment(origAssign.position) value.add(origAssign.value)
val target = PtAssignTarget(origAssign.position)
target.add(tempvar)
assign.add(target)
assign.add(origAssign.target.children.single())
val augAssign = PtAugmentedAssign(origAssign.operator, origAssign.position)
augAssign.add(target)
augAssign.add(origAssign.value)
val assignBack = PtAssignment(origAssign.position)
assignBack.add(origAssign.target)
assignBack.add(tempvar)
return translateRegularAssign(assign) + translate(augAssign) + translateRegularAssign(assignBack)
} else {
value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position)
val left: PtExpression = origAssign.target.children.single() as PtExpression
value.add(left)
value.add(origAssign.value)
}
} }
val normalAssign = PtAssignment(origAssign.position) val normalAssign = PtAssignment(origAssign.position)
normalAssign.add(origAssign.target) normalAssign.add(origAssign.target)
@ -347,19 +330,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
return Pair(result, tr.resultReg) return Pair(result, tr.resultReg)
} }
if(codeGen.options.useNewExprCode) { val mult: PtExpression
val tr = expressionEval.translateExpression(array.index) mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
result += tr.chunks mult.children += array.index
addInstr(result, IRInstruction(Opcode.MUL, tr.dt, reg1=tr.resultReg, immediate = itemsize), null) mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
return Pair(result, tr.resultReg) val tr = expressionEval.translateExpression(mult)
} else { addToResult(result, tr, tr.resultReg, -1)
val mult: PtExpression return Pair(result, tr.resultReg)
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
mult.children += array.index
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
val tr = expressionEval.translateExpression(mult)
addToResult(result, tr, tr.resultReg, -1)
return Pair(result, tr.resultReg)
}
} }
} }

View File

@ -340,7 +340,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult { private fun translate(binExpr: PtBinaryExpression): ExpressionCodeResult {
require(!codeGen.options.useNewExprCode)
val vmDt = irType(binExpr.left.type) val vmDt = irType(binExpr.left.type)
val signed = binExpr.left.type in SignedDatatypes val signed = binExpr.left.type in SignedDatatypes
return when(binExpr.operator) { return when(binExpr.operator) {

View File

@ -905,7 +905,6 @@ class IRCodeGen(
val goto = ifElse.ifScope.children.firstOrNull() as? PtJump val goto = ifElse.ifScope.children.firstOrNull() as? PtJump
when (condition) { when (condition) {
is PtBinaryExpression -> { is PtBinaryExpression -> {
require(!options.useNewExprCode)
if(condition.operator !in ComparisonOperators) if(condition.operator !in ComparisonOperators)
throw AssemblyError("if condition should only be a binary comparison expression") throw AssemblyError("if condition should only be a binary comparison expression")
@ -919,7 +918,6 @@ class IRCodeGen(
} }
else -> { else -> {
// if X --> meaning: if X!=0 // if X --> meaning: if X!=0
require(options.useNewExprCode)
val irDt = irType(condition.type) val irDt = irType(condition.type)
val signed = condition.type in SignedDatatypes val signed = condition.type in SignedDatatypes
return if(goto!=null && ifElse.elseScope.children.isEmpty()) { return if(goto!=null && ifElse.elseScope.children.isEmpty()) {

View File

@ -54,7 +54,6 @@ private fun compileMain(args: Array<String>): Boolean {
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM") val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM")
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)") val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
val varsHighBank by cli.option(ArgType.Int, fullName = "varshigh", description = "put uninitialized variables in high memory area instead of at the end of the program. On the cx16 target the value specifies the HiRAM bank (0=keep active), on other systems it is ignored.") val varsHighBank by cli.option(ArgType.Int, fullName = "varshigh", description = "put uninitialized variables in high memory area instead of at the end of the program. On the cx16 target the value specifies the HiRAM bank (0=keep active), on other systems it is ignored.")
val useNewExprCode by cli.option(ArgType.Boolean, fullName = "newexpr", description = "use new expression code-gen (experimental)")
val splitWordArrays by cli.option(ArgType.Boolean, fullName = "splitarrays", description = "treat all word arrays as tagged with @split to make them lsb/msb split in memory") val splitWordArrays by cli.option(ArgType.Boolean, fullName = "splitarrays", description = "treat all word arrays as tagged with @split to make them lsb/msb split in memory")
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999) val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
@ -135,7 +134,6 @@ private fun compileMain(args: Array<String>): Boolean {
asmListfile == true, asmListfile == true,
experimentalCodegen == true, experimentalCodegen == true,
varsHighBank, varsHighBank,
useNewExprCode == true,
compilationTarget, compilationTarget,
evalStackAddr, evalStackAddr,
splitWordArrays == true, splitWordArrays == true,
@ -205,7 +203,6 @@ private fun compileMain(args: Array<String>): Boolean {
asmListfile == true, asmListfile == true,
experimentalCodegen == true, experimentalCodegen == true,
varsHighBank, varsHighBank,
useNewExprCode == true,
compilationTarget, compilationTarget,
evalStackAddr, evalStackAddr,
splitWordArrays == true, splitWordArrays == true,

View File

@ -6,10 +6,10 @@ package prog8.buildversion
const val MAVEN_GROUP = "prog8" const val MAVEN_GROUP = "prog8"
const val MAVEN_NAME = "compiler" const val MAVEN_NAME = "compiler"
const val VERSION = "9.1-SNAPSHOT" const val VERSION = "9.1-SNAPSHOT"
const val GIT_REVISION = -1 const val GIT_REVISION = 3914
const val GIT_SHA = "bf86e1f41d9c97d3b56e91e5217bcda258fa3e09" const val GIT_SHA = "bb95484c8abd6a65220e542913d59d337d833c86"
const val GIT_DATE = "UNKNOWN" const val GIT_DATE = "2023-07-02T04:15:09Z"
const val GIT_BRANCH = "prefixing" const val GIT_BRANCH = "prefixing"
const val BUILD_DATE = "2023-06-30T23:38:56Z" const val BUILD_DATE = "2023-07-02T13:23:24Z"
const val BUILD_UNIX_TIME = 1688168336048L const val BUILD_UNIX_TIME = 1688304204488L
const val DIRTY = 1 const val DIRTY = 1

View File

@ -4,12 +4,11 @@ import com.github.michaelbull.result.onFailure
import prog8.ast.IBuiltinFunctions import prog8.ast.IBuiltinFunctions
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.AstException import prog8.ast.base.AstException
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.Expression import prog8.ast.expressions.Expression
import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.Directive import prog8.ast.statements.Directive
import prog8.code.SymbolTableMaker import prog8.code.SymbolTableMaker
import prog8.code.ast.* import prog8.code.ast.PtProgram
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.* import prog8.code.target.*
import prog8.codegen.vm.VmCodeGen import prog8.codegen.vm.VmCodeGen
@ -37,7 +36,6 @@ class CompilerArguments(val filepath: Path,
val asmListfile: Boolean, val asmListfile: Boolean,
val experimentalCodegen: Boolean, val experimentalCodegen: Boolean,
val varsHighBank: Int?, val varsHighBank: Int?,
val useNewExprCode: Boolean,
val compilationTarget: String, val compilationTarget: String,
val evalStackBaseAddress: UInt?, val evalStackBaseAddress: UInt?,
val splitWordArrays: Boolean, val splitWordArrays: Boolean,
@ -79,7 +77,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
asmListfile = args.asmListfile asmListfile = args.asmListfile
experimentalCodegen = args.experimentalCodegen experimentalCodegen = args.experimentalCodegen
varsHighBank = args.varsHighBank varsHighBank = args.varsHighBank
useNewExprCode = args.useNewExprCode
evalStackBaseAddress = args.evalStackBaseAddress evalStackBaseAddress = args.evalStackBaseAddress
splitWordArrays = args.splitWordArrays splitWordArrays = args.splitWordArrays
outputDir = args.outputDir.normalize() outputDir = args.outputDir.normalize()
@ -412,17 +409,6 @@ private fun createAssemblyAndAssemble(program: PtProgram,
else else
throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.machine.cpu}") throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.machine.cpu}")
if(compilerOptions.useNewExprCode) {
if(compilerOptions.compTarget.machine.cpu !in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) {
// the IR code gen backend has its own, better, version of dealing with binary expressions.
throw IllegalArgumentException("'newexpr' expression rewrite should not be used with compilation target ${compilerOptions.compTarget.name}")
}
transformNewExpressions(program)
}
// printAst(program, true) { println(it) }
val stMaker = SymbolTableMaker(program, compilerOptions) val stMaker = SymbolTableMaker(program, compilerOptions)
val symbolTable = stMaker.make() val symbolTable = stMaker.make()
val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors) val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors)
@ -434,188 +420,3 @@ private fun createAssemblyAndAssemble(program: PtProgram,
false false
} }
} }
private fun transformNewExpressions(program: PtProgram) {
val newVariables = mutableMapOf<PtSub, MutableList<PtVariable>>()
var countByteVars = 0
var countWordVars = 0
var countFloatVars = 0
// TODO: find a reliable way to reuse more temp vars across expressions
fun getExprVar(type: DataType, pos: Position, scope: PtSub): PtIdentifier {
val count = when(type) {
in ByteDatatypes -> {
countByteVars++
countByteVars
}
in WordDatatypes -> {
countWordVars++
countWordVars
}
DataType.FLOAT -> {
countFloatVars++
countFloatVars
}
else -> throw FatalAstException("weird dt")
}
val name = "p8p_exprvar_${count}_${type.toString().lowercase()}"
var subVars = newVariables[scope]
if(subVars==null) {
subVars = mutableListOf()
newVariables[scope] = subVars
}
if(subVars.all { it.name!=name }) {
subVars.add(PtVariable(name, type, ZeropageWish.DONTCARE, null, null, pos))
}
return PtIdentifier("${scope.scopedName}.$name", type, pos)
}
fun transformExpr(expr: PtBinaryExpression): Pair<PtExpression, List<IPtAssignment>> {
// depth first process the expression tree
val scope = expr.definingSub()!!
val assignments = mutableListOf<IPtAssignment>()
fun transformOperand(node: PtExpression): PtNode {
return when(node) {
is PtNumber, is PtIdentifier, is PtArray, is PtString, is PtMachineRegister -> node
is PtBinaryExpression -> {
val (replacement, subAssigns) = transformExpr(node)
assignments.addAll(subAssigns)
replacement
}
else -> {
val variable = getExprVar(node.type, node.position, scope)
val assign = PtAssignment(node.position)
val target = PtAssignTarget(variable.position)
target.add(variable)
assign.add(target)
assign.add(node)
assignments.add(assign)
variable
}
}
}
val newLeft = transformOperand(expr.left)
val newRight = transformOperand(expr.right)
// process the binexpr
val resultVar =
if(expr.type == expr.left.type) {
getExprVar(expr.type, expr.position, scope)
} else {
if(expr.operator in ComparisonOperators && expr.type in ByteDatatypes) {
// this is very common and should be dealth with correctly; byte==0, word>42
val varType = if(expr.left.type in PassByReferenceDatatypes) DataType.UWORD else expr.left.type
getExprVar(varType, expr.position, scope)
}
else if(expr.left.type in PassByReferenceDatatypes && expr.type==DataType.UBYTE) {
// this is common and should be dealth with correctly; for instance "name"=="john"
val varType = if (expr.left.type in PassByReferenceDatatypes) DataType.UWORD else expr.left.type
getExprVar(varType, expr.position, scope)
} else if(expr.left.type equalsSize expr.type) {
getExprVar(expr.type, expr.position, scope)
} else {
TODO("expression type differs from left operand type! got ${expr.left.type} expected ${expr.type} ${expr.position}")
}
}
if(resultVar.name!=(newLeft as? PtIdentifier)?.name) {
// resultvar = left
val assign1 = PtAssignment(newLeft.position)
val target1 = PtAssignTarget(resultVar.position)
target1.add(resultVar)
assign1.add(target1)
assign1.add(newLeft)
assignments.add(assign1)
}
// resultvar {oper}= right
val operator = if(expr.operator in ComparisonOperators) expr.operator else expr.operator+'='
val assign2 = PtAugmentedAssign(operator, newRight.position)
val target2 = PtAssignTarget(resultVar.position)
target2.add(resultVar.copy())
assign2.add(target2)
assign2.add(newRight)
assignments.add(assign2)
return Pair(resultVar, assignments)
}
fun isProperStatement(node: PtNode): Boolean {
return when(node) {
is PtAssignment -> true
is PtAugmentedAssign -> true
is PtBreakpoint -> true
is PtConditionalBranch -> true
is PtForLoop -> true
is PtIfElse -> true
is PtIncludeBinary -> true
is PtInlineAssembly -> true
is PtJump -> true
is PtAsmSub -> true
is PtLabel -> true
is PtSub -> true
is PtVariable -> true
is PtNop -> true
is PtPostIncrDecr -> true
is PtRepeatLoop -> true
is PtReturn -> true
is PtWhen -> true
is PtBuiltinFunctionCall -> node.void
is PtFunctionCall -> node.void
else -> false
}
}
fun transform(node: PtNode, parent: PtNode) {
if(node is PtBinaryExpression) {
node.children.toTypedArray().forEach {
transform(it, node)
}
val (rep, assignments) = transformExpr(node)
var replacement = rep
if(!(rep.type equalsSize node.type)) {
if(rep.type in NumericDatatypes && node.type in ByteDatatypes) {
replacement = PtTypeCast(node.type, node.position)
replacement.add(rep)
} else
TODO("cast replacement type ${rep.type} -> ${node.type}")
}
var idx = parent.children.indexOf(node)
parent.children[idx] = replacement
replacement.parent = parent
// find the statement above which we should insert the assignments
var stmt = node
while(!isProperStatement(stmt))
stmt = stmt.parent
idx = stmt.parent.children.indexOf(stmt)
assignments.reversed().forEach {
stmt.parent.add(idx, it as PtNode)
}
} else {
node.children.toTypedArray().forEach { child -> transform(child, node) }
}
}
program.allBlocks().forEach { block ->
block.children.toTypedArray().forEach {
transform(it, block)
}
}
// add the new variables
newVariables.forEach { (sub, vars) ->
vars.forEach {
sub.add(0, it)
}
}
// extra check to see that all PtBinaryExpressions have been transformed
fun binExprCheck(node: PtNode) {
if(node is PtBinaryExpression)
throw IllegalArgumentException("still got binexpr $node ${node.position}")
node.children.forEach { binExprCheck(it) }
}
binExprCheck(program)
}

View File

@ -33,7 +33,6 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
asmListfile = false, asmListfile = false,
experimentalCodegen = false, experimentalCodegen = false,
varsHighBank = null, varsHighBank = null,
useNewExprCode = false,
compilationTarget = target.name, compilationTarget = target.name,
evalStackBaseAddress = null, evalStackBaseAddress = null,
splitWordArrays = false, splitWordArrays = false,

View File

@ -50,7 +50,6 @@ class TestCompilerOptionSourcedirs: FunSpec({
asmListfile = false, asmListfile = false,
experimentalCodegen = false, experimentalCodegen = false,
varsHighBank = null, varsHighBank = null,
useNewExprCode = false,
compilationTarget = Cx16Target.NAME, compilationTarget = Cx16Target.NAME,
evalStackBaseAddress = null, evalStackBaseAddress = null,
splitWordArrays = false, splitWordArrays = false,

View File

@ -17,9 +17,9 @@ class TestVariables: FunSpec({
ubyte @shared bytevar = 0 ubyte @shared bytevar = 0
%asm {{ %asm {{
lda arrayvar lda p8_arrayvar
lda stringvar lda p8_stringvar
lda bytevar lda p8_bytevar
}} }}
} }
} }

View File

@ -85,10 +85,10 @@ main {
result.codegenAst!!.name shouldBe result.compilerAst.name result.codegenAst!!.name shouldBe result.compilerAst.name
result.codegenAst!!.children.size shouldBeGreaterThan 2 result.codegenAst!!.children.size shouldBeGreaterThan 2
val start = result.codegenAst!!.entrypoint()!! val start = result.codegenAst!!.entrypoint()!!
start.name shouldBe "start" start.name shouldBe "p8_start"
start.children.size shouldBeGreaterThan 2 start.children.size shouldBeGreaterThan 2
val seed = start.children[0] as PtVariable val seed = start.children[0] as PtVariable
seed.name shouldBe "seed" seed.name shouldBe "p8_seed"
seed.value shouldBe null seed.value shouldBe null
seed.type shouldBe DataType.ARRAY_UW seed.type shouldBe DataType.ARRAY_UW
val assign = start.children[1] as PtAssignment val assign = start.children[1] as PtAssignment
@ -161,10 +161,8 @@ main {
qq = 16000 + c*${'$'}0008 qq = 16000 + c*${'$'}0008
} }
}""" }"""
compileText(C64Target(), true, text, writeAssembly = true, useNewExprCode = false) shouldNotBe null compileText(C64Target(), true, text, writeAssembly = true) shouldNotBe null
compileText(VMTarget(), true, text, writeAssembly = true, useNewExprCode = false) shouldNotBe null compileText(VMTarget(), true, text, writeAssembly = true) shouldNotBe null
compileText(C64Target(), true, text, writeAssembly = true, useNewExprCode = true) shouldNotBe null
// no newexpr for IR targets: compileText(VMTarget(), true, text, writeAssembly = true, useNewExprCode = true) shouldNotBe null
} }
test("builtin func in float expression") { test("builtin func in float expression") {

View File

@ -18,7 +18,6 @@ internal fun compileFile(
errors: IErrorReporter? = null, errors: IErrorReporter? = null,
writeAssembly: Boolean = true, writeAssembly: Boolean = true,
optFloatExpr: Boolean = true, optFloatExpr: Boolean = true,
useNewExprCode: Boolean = false
) : CompilationResult? { ) : CompilationResult? {
val filepath = fileDir.resolve(fileName) val filepath = fileDir.resolve(fileName)
assumeReadableFile(filepath) assumeReadableFile(filepath)
@ -32,7 +31,6 @@ internal fun compileFile(
asmListfile = false, asmListfile = false,
experimentalCodegen = false, experimentalCodegen = false,
varsHighBank = null, varsHighBank = null,
useNewExprCode = useNewExprCode,
platform.name, platform.name,
evalStackBaseAddress = null, evalStackBaseAddress = null,
symbolDefs = emptyMap(), symbolDefs = emptyMap(),
@ -55,11 +53,10 @@ internal fun compileText(
errors: IErrorReporter? = null, errors: IErrorReporter? = null,
writeAssembly: Boolean = true, writeAssembly: Boolean = true,
optFloatExpr: Boolean = true, optFloatExpr: Boolean = true,
useNewExprCode: Boolean = false
) : CompilationResult? { ) : CompilationResult? {
val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8") val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
// we don't assumeNotExists(filePath) - should be ok to just overwrite it // we don't assumeNotExists(filePath) - should be ok to just overwrite it
filePath.toFile().writeText(sourceText) filePath.toFile().writeText(sourceText)
return compileFile(platform, optimize, filePath.parent, filePath.name, return compileFile(platform, optimize, filePath.parent, filePath.name,
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, useNewExprCode=useNewExprCode) errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr)
} }

View File

@ -44,7 +44,6 @@ class RequestParser : Take {
experimentalCodegen = false, experimentalCodegen = false,
splitWordArrays = false, splitWordArrays = false,
varsHighBank = null, varsHighBank = null,
useNewExprCode = false
) )
val compilationResult = compileProgram(args) val compilationResult = compileProgram(args)
return RsJson(Jsonding()) return RsJson(Jsonding())