mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
cleanups
This commit is contained in:
parent
3ef5bdfeda
commit
4a710ecdfc
@ -82,8 +82,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
|
||||
override fun lookup(scopedName: String) = flat[scopedName]
|
||||
|
||||
fun getLength(name: String): Int? {
|
||||
val node = flat[name]
|
||||
return when(node) {
|
||||
return when(val node = flat[name]) {
|
||||
is StMemVar -> node.length
|
||||
is StMemorySlab -> node.size.toInt()
|
||||
is StStaticVariable -> node.length
|
||||
|
@ -230,7 +230,7 @@ class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.BOO
|
||||
|
||||
companion object {
|
||||
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)
|
||||
|
@ -63,18 +63,18 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
"???"
|
||||
}
|
||||
is PtAsmSub -> {
|
||||
val params = node.parameters.map {
|
||||
val register = it.first.registerOrPair
|
||||
val statusflag = it.first.statusflag
|
||||
"${it.second.type} ${it.second.name} @${register ?: statusflag}"
|
||||
}.joinToString(", ")
|
||||
val params = node.parameters.joinToString(", ") {
|
||||
val register = it.first.registerOrPair
|
||||
val statusflag = it.first.statusflag
|
||||
"${it.second.type} ${it.second.name} @${register ?: statusflag}"
|
||||
}
|
||||
val clobbers = if (node.clobbers.isEmpty()) "" else "clobbers ${node.clobbers}"
|
||||
val returns = if (node.returns.isEmpty()) "" else {
|
||||
"-> ${node.returns.map {
|
||||
val register = it.first.registerOrPair
|
||||
val statusflag = it.first.statusflag
|
||||
"${it.second} @${register ?: statusflag}"}
|
||||
.joinToString(", ")
|
||||
"-> ${node.returns.joinToString(", ") {
|
||||
val register = it.first.registerOrPair
|
||||
val statusflag = it.first.statusflag
|
||||
"${it.second} @${register ?: statusflag}"
|
||||
}
|
||||
}"
|
||||
}
|
||||
val str = if (node.inline) "inline " else ""
|
||||
@ -108,7 +108,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||
}
|
||||
}
|
||||
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) "
|
||||
if(node.returntype!=null)
|
||||
str += "-> ${node.returntype.name.lowercase()}"
|
||||
|
@ -78,7 +78,7 @@ enum class RegisterOrPair {
|
||||
R8, R9, R10, R11, R12, R13, R14, R15;
|
||||
|
||||
companion object {
|
||||
val names by lazy { values().map { it.toString()} }
|
||||
val names by lazy { entries.map { it.toString()} }
|
||||
fun fromCpuRegister(cpu: CpuRegister): RegisterOrPair {
|
||||
return when(cpu) {
|
||||
CpuRegister.A -> A
|
||||
@ -104,7 +104,7 @@ enum class Statusflag {
|
||||
Pn; // don't use
|
||||
|
||||
companion object {
|
||||
val names by lazy { values().map { it.toString()} }
|
||||
val names by lazy { entries.map { it.toString()} }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,8 +100,7 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend {
|
||||
}
|
||||
|
||||
nodesToPrefix.forEach { (parent, index) ->
|
||||
val node = parent.children[index]
|
||||
when(node) {
|
||||
when(val node = parent.children[index]) {
|
||||
is PtIdentifier -> parent.children[index] = node.prefix(parent, st)
|
||||
is PtFunctionCall -> throw AssemblyError("PtFunctionCall should be processed in their own list, last")
|
||||
is PtJump -> parent.children[index] = node.prefix(parent, st)
|
||||
@ -247,7 +246,7 @@ class AsmGen6502Internal (
|
||||
|
||||
if(errors.noErrors()) {
|
||||
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) {
|
||||
scanInvalid65816instructions(asmLines)
|
||||
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) {
|
||||
val signed = value.type.oneOf(DataType.BYTE, DataType.WORD)
|
||||
if(dt in ByteDatatypesWithBoolean) {
|
||||
|
@ -82,8 +82,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
val source = fcall.args[0] as PtIdentifier
|
||||
val target = fcall.args[1] as PtIdentifier
|
||||
|
||||
val sourceSymbol = asmgen.symbolTable.lookup(source.name)
|
||||
val numElements = when(sourceSymbol) {
|
||||
val numElements = when(val sourceSymbol = asmgen.symbolTable.lookup(source.name)) {
|
||||
is StStaticVariable -> sourceSymbol.length!!
|
||||
is StMemVar -> sourceSymbol.length!!
|
||||
else -> 0
|
||||
@ -827,8 +826,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
|
||||
private fun funcSgn(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, scope: IPtSubroutine?) {
|
||||
translateArguments(fcall, scope)
|
||||
val dt = fcall.args.single().type
|
||||
when (dt) {
|
||||
when (val dt = fcall.args.single().type) {
|
||||
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.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) {
|
||||
// address goes in P8ZP_SCRATCH_W1, number of elements in A
|
||||
val symbol = asmgen.symbolTable.lookup(arg.name)
|
||||
val numElements = when(symbol) {
|
||||
val numElements = when(val symbol = asmgen.symbolTable.lookup(arg.name)) {
|
||||
is StStaticVariable -> symbol.length!!
|
||||
is StMemVar -> symbol.length!!
|
||||
else -> 0
|
||||
|
@ -335,8 +335,7 @@ $endLabel""")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
asmgen.loopEndLabels.push(endLabel)
|
||||
val iterableName = asmgen.asmVariableName(ident)
|
||||
val symbol = asmgen.symbolTable.lookup(ident.name)
|
||||
val numElements = when(symbol) {
|
||||
val numElements = when(val symbol = asmgen.symbolTable.lookup(ident.name)) {
|
||||
is StStaticVariable -> symbol.length!!
|
||||
is StMemVar -> symbol.length!!
|
||||
else -> 0
|
||||
|
@ -90,7 +90,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
|
||||
}
|
||||
|
||||
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 usedX() = registersUsed.any {it.registerOrPair==RegisterOrPair.X || it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.XY}
|
||||
|
@ -616,7 +616,7 @@ _jump jmp ($asmLabel)
|
||||
if(right is PtIdentifier) {
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
|
||||
val variable = asmgen.asmVariableName(right)
|
||||
return code(variable, variable+"+1")
|
||||
return code(variable, "$variable+1")
|
||||
}
|
||||
|
||||
// TODO optimize for simple array value
|
||||
@ -737,7 +737,7 @@ _jump jmp ($asmLabel)
|
||||
if(right is PtIdentifier) {
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
|
||||
val variable = asmgen.asmVariableName(right)
|
||||
return code(variable, variable+"+1")
|
||||
return code(variable, "$variable+1")
|
||||
}
|
||||
|
||||
// TODO optimize for simple array value
|
||||
@ -1514,7 +1514,7 @@ _jump jmp ($asmLabel)
|
||||
else -> {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
val varname = asmgen.asmVariableName(left)
|
||||
translateAYNotEquals(varname, varname + "+1")
|
||||
translateAYNotEquals(varname, "$varname+1")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1562,7 +1562,7 @@ _jump jmp ($asmLabel)
|
||||
else -> {
|
||||
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
|
||||
val varname = asmgen.asmVariableName(left)
|
||||
translateAYEquals(varname, varname+"+1")
|
||||
translateAYEquals(varname, "$varname+1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1703,7 +1703,7 @@ $shortcutLabel:""")
|
||||
|
||||
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.
|
||||
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?) {
|
||||
|
@ -76,7 +76,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
|
||||
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {
|
||||
// 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")
|
||||
|
||||
val target = augAssign.target
|
||||
@ -87,7 +87,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
val array = target.array
|
||||
val value = augAssign.value
|
||||
val signed = target.type in SignedDatatypes
|
||||
val result = when(augAssign.operator) {
|
||||
|
||||
val chunks = when (augAssign.operator) {
|
||||
"+=" -> operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
||||
"-=" -> operatorMinusInplace(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)
|
||||
|
||||
else -> throw AssemblyError("invalid augmented assign operator ${augAssign.operator}")
|
||||
}
|
||||
|
||||
val chunks = if(result!=null) result else fallbackAssign(augAssign)
|
||||
} ?: fallbackAssign(augAssign)
|
||||
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(augAssign.position)
|
||||
return chunks
|
||||
}
|
||||
@ -140,7 +139,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
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=="+")
|
||||
return emptyList()
|
||||
|
||||
@ -503,9 +502,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
return Pair(result, tr.resultReg)
|
||||
}
|
||||
|
||||
val mult: PtExpression
|
||||
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
val mult: PtExpression = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
||||
mult.children += array.index
|
||||
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
||||
val tr = expressionEval.translateExpression(mult)
|
||||
|
@ -786,17 +786,21 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = translateExpression(binExpr.left)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
return if(binExpr.right is PtNumber) {
|
||||
addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt()), null)
|
||||
ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
|
||||
} else if(binExpr.right is PtBool) {
|
||||
addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtBool).asInt()), null)
|
||||
ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
|
||||
} else {
|
||||
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)
|
||||
return when (binExpr.right) {
|
||||
is PtNumber -> {
|
||||
addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtNumber).number.toInt()), null)
|
||||
ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
|
||||
}
|
||||
is PtBool -> {
|
||||
addInstr(result, IRInstruction(Opcode.XOR, vmDt, reg1 = tr.resultReg, immediate = (binExpr.right as PtBool).asInt()), null)
|
||||
ExpressionCodeResult(result, vmDt, tr.resultReg, -1)
|
||||
}
|
||||
else -> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,9 +52,6 @@ class IRCodeGen(
|
||||
optimizer.optimize(options.optimize, errors)
|
||||
irProg.validate()
|
||||
|
||||
val regOptimizer = IRRegisterOptimizer(irProg)
|
||||
regOptimizer.optimize()
|
||||
|
||||
return irProg
|
||||
}
|
||||
|
||||
|
@ -179,8 +179,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
chunks += sub.chunks[0]
|
||||
for(ix in 1 until sub.chunks.size) {
|
||||
val lastChunk = chunks.last()
|
||||
val candidate = sub.chunks[ix]
|
||||
when(candidate) {
|
||||
when(val candidate = sub.chunks[ix]) {
|
||||
is IRCodeChunk -> {
|
||||
if(mayJoinCodeChunks(lastChunk, candidate)) {
|
||||
lastChunk.instructions += candidate.instructions
|
||||
|
@ -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)
|
||||
}
|
||||
*/
|
||||
}
|
@ -939,7 +939,7 @@ internal class AstChecker(private val program: Program,
|
||||
err("this directive may only occur at module level")
|
||||
val allowedEncodings = Encoding.entries.map {it.prefix}
|
||||
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)
|
||||
}
|
||||
|
@ -332,8 +332,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
||||
private fun afterFunctionCallArgs(call: IFunctionCall): Iterable<IAstModification> {
|
||||
// see if a typecast is needed to convert the arguments into the required parameter type
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
val sub = call.target.targetStatement(program)
|
||||
val params = when(sub) {
|
||||
val params = when(val sub = call.target.targetStatement(program)) {
|
||||
is BuiltinFunctionPlaceholder -> BuiltinFunctions.getValue(sub.name).parameters
|
||||
is Subroutine -> sub.parameters.map { FParam(it.name, listOf(it.type).toTypedArray()) }
|
||||
else -> emptyList()
|
||||
|
@ -205,18 +205,20 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
}
|
||||
|
||||
fun checkArray(variable: VarDecl): Iterable<IAstModification> {
|
||||
return if(variable.value==null) {
|
||||
val arraySpec = variable.arraysize!!
|
||||
val size = arraySpec.indexExpr.constValue(program)?.number?.toInt() ?: throw FatalAstException("no array size")
|
||||
return if(size==0)
|
||||
replaceWithFalse()
|
||||
else
|
||||
noModifications
|
||||
return when (variable.value) {
|
||||
null -> {
|
||||
val arraySpec = variable.arraysize!!
|
||||
val size = arraySpec.indexExpr.constValue(program)?.number?.toInt() ?: throw FatalAstException("no array size")
|
||||
return if(size==0)
|
||||
replaceWithFalse()
|
||||
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> {
|
||||
|
@ -93,7 +93,6 @@ class Block(override val name: String,
|
||||
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 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() {
|
||||
|
@ -70,10 +70,10 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
when(child) {
|
||||
is IRAsmSubroutine -> {
|
||||
val clobbers = child.clobbers.joinToString(",")
|
||||
val returns = child.returns.map { ret ->
|
||||
if(ret.reg.registerOrPair!=null) "${ret.reg.registerOrPair}:${ret.dt.toString().lowercase()}"
|
||||
val returns = child.returns.joinToString(",") { ret ->
|
||||
if (ret.reg.registerOrPair != null) "${ret.reg.registerOrPair}:${ret.dt.toString().lowercase()}"
|
||||
else "${ret.reg.statusflag}:${ret.dt.toString().lowercase()}"
|
||||
}.joinToString(",")
|
||||
}
|
||||
xml.writeStartElement("ASMSUB")
|
||||
xml.writeAttribute("NAME", child.label)
|
||||
xml.writeAttribute("ADDRESS", child.address?.toHex() ?: "")
|
||||
|
@ -213,8 +213,7 @@ class IRProgram(val name: String,
|
||||
chunk.instructions.withIndex().forEach { (index, instr) ->
|
||||
if(instr.labelSymbol!=null && instr.opcode in OpcodesThatBranch) {
|
||||
if(instr.opcode==Opcode.JUMPI) {
|
||||
val pointervar = st.lookup(instr.labelSymbol)!!
|
||||
when(pointervar) {
|
||||
when(val pointervar = st.lookup(instr.labelSymbol)!!) {
|
||||
is IRStStaticVariable -> require(pointervar.dt==DataType.UWORD)
|
||||
is IRStMemVar -> require(pointervar.dt==DataType.UWORD)
|
||||
else -> throw AssemblyError("weird pointervar type")
|
||||
|
@ -6,7 +6,7 @@ import kotlin.random.Random
|
||||
* 64 Kb of random access memory. Initialized to random values.
|
||||
*/
|
||||
class Memory {
|
||||
private val mem = Array<UByte>(64 * 1024) { Random.nextInt().toUByte() }
|
||||
private val mem = Array(64 * 1024) { Random.nextInt().toUByte() }
|
||||
|
||||
fun reset() {
|
||||
mem.fill(0u)
|
||||
|
@ -142,8 +142,7 @@ enum class Syscall {
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val VALUES = values()
|
||||
fun fromInt(value: Int) = VALUES[value]
|
||||
fun fromInt(value: Int) = entries[value]
|
||||
}
|
||||
}
|
||||
|
||||
@ -657,7 +656,7 @@ object SysCalls {
|
||||
val addr = (addrA as UShort).toInt()
|
||||
if(File(filename).exists()) {
|
||||
val data = File(filename).readBytes()
|
||||
for (i in 0..<data.size) {
|
||||
for (i in data.indices) {
|
||||
vm.memory.setUB(addr + i, data[i].toUByte())
|
||||
}
|
||||
returnValue(callspec.returns.single(), (addr + data.size).toUShort(), vm)
|
||||
|
@ -56,7 +56,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
val (prg, labelAddr) = VmProgramLoader().load(irProgram, memory)
|
||||
program = prg
|
||||
artificialLabelAddresses = mutableMapOf()
|
||||
labelAddr.forEach { labelname, artificialAddress ->
|
||||
labelAddr.forEach { (labelname, artificialAddress) ->
|
||||
artificialLabelAddresses[artificialAddress] = program.single { it.label==labelname }
|
||||
}
|
||||
require(irProgram.st.getAsmSymbols().isEmpty()) { "virtual machine can't yet process asmsymbols defined on command line" }
|
||||
|
@ -251,7 +251,7 @@ class VmProgramLoader {
|
||||
}
|
||||
}
|
||||
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) {
|
||||
val iElt = if(iElts.isEmpty()) {
|
||||
require(variable.uninitialized)
|
||||
@ -322,7 +322,7 @@ class VmProgramLoader {
|
||||
|
||||
DataType.ARRAY_F -> {
|
||||
for (elt in iElts) {
|
||||
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toDouble()
|
||||
val value = getInitializerValue(variable.dt, elt, symbolAddresses)
|
||||
memory.setFloat(address, value)
|
||||
address += program.options.compTarget.machine.FLOAT_MEM_SIZE
|
||||
}
|
||||
@ -386,7 +386,7 @@ class VmProgramLoader {
|
||||
}
|
||||
|
||||
DataType.ARRAY_F -> {
|
||||
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toDouble()
|
||||
val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
|
||||
repeat(variable.length!!) {
|
||||
memory.setFloat(address, value)
|
||||
address += program.options.compTarget.machine.FLOAT_MEM_SIZE
|
||||
|
Loading…
x
Reference in New Issue
Block a user