This commit is contained in:
Irmen de Jong
2024-05-17 18:48:04 +02:00
parent 3ef5bdfeda
commit 4a710ecdfc
25 changed files with 75 additions and 274 deletions

View File

@@ -82,8 +82,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
override fun lookup(scopedName: String) = flat[scopedName] override fun lookup(scopedName: String) = flat[scopedName]
fun getLength(name: String): Int? { fun getLength(name: String): Int? {
val node = flat[name] return when(val node = flat[name]) {
return when(node) {
is StMemVar -> node.length is StMemVar -> node.length
is StMemorySlab -> node.size.toInt() is StMemorySlab -> node.size.toInt()
is StStaticVariable -> node.length is StStaticVariable -> node.length

View File

@@ -230,7 +230,7 @@ class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.BOO
companion object { companion object {
fun fromNumber(number: Number, position: Position): PtBool = fun fromNumber(number: Number, position: Position): PtBool =
PtBool(if(number==0.0) false else true, position) PtBool(number != 0.0, position)
} }
override fun hashCode(): Int = Objects.hash(type, value) override fun hashCode(): Int = Objects.hash(type, value)

View File

@@ -63,18 +63,18 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
"???" "???"
} }
is PtAsmSub -> { is PtAsmSub -> {
val params = node.parameters.map { val params = node.parameters.joinToString(", ") {
val register = it.first.registerOrPair val register = it.first.registerOrPair
val statusflag = it.first.statusflag val statusflag = it.first.statusflag
"${it.second.type} ${it.second.name} @${register ?: statusflag}" "${it.second.type} ${it.second.name} @${register ?: statusflag}"
}.joinToString(", ") }
val clobbers = if (node.clobbers.isEmpty()) "" else "clobbers ${node.clobbers}" val clobbers = if (node.clobbers.isEmpty()) "" else "clobbers ${node.clobbers}"
val returns = if (node.returns.isEmpty()) "" else { val returns = if (node.returns.isEmpty()) "" else {
"-> ${node.returns.map { "-> ${node.returns.joinToString(", ") {
val register = it.first.registerOrPair val register = it.first.registerOrPair
val statusflag = it.first.statusflag val statusflag = it.first.statusflag
"${it.second} @${register ?: statusflag}"} "${it.second} @${register ?: statusflag}"
.joinToString(", ") }
}" }"
} }
val str = if (node.inline) "inline " else "" val str = if (node.inline) "inline " else ""
@@ -108,7 +108,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
} }
} }
is PtSub -> { is PtSub -> {
val params = node.parameters.map { "${it.type} ${it.name}" }.joinToString(", ") val params = node.parameters.joinToString(", ") { "${it.type} ${it.name}" }
var str = "sub ${node.name}($params) " var str = "sub ${node.name}($params) "
if(node.returntype!=null) if(node.returntype!=null)
str += "-> ${node.returntype.name.lowercase()}" str += "-> ${node.returntype.name.lowercase()}"

View File

@@ -78,7 +78,7 @@ enum class RegisterOrPair {
R8, R9, R10, R11, R12, R13, R14, R15; R8, R9, R10, R11, R12, R13, R14, R15;
companion object { companion object {
val names by lazy { values().map { it.toString()} } val names by lazy { entries.map { it.toString()} }
fun fromCpuRegister(cpu: CpuRegister): RegisterOrPair { fun fromCpuRegister(cpu: CpuRegister): RegisterOrPair {
return when(cpu) { return when(cpu) {
CpuRegister.A -> A CpuRegister.A -> A
@@ -104,7 +104,7 @@ enum class Statusflag {
Pn; // don't use Pn; // don't use
companion object { companion object {
val names by lazy { values().map { it.toString()} } val names by lazy { entries.map { it.toString()} }
} }
} }

View File

@@ -100,8 +100,7 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
} }
nodesToPrefix.forEach { (parent, index) -> nodesToPrefix.forEach { (parent, index) ->
val node = parent.children[index] when(val node = parent.children[index]) {
when(node) {
is PtIdentifier -> parent.children[index] = node.prefix(parent, st) is PtIdentifier -> parent.children[index] = node.prefix(parent, st)
is PtFunctionCall -> throw AssemblyError("PtFunctionCall should be processed in their own list, last") is PtFunctionCall -> throw AssemblyError("PtFunctionCall should be processed in their own list, last")
is PtJump -> parent.children[index] = node.prefix(parent, st) is PtJump -> parent.children[index] = node.prefix(parent, st)
@@ -247,7 +246,7 @@ class AsmGen6502Internal (
if(errors.noErrors()) { if(errors.noErrors()) {
val output = options.outputDir.resolve("${program.name}.asm") val output = options.outputDir.resolve("${program.name}.asm")
val asmLines = assembly.asSequence().flatMapTo(mutableListOf()) { it.split('\n') } val asmLines = assembly.flatMapTo(mutableListOf()) { it.split('\n') }
if(options.compTarget.name==Cx16Target.NAME) { if(options.compTarget.name==Cx16Target.NAME) {
scanInvalid65816instructions(asmLines) scanInvalid65816instructions(asmLines)
if(!errors.noErrors()) { if(!errors.noErrors()) {
@@ -1320,91 +1319,6 @@ $repeatLabel""")
} }
} }
internal fun popCpuStack(asmsub: PtAsmSub, parameter: PtSubroutineParameter, reg: RegisterOrStatusflag) {
val shouldKeepA = asmsub.parameters.any { it.first.registerOrPair==RegisterOrPair.AX || it.first.registerOrPair==RegisterOrPair.AY}
if(reg.statusflag!=null) {
if(shouldKeepA)
out(" sta P8ZP_SCRATCH_REG")
out("""
clc
pla
beq +
sec
+""")
if(shouldKeepA)
out(" lda P8ZP_SCRATCH_REG")
}
else {
if (parameter.type in ByteDatatypesWithBoolean) {
if (isTargetCpu(CpuType.CPU65c02)) {
when (reg.registerOrPair) {
RegisterOrPair.A -> out(" pla")
RegisterOrPair.X -> out(" plx")
RegisterOrPair.Y -> out(" ply")
in Cx16VirtualRegisters -> out(" pla | sta cx16.${reg.registerOrPair!!.name.lowercase()}")
else -> throw AssemblyError("invalid target register ${reg.registerOrPair}")
}
} else {
when (reg.registerOrPair) {
RegisterOrPair.A -> out(" pla")
RegisterOrPair.X -> {
if(shouldKeepA)
out(" sta P8ZP_SCRATCH_REG | pla | tax | lda P8ZP_SCRATCH_REG")
else
out(" pla | tax")
}
RegisterOrPair.Y -> {
if(shouldKeepA)
out(" sta P8ZP_SCRATCH_REG | pla | tay | lda P8ZP_SCRATCH_REG")
else
out(" pla | tay")
}
in Cx16VirtualRegisters -> out(" pla | sta cx16.${reg.registerOrPair!!.name.lowercase()}")
else -> throw AssemblyError("invalid target register ${reg.registerOrPair}")
}
}
} else {
// word pop
if (isTargetCpu(CpuType.CPU65c02))
when (reg.registerOrPair) {
RegisterOrPair.AX -> out(" plx | pla")
RegisterOrPair.AY -> out(" ply | pla")
RegisterOrPair.XY -> out(" ply | plx")
in Cx16VirtualRegisters -> {
val regname = reg.registerOrPair!!.name.lowercase()
out(" pla | sta cx16.$regname+1 | pla | sta cx16.$regname")
}
else -> throw AssemblyError("invalid target register ${reg.registerOrPair}")
}
else {
when (reg.registerOrPair) {
RegisterOrPair.AX -> out(" pla | tax | pla")
RegisterOrPair.AY -> out(" pla | tay | pla")
RegisterOrPair.XY -> out(" pla | tay | pla | tax")
in Cx16VirtualRegisters -> {
val regname = reg.registerOrPair!!.name.lowercase()
out(" pla | sta cx16.$regname+1 | pla | sta cx16.$regname")
}
else -> throw AssemblyError("invalid target register ${reg.registerOrPair}")
}
}
}
}
}
internal fun popCpuStack(dt: DataType) {
if (dt in ByteDatatypesWithBoolean) {
out(" pla")
} else if (dt in WordDatatypes) {
if (isTargetCpu(CpuType.CPU65c02))
out(" ply | pla")
else
out(" pla | tay | pla")
} else {
throw AssemblyError("can't pop type $dt")
}
}
internal fun pushCpuStack(dt: DataType, value: PtExpression) { internal fun pushCpuStack(dt: DataType, value: PtExpression) {
val signed = value.type.oneOf(DataType.BYTE, DataType.WORD) val signed = value.type.oneOf(DataType.BYTE, DataType.WORD)
if(dt in ByteDatatypesWithBoolean) { if(dt in ByteDatatypesWithBoolean) {

View File

@@ -82,8 +82,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
val source = fcall.args[0] as PtIdentifier val source = fcall.args[0] as PtIdentifier
val target = fcall.args[1] as PtIdentifier val target = fcall.args[1] as PtIdentifier
val sourceSymbol = asmgen.symbolTable.lookup(source.name) val numElements = when(val sourceSymbol = asmgen.symbolTable.lookup(source.name)) {
val numElements = when(sourceSymbol) {
is StStaticVariable -> sourceSymbol.length!! is StStaticVariable -> sourceSymbol.length!!
is StMemVar -> sourceSymbol.length!! is StMemVar -> sourceSymbol.length!!
else -> 0 else -> 0
@@ -827,8 +826,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) { private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
translateArguments(fcall, scope) translateArguments(fcall, scope)
val dt = fcall.args.single().type when (val dt = fcall.args.single().type) {
when (dt) {
DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A") DataType.UBYTE -> asmgen.out(" jsr prog8_lib.func_sign_ub_into_A")
DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A") DataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A") DataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
@@ -1398,8 +1396,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
private fun outputAddressAndLengthOfArray(arg: PtIdentifier) { private fun outputAddressAndLengthOfArray(arg: PtIdentifier) {
// address goes in P8ZP_SCRATCH_W1, number of elements in A // address goes in P8ZP_SCRATCH_W1, number of elements in A
val symbol = asmgen.symbolTable.lookup(arg.name) val numElements = when(val symbol = asmgen.symbolTable.lookup(arg.name)) {
val numElements = when(symbol) {
is StStaticVariable -> symbol.length!! is StStaticVariable -> symbol.length!!
is StMemVar -> symbol.length!! is StMemVar -> symbol.length!!
else -> 0 else -> 0

View File

@@ -335,8 +335,7 @@ $endLabel""")
val endLabel = asmgen.makeLabel("for_end") val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel) asmgen.loopEndLabels.push(endLabel)
val iterableName = asmgen.asmVariableName(ident) val iterableName = asmgen.asmVariableName(ident)
val symbol = asmgen.symbolTable.lookup(ident.name) val numElements = when(val symbol = asmgen.symbolTable.lookup(ident.name)) {
val numElements = when(symbol) {
is StStaticVariable -> symbol.length!! is StStaticVariable -> symbol.length!!
is StMemVar -> symbol.length!! is StMemVar -> symbol.length!!
else -> 0 else -> 0

View File

@@ -90,7 +90,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
} }
private fun argumentsViaRegisters(sub: PtAsmSub, call: PtFunctionCall) { private fun argumentsViaRegisters(sub: PtAsmSub, call: PtFunctionCall) {
val registersUsed = mutableListOf<RegisterOrStatusflag>(); val registersUsed = mutableListOf<RegisterOrStatusflag>()
fun usedA() = registersUsed.any {it.registerOrPair==RegisterOrPair.A || it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.AY} fun usedA() = registersUsed.any {it.registerOrPair==RegisterOrPair.A || it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.AY}
fun usedX() = registersUsed.any {it.registerOrPair==RegisterOrPair.X || it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.XY} fun usedX() = registersUsed.any {it.registerOrPair==RegisterOrPair.X || it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.XY}

View File

@@ -616,7 +616,7 @@ _jump jmp ($asmLabel)
if(right is PtIdentifier) { if(right is PtIdentifier) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed) asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val variable = asmgen.asmVariableName(right) val variable = asmgen.asmVariableName(right)
return code(variable, variable+"+1") return code(variable, "$variable+1")
} }
// TODO optimize for simple array value // TODO optimize for simple array value
@@ -737,7 +737,7 @@ _jump jmp ($asmLabel)
if(right is PtIdentifier) { if(right is PtIdentifier) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed) asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val variable = asmgen.asmVariableName(right) val variable = asmgen.asmVariableName(right)
return code(variable, variable+"+1") return code(variable, "$variable+1")
} }
// TODO optimize for simple array value // TODO optimize for simple array value
@@ -1514,7 +1514,7 @@ _jump jmp ($asmLabel)
else -> { else -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left) val varname = asmgen.asmVariableName(left)
translateAYNotEquals(varname, varname + "+1") translateAYNotEquals(varname, "$varname+1")
} }
} }
} }
@@ -1562,7 +1562,7 @@ _jump jmp ($asmLabel)
else -> { else -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed) asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left) val varname = asmgen.asmVariableName(left)
translateAYEquals(varname, varname+"+1") translateAYEquals(varname, "$varname+1")
} }
} }
} }

View File

@@ -1703,7 +1703,7 @@ $shortcutLabel:""")
private fun inplacemodificationWordWithLiteralval(name: String, dt: DataType, operator: String, value: Int, block: PtBlock?) { private fun inplacemodificationWordWithLiteralval(name: String, dt: DataType, operator: String, value: Int, block: PtBlock?) {
// note: this contains special optimized cases because we know the exact value. Don't replace this with another routine. // note: this contains special optimized cases because we know the exact value. Don't replace this with another routine.
inplacemodificationSomeWordWithLiteralval(name, name + "+1", dt, operator, value, block) inplacemodificationSomeWordWithLiteralval(name, "$name+1", dt, operator, value, block)
} }
private fun inplacemodificationSomeWordWithLiteralval(lsb: String, msb: String, dt: DataType, operator: String, value: Int, block: PtBlock?) { private fun inplacemodificationSomeWordWithLiteralval(lsb: String, msb: String, dt: DataType, operator: String, value: Int, block: PtBlock?) {

View File

@@ -76,7 +76,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks { internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {
// augmented assignment always has just a single target // augmented assignment always has just a single target
if(augAssign.target.children.single() is PtIrRegister) if (augAssign.target.children.single() is PtIrRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister") throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
val target = augAssign.target val target = augAssign.target
@@ -87,7 +87,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
val array = target.array val array = target.array
val value = augAssign.value val value = augAssign.value
val signed = target.type in SignedDatatypes val signed = target.type in SignedDatatypes
val result = when(augAssign.operator) {
val chunks = when (augAssign.operator) {
"+=" -> operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value) "+=" -> operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value)
"-=" -> operatorMinusInplace(symbol, array, constAddress, memTarget, targetDt, value) "-=" -> operatorMinusInplace(symbol, array, constAddress, memTarget, targetDt, value)
"*=" -> operatorMultiplyInplace(symbol, array, constAddress, memTarget, targetDt, value) "*=" -> operatorMultiplyInplace(symbol, array, constAddress, memTarget, targetDt, value)
@@ -109,9 +110,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
in PrefixOperators -> inplacePrefix(augAssign.operator, symbol, array, constAddress, memTarget, targetDt) in PrefixOperators -> inplacePrefix(augAssign.operator, symbol, array, constAddress, memTarget, targetDt)
else -> throw AssemblyError("invalid augmented assign operator ${augAssign.operator}") else -> throw AssemblyError("invalid augmented assign operator ${augAssign.operator}")
} } ?: fallbackAssign(augAssign)
val chunks = if(result!=null) result else fallbackAssign(augAssign)
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(augAssign.position) chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(augAssign.position)
return chunks return chunks
} }
@@ -140,7 +139,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
return translateRegularAssign(normalAssign) return translateRegularAssign(normalAssign)
} }
private fun inplacePrefix(operator: String, symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType): IRCodeChunks? { private fun inplacePrefix(operator: String, symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType): IRCodeChunks {
if(operator=="+") if(operator=="+")
return emptyList() return emptyList()
@@ -503,9 +502,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
addToResult(result, tr, tr.resultReg, -1) addToResult(result, tr, tr.resultReg, -1)
return Pair(result, tr.resultReg) return Pair(result, tr.resultReg)
} }
val mult: PtExpression = PtBinaryExpression("*", DataType.UBYTE, array.position)
val mult: PtExpression
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
mult.children += array.index mult.children += array.index
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position) mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
val tr = expressionEval.translateExpression(mult) val tr = expressionEval.translateExpression(mult)

View File

@@ -786,17 +786,21 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val tr = translateExpression(binExpr.left) val tr = translateExpression(binExpr.left)
addToResult(result, tr, tr.resultReg, -1) addToResult(result, tr, tr.resultReg, -1)
return if(binExpr.right is PtNumber) { return when (binExpr.right) {
addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt()), null) is PtNumber -> {
ExpressionCodeResult(result, vmDt, tr.resultReg, -1) addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt()), null)
} else if(binExpr.right is PtBool) { ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtBool).asInt()), null) }
ExpressionCodeResult(result, vmDt, tr.resultReg, -1) is PtBool -> {
} else { addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtBool).asInt()), null)
val rightTr = translateExpression(binExpr.right) ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
addToResult(result, rightTr, rightTr.resultReg, -1) }
addInstr(result, IRInstruction(Opcode.XORR, vmDt, reg1 = tr.resultReg, reg2 = rightTr.resultReg), null) else -> {
ExpressionCodeResult(result, vmDt, tr.resultReg, -1) val rightTr = translateExpression(binExpr.right)
addToResult(result, rightTr, rightTr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.XORR, vmDt, reg1 = tr.resultReg, reg2 = rightTr.resultReg), null)
ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
}
} }
} }

View File

@@ -52,9 +52,6 @@ class IRCodeGen(
optimizer.optimize(options.optimize, errors) optimizer.optimize(options.optimize, errors)
irProg.validate() irProg.validate()
val regOptimizer = IRRegisterOptimizer(irProg)
regOptimizer.optimize()
return irProg return irProg
} }

View File

@@ -179,8 +179,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
chunks += sub.chunks[0] chunks += sub.chunks[0]
for(ix in 1 until sub.chunks.size) { for(ix in 1 until sub.chunks.size) {
val lastChunk = chunks.last() val lastChunk = chunks.last()
val candidate = sub.chunks[ix] when(val candidate = sub.chunks[ix]) {
when(candidate) {
is IRCodeChunk -> { is IRCodeChunk -> {
if(mayJoinCodeChunks(lastChunk, candidate)) { if(mayJoinCodeChunks(lastChunk, candidate)) {
lastChunk.instructions += candidate.instructions lastChunk.instructions += candidate.instructions

View File

@@ -1,103 +0,0 @@
package prog8.codegen.intermediate
import prog8.intermediate.IRProgram
class IRRegisterOptimizer(private val irProg: IRProgram) {
fun optimize() {
// reuseRegisters()
}
/*
TODO: this register re-use renumbering isn't going to work like this,
because subroutines will be clobbering the registers that the subroutine
which is calling them might be using...
private fun reuseRegisters() {
fun addToUsage(usage: MutableMap<Pair<Int, IRDataType>, MutableSet<IRCodeChunkBase>>,
regnum: Int,
dt: IRDataType,
chunk: IRCodeChunkBase) {
val key = regnum to dt
val chunks = usage[key] ?: mutableSetOf()
chunks.add(chunk)
usage[key] = chunks
}
val usage: MutableMap<Pair<Int, IRDataType>, MutableSet<IRCodeChunkBase>> = mutableMapOf()
irProg.foreachCodeChunk { chunk ->
chunk.usedRegisters().regsTypes.forEach { (regNum, types) ->
types.forEach { dt ->
addToUsage(usage, regNum, dt, chunk)
}
}
}
val registerReplacements = usage.asSequence()
.filter { it.value.size==1 }
.map { it.key to it.value.iterator().next() }
.groupBy({ it.second }, {it.first})
.asSequence()
.associate { (chunk, registers) ->
chunk to registers.withIndex().associate { (index, reg) -> reg to 50000+index }
}
registerReplacements.forEach { replaceRegisters(it.key, it.value) }
}
private fun replaceRegisters(chunk: IRCodeChunkBase, replacements: Map<Pair<Int, IRDataType>, Int>) {
val (rF, rI) = replacements.asSequence().partition { it.key.second==IRDataType.FLOAT }
val replacementsInt = rI.associate { it.key.first to it.value }
val replacementsFloat = rF.associate { it.key.first to it.value }
fun replaceRegs(fcallArgs: FunctionCallArgs?): FunctionCallArgs? {
if(fcallArgs==null)
return null
val args = if(fcallArgs.arguments.isEmpty()) fcallArgs.arguments else {
fcallArgs.arguments.map {
FunctionCallArgs.ArgumentSpec(
it.name,
it.address,
FunctionCallArgs.RegSpec(
it.reg.dt,
if(it.reg.dt==IRDataType.FLOAT)
replacementsFloat.getOrDefault(it.reg.registerNum, it.reg.registerNum)
else
replacementsInt.getOrDefault(it.reg.registerNum, it.reg.registerNum),
it.reg.cpuRegister
)
)
}
}
val rt = fcallArgs.returns
val returns = if(rt==null) null else {
FunctionCallArgs.RegSpec(
rt.dt,
if(rt.dt==IRDataType.FLOAT)
replacementsFloat.getOrDefault(rt.registerNum, rt.registerNum)
else
replacementsInt.getOrDefault(rt.registerNum, rt.registerNum),
rt.cpuRegister
)
}
return FunctionCallArgs(args, returns)
}
fun replaceRegs(instruction: IRInstruction): IRInstruction {
val reg1 = replacementsInt.getOrDefault(instruction.reg1, instruction.reg1)
val reg2 = replacementsInt.getOrDefault(instruction.reg2, instruction.reg2)
val fpReg1 = replacementsFloat.getOrDefault(instruction.fpReg1, instruction.fpReg1)
val fpReg2 = replacementsFloat.getOrDefault(instruction.fpReg2, instruction.fpReg2)
return instruction.copy(reg1 = reg1, reg2 = reg2, fpReg1 = fpReg1, fpReg2 = fpReg2, fcallArgs = replaceRegs(instruction.fcallArgs))
}
val newInstructions = chunk.instructions.map {
replaceRegs(it)
}
chunk.instructions.clear()
chunk.instructions.addAll(newInstructions)
}
*/
}

View File

@@ -939,7 +939,7 @@ internal class AstChecker(private val program: Program,
err("this directive may only occur at module level") err("this directive may only occur at module level")
val allowedEncodings = Encoding.entries.map {it.prefix} val allowedEncodings = Encoding.entries.map {it.prefix}
if(directive.args.size!=1 || directive.args[0].name !in allowedEncodings) if(directive.args.size!=1 || directive.args[0].name !in allowedEncodings)
err("invalid encoding directive, expected one of ${allowedEncodings}") err("invalid encoding directive, expected one of $allowedEncodings")
} }
else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position) else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)
} }

View File

@@ -332,8 +332,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
private fun afterFunctionCallArgs(call: IFunctionCall): Iterable<IAstModification> { private fun afterFunctionCallArgs(call: IFunctionCall): Iterable<IAstModification> {
// see if a typecast is needed to convert the arguments into the required parameter type // see if a typecast is needed to convert the arguments into the required parameter type
val modifications = mutableListOf<IAstModification>() val modifications = mutableListOf<IAstModification>()
val sub = call.target.targetStatement(program) val params = when(val sub = call.target.targetStatement(program)) {
val params = when(sub) {
is BuiltinFunctionPlaceholder -> BuiltinFunctions.getValue(sub.name).parameters is BuiltinFunctionPlaceholder -> BuiltinFunctions.getValue(sub.name).parameters
is Subroutine -> sub.parameters.map { FParam(it.name, listOf(it.type).toTypedArray()) } is Subroutine -> sub.parameters.map { FParam(it.name, listOf(it.type).toTypedArray()) }
else -> emptyList() else -> emptyList()

View File

@@ -205,18 +205,20 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
} }
fun checkArray(variable: VarDecl): Iterable<IAstModification> { fun checkArray(variable: VarDecl): Iterable<IAstModification> {
return if(variable.value==null) { return when (variable.value) {
val arraySpec = variable.arraysize!! null -> {
val size = arraySpec.indexExpr.constValue(program)?.number?.toInt() ?: throw FatalAstException("no array size") val arraySpec = variable.arraysize!!
return if(size==0) val size = arraySpec.indexExpr.constValue(program)?.number?.toInt() ?: throw FatalAstException("no array size")
replaceWithFalse() return if(size==0)
else replaceWithFalse()
noModifications else
noModifications
}
is ArrayLiteral -> {
checkArray((variable.value as ArrayLiteral).value)
}
else -> noModifications
} }
else if(variable.value is ArrayLiteral) {
checkArray((variable.value as ArrayLiteral).value)
}
else noModifications
} }
fun checkString(stringVal: StringLiteral): Iterable<IAstModification> { fun checkString(stringVal: StringLiteral): Iterable<IAstModification> {

View File

@@ -93,7 +93,6 @@ class Block(override val name: String,
override fun referencesIdentifier(nameInSource: List<String>): Boolean = statements.any { it.referencesIdentifier(nameInSource) } override fun referencesIdentifier(nameInSource: List<String>): Boolean = statements.any { it.referencesIdentifier(nameInSource) }
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet() fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet()
fun renamed(newName: String): Block = Block(newName, address, statements, isInLibrary, position)
} }
data class Directive(val directive: String, val args: List<DirectiveArg>, override val position: Position) : Statement() { data class Directive(val directive: String, val args: List<DirectiveArg>, override val position: Position) : Statement() {

View File

@@ -70,10 +70,10 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
when(child) { when(child) {
is IRAsmSubroutine -> { is IRAsmSubroutine -> {
val clobbers = child.clobbers.joinToString(",") val clobbers = child.clobbers.joinToString(",")
val returns = child.returns.map { ret -> val returns = child.returns.joinToString(",") { ret ->
if(ret.reg.registerOrPair!=null) "${ret.reg.registerOrPair}:${ret.dt.toString().lowercase()}" if (ret.reg.registerOrPair != null) "${ret.reg.registerOrPair}:${ret.dt.toString().lowercase()}"
else "${ret.reg.statusflag}:${ret.dt.toString().lowercase()}" else "${ret.reg.statusflag}:${ret.dt.toString().lowercase()}"
}.joinToString(",") }
xml.writeStartElement("ASMSUB") xml.writeStartElement("ASMSUB")
xml.writeAttribute("NAME", child.label) xml.writeAttribute("NAME", child.label)
xml.writeAttribute("ADDRESS", child.address?.toHex() ?: "") xml.writeAttribute("ADDRESS", child.address?.toHex() ?: "")

View File

@@ -213,8 +213,7 @@ class IRProgram(val name: String,
chunk.instructions.withIndex().forEach { (index, instr) -> chunk.instructions.withIndex().forEach { (index, instr) ->
if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) { if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) {
if(instr.opcode==Opcode.JUMPI) { if(instr.opcode==Opcode.JUMPI) {
val pointervar = st.lookup(instr.labelSymbol)!! when(val pointervar = st.lookup(instr.labelSymbol)!!) {
when(pointervar) {
is IRStStaticVariable -> require(pointervar.dt==DataType.UWORD) is IRStStaticVariable -> require(pointervar.dt==DataType.UWORD)
is IRStMemVar -> require(pointervar.dt==DataType.UWORD) is IRStMemVar -> require(pointervar.dt==DataType.UWORD)
else -> throw AssemblyError("weird pointervar type") else -> throw AssemblyError("weird pointervar type")

View File

@@ -6,7 +6,7 @@ import kotlin.random.Random
* 64 Kb of random access memory. Initialized to random values. * 64 Kb of random access memory. Initialized to random values.
*/ */
class Memory { class Memory {
private val mem = Array<UByte>(64 * 1024) { Random.nextInt().toUByte() } private val mem = Array(64 * 1024) { Random.nextInt().toUByte() }
fun reset() { fun reset() {
mem.fill(0u) mem.fill(0u)

View File

@@ -142,8 +142,7 @@ enum class Syscall {
; ;
companion object { companion object {
private val VALUES = values() fun fromInt(value: Int) = entries[value]
fun fromInt(value: Int) = VALUES[value]
} }
} }
@@ -657,7 +656,7 @@ object SysCalls {
val addr = (addrA as UShort).toInt() val addr = (addrA as UShort).toInt()
if(File(filename).exists()) { if(File(filename).exists()) {
val data = File(filename).readBytes() val data = File(filename).readBytes()
for (i in 0..<data.size) { for (i in data.indices) {
vm.memory.setUB(addr + i, data[i].toUByte()) vm.memory.setUB(addr + i, data[i].toUByte())
} }
returnValue(callspec.returns.single(), (addr + data.size).toUShort(), vm) returnValue(callspec.returns.single(), (addr + data.size).toUShort(), vm)

View File

@@ -56,7 +56,7 @@ class VirtualMachine(irProgram: IRProgram) {
val (prg, labelAddr) = VmProgramLoader().load(irProgram, memory) val (prg, labelAddr) = VmProgramLoader().load(irProgram, memory)
program = prg program = prg
artificialLabelAddresses = mutableMapOf() artificialLabelAddresses = mutableMapOf()
labelAddr.forEach { labelname, artificialAddress -> labelAddr.forEach { (labelname, artificialAddress) ->
artificialLabelAddresses[artificialAddress] = program.single { it.label==labelname } artificialLabelAddresses[artificialAddress] = program.single { it.label==labelname }
} }
require(irProgram.st.getAsmSymbols().isEmpty()) { "virtual machine can't yet process asmsymbols defined on command line" } require(irProgram.st.getAsmSymbols().isEmpty()) { "virtual machine can't yet process asmsymbols defined on command line" }

View File

@@ -251,7 +251,7 @@ class VmProgramLoader {
} }
} }
variable.onetimeInitializationArrayValue?.let { iElts -> variable.onetimeInitializationArrayValue?.let { iElts ->
require(variable.length==iElts.size || iElts.size==1 || iElts.size==0) require(variable.length==iElts.size || iElts.size==1 || iElts.isEmpty())
if(iElts.isEmpty() || iElts.size==1) { if(iElts.isEmpty() || iElts.size==1) {
val iElt = if(iElts.isEmpty()) { val iElt = if(iElts.isEmpty()) {
require(variable.uninitialized) require(variable.uninitialized)
@@ -322,7 +322,7 @@ class VmProgramLoader {
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
for (elt in iElts) { for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toDouble() val value = getInitializerValue(variable.dt, elt, symbolAddresses)
memory.setFloat(address, value) memory.setFloat(address, value)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE address += program.options.compTarget.machine.FLOAT_MEM_SIZE
} }
@@ -386,7 +386,7 @@ class VmProgramLoader {
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toDouble() val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
repeat(variable.length!!) { repeat(variable.length!!) {
memory.setFloat(address, value) memory.setFloat(address, value)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE address += program.options.compTarget.machine.FLOAT_MEM_SIZE