mirror of
https://github.com/irmen/prog8.git
synced 2025-08-15 14:27:37 +00:00
cleanups
This commit is contained in:
@@ -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
|
||||||
|
@@ -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)
|
||||||
|
@@ -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()}"
|
||||||
|
@@ -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()} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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}
|
||||||
|
@@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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?) {
|
||||||
|
@@ -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)
|
||||||
|
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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")
|
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)
|
||||||
}
|
}
|
||||||
|
@@ -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()
|
||||||
|
@@ -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> {
|
||||||
|
@@ -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() {
|
||||||
|
@@ -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() ?: "")
|
||||||
|
@@ -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")
|
||||||
|
@@ -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)
|
||||||
|
@@ -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)
|
||||||
|
@@ -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" }
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user