mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
kotlin 1.7.20
This commit is contained in:
parent
7c1bdfe713
commit
43e31765e5
@ -117,15 +117,15 @@ internal class SymbolTableMaker: IAstVisitor {
|
||||
// st.origAstLinks[label] = node
|
||||
}
|
||||
|
||||
override fun visit(fcall: BuiltinFunctionCall) {
|
||||
if(fcall.name=="memory") {
|
||||
override fun visit(bfc: BuiltinFunctionCall) {
|
||||
if(bfc.name=="memory") {
|
||||
// memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable
|
||||
val name = (fcall.args[0] as StringLiteral).value
|
||||
val name = (bfc.args[0] as StringLiteral).value
|
||||
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||
val size = (fcall.args[1] as NumericLiteral).number.toUInt()
|
||||
val align = (fcall.args[2] as NumericLiteral).number.toUInt()
|
||||
st.add(StMemorySlab("prog8_memoryslab_$name", size, align, fcall.position))
|
||||
val size = (bfc.args[1] as NumericLiteral).number.toUInt()
|
||||
val align = (bfc.args[2] as NumericLiteral).number.toUInt()
|
||||
st.add(StMemorySlab("prog8_memoryslab_$name", size, align, bfc.position))
|
||||
}
|
||||
super.visit(fcall)
|
||||
super.visit(bfc)
|
||||
}
|
||||
}
|
||||
|
@ -4,4 +4,4 @@ org.gradle.parallel=true
|
||||
org.gradle.daemon=true
|
||||
kotlin.code.style=official
|
||||
javaVersion=11
|
||||
kotlinVersion=1.7.10
|
||||
kotlinVersion=1.7.20
|
@ -55,6 +55,7 @@ class IRFileReader {
|
||||
val zpReserved = mutableListOf<UIntRange>()
|
||||
var loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||
var dontReinitGlobals = false
|
||||
var optimize = true
|
||||
var evalStackBaseAddress: UInt? = null
|
||||
var outputDir = Path("")
|
||||
if(line!="<OPTIONS>")
|
||||
@ -86,6 +87,7 @@ class IRFileReader {
|
||||
zpReserved.add(UIntRange(start.toUInt(), end.toUInt()))
|
||||
}
|
||||
"outputDir" -> outputDir = Path(value)
|
||||
"optimize" -> optimize = value.toBoolean()
|
||||
else -> throw IRParseException("illegal OPTION $name")
|
||||
}
|
||||
}
|
||||
@ -101,7 +103,8 @@ class IRFileReader {
|
||||
loadAddress,
|
||||
dontReinitGlobals = dontReinitGlobals,
|
||||
evalStackBaseAddress = evalStackBaseAddress,
|
||||
outputDir = outputDir
|
||||
outputDir = outputDir,
|
||||
optimize = optimize
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
out.write("zpReserved=${range.first},${range.last}\n")
|
||||
}
|
||||
out.write("loadAddress=${irProgram.options.loadAddress}\n")
|
||||
out.write("optimize=${irProgram.options.optimize}\n")
|
||||
out.write("dontReinitGlobals=${irProgram.options.dontReinitGlobals}\n")
|
||||
out.write("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress}\n")
|
||||
out.write("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
|
||||
|
@ -57,8 +57,8 @@ syscall value - do a systemcall identified by call numbe
|
||||
return - restore last saved instruction location and continue at that instruction
|
||||
|
||||
|
||||
BRANCHING
|
||||
---------
|
||||
BRANCHING and CONDITIONALS
|
||||
--------------------------
|
||||
All have type b or w except the branches that only check status bits.
|
||||
|
||||
bstcc address - branch to location if Status bit Carry is Clear
|
||||
@ -402,6 +402,29 @@ val OpcodesWithAddress = setOf(
|
||||
Opcode.BGES
|
||||
)
|
||||
|
||||
val OpcodesThatBranch = setOf(
|
||||
Opcode.JUMP,
|
||||
Opcode.RETURN,
|
||||
Opcode.BSTCC,
|
||||
Opcode.BSTCS,
|
||||
Opcode.BSTEQ,
|
||||
Opcode.BSTNE,
|
||||
Opcode.BSTNEG,
|
||||
Opcode.BSTPOS,
|
||||
Opcode.BZ,
|
||||
Opcode.BNZ,
|
||||
Opcode.BEQ,
|
||||
Opcode.BNE,
|
||||
Opcode.BLT,
|
||||
Opcode.BLTS,
|
||||
Opcode.BGT,
|
||||
Opcode.BGTS,
|
||||
Opcode.BLE,
|
||||
Opcode.BLES,
|
||||
Opcode.BGE,
|
||||
Opcode.BGES
|
||||
)
|
||||
|
||||
val OpcodesForCpuRegisters = setOf(
|
||||
Opcode.LOADCPU,
|
||||
Opcode.STORECPU,
|
||||
@ -416,122 +439,6 @@ enum class VmDataType {
|
||||
// TODO add INT (32-bit)? INT24 (24-bit)?
|
||||
}
|
||||
|
||||
data class IRInstruction(
|
||||
val opcode: Opcode,
|
||||
val type: VmDataType?=null,
|
||||
val reg1: Int?=null, // 0-$ffff
|
||||
val reg2: Int?=null, // 0-$ffff
|
||||
val fpReg1: Int?=null, // 0-$ffff
|
||||
val fpReg2: Int?=null, // 0-$ffff
|
||||
val value: Int?=null, // 0-$ffff
|
||||
val fpValue: Float?=null,
|
||||
val labelSymbol: String?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
||||
val binaryData: Collection<UByte>?=null
|
||||
): IRCodeLine() {
|
||||
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
|
||||
// This knowledge is useful in IL assembly optimizers to see how registers are used.
|
||||
val reg1direction: OperandDirection
|
||||
val fpReg1direction: OperandDirection
|
||||
|
||||
init {
|
||||
require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"}
|
||||
require(reg1==null || reg1 in 0..65536) {"reg1 out of bounds"}
|
||||
require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"}
|
||||
require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"}
|
||||
require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
|
||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||
when (type) {
|
||||
VmDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}
|
||||
VmDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"}
|
||||
VmDataType.FLOAT, null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
require((opcode==Opcode.BINARYDATA && binaryData!=null) || (opcode!=Opcode.BINARYDATA && binaryData==null)) {
|
||||
"binarydata inconsistency"
|
||||
}
|
||||
|
||||
val formats = instructionFormats.getValue(opcode)
|
||||
require (type != null || formats.containsKey(null)) { "missing type" }
|
||||
|
||||
val format = formats.getValue(type)
|
||||
if(format.reg1) require(reg1!=null) { "missing reg1" }
|
||||
if(format.reg2) require(reg2!=null) { "missing reg2" }
|
||||
if(format.fpReg1) require(fpReg1!=null) { "missing fpReg1" }
|
||||
if(format.fpReg2) require(fpReg2!=null) { "missing fpReg2" }
|
||||
if(!format.reg1) require(reg1==null) { "invalid reg1" }
|
||||
if(!format.reg2) require(reg2==null) { "invalid reg2" }
|
||||
if(!format.fpReg1) require(fpReg1==null) { "invalid fpReg1" }
|
||||
if(!format.fpReg2) require(fpReg2==null) { "invalid fpReg2" }
|
||||
|
||||
if (type==VmDataType.FLOAT) {
|
||||
if(format.fpValue) require(fpValue!=null || labelSymbol!=null) {"missing a fp-value or labelsymbol"}
|
||||
} else {
|
||||
if(format.value) require(value!=null || labelSymbol!=null) {"missing a value or labelsymbol"}
|
||||
require(fpReg1==null && fpReg2==null) {"integer point instruction can't use floating point registers"}
|
||||
}
|
||||
|
||||
reg1direction = format.reg1direction
|
||||
fpReg1direction = format.fpReg1direction
|
||||
|
||||
if(opcode in setOf(Opcode.BEQ, Opcode.BNE, Opcode.BLT, Opcode.BLTS,
|
||||
Opcode.BGT, Opcode.BGTS, Opcode.BLE, Opcode.BLES,
|
||||
Opcode.BGE, Opcode.BGES,
|
||||
Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS,
|
||||
Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES,
|
||||
Opcode.SGE, Opcode.SGES)) {
|
||||
if(type==VmDataType.FLOAT)
|
||||
require(fpReg1!=fpReg2) {"$opcode: fpReg1 and fpReg2 should be different"}
|
||||
else
|
||||
require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val result = mutableListOf(opcode.name.lowercase())
|
||||
|
||||
when(type) {
|
||||
VmDataType.BYTE -> result.add(".b ")
|
||||
VmDataType.WORD -> result.add(".w ")
|
||||
VmDataType.FLOAT -> result.add(".f ")
|
||||
else -> result.add(" ")
|
||||
}
|
||||
reg1?.let {
|
||||
result.add("r$it")
|
||||
result.add(",")
|
||||
}
|
||||
reg2?.let {
|
||||
result.add("r$it")
|
||||
result.add(",")
|
||||
}
|
||||
fpReg1?.let {
|
||||
result.add("fr$it")
|
||||
result.add(",")
|
||||
}
|
||||
fpReg2?.let {
|
||||
result.add("fr$it")
|
||||
result.add(",")
|
||||
}
|
||||
value?.let {
|
||||
result.add(it.toString())
|
||||
result.add(",")
|
||||
}
|
||||
fpValue?.let {
|
||||
result.add(it.toString())
|
||||
result.add(",")
|
||||
}
|
||||
labelSymbol?.let {
|
||||
if(it.startsWith('&'))
|
||||
result.add(it) // address-of something
|
||||
else
|
||||
result.add("_$it")
|
||||
}
|
||||
if(result.last() == ",")
|
||||
result.removeLast()
|
||||
return result.joinToString("").trimEnd()
|
||||
}
|
||||
}
|
||||
|
||||
enum class OperandDirection {
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
@ -737,3 +644,120 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.BREAKPOINT to InstructionFormat.from("N"),
|
||||
Opcode.BINARYDATA to InstructionFormat.from("N"),
|
||||
)
|
||||
|
||||
|
||||
data class IRInstruction(
|
||||
val opcode: Opcode,
|
||||
val type: VmDataType?=null,
|
||||
val reg1: Int?=null, // 0-$ffff
|
||||
val reg2: Int?=null, // 0-$ffff
|
||||
val fpReg1: Int?=null, // 0-$ffff
|
||||
val fpReg2: Int?=null, // 0-$ffff
|
||||
val value: Int?=null, // 0-$ffff
|
||||
val fpValue: Float?=null,
|
||||
val labelSymbol: String?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
|
||||
val binaryData: Collection<UByte>?=null
|
||||
): IRCodeLine() {
|
||||
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
|
||||
// This knowledge is useful in IL assembly optimizers to see how registers are used.
|
||||
val reg1direction: OperandDirection
|
||||
val fpReg1direction: OperandDirection
|
||||
|
||||
init {
|
||||
require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"}
|
||||
require(reg1==null || reg1 in 0..65536) {"reg1 out of bounds"}
|
||||
require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"}
|
||||
require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"}
|
||||
require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
|
||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||
when (type) {
|
||||
VmDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}
|
||||
VmDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"}
|
||||
VmDataType.FLOAT, null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
require((opcode==Opcode.BINARYDATA && binaryData!=null) || (opcode!=Opcode.BINARYDATA && binaryData==null)) {
|
||||
"binarydata inconsistency"
|
||||
}
|
||||
|
||||
val formats = instructionFormats.getValue(opcode)
|
||||
require (type != null || formats.containsKey(null)) { "missing type" }
|
||||
|
||||
val format = formats.getValue(type)
|
||||
if(format.reg1) require(reg1!=null) { "missing reg1" }
|
||||
if(format.reg2) require(reg2!=null) { "missing reg2" }
|
||||
if(format.fpReg1) require(fpReg1!=null) { "missing fpReg1" }
|
||||
if(format.fpReg2) require(fpReg2!=null) { "missing fpReg2" }
|
||||
if(!format.reg1) require(reg1==null) { "invalid reg1" }
|
||||
if(!format.reg2) require(reg2==null) { "invalid reg2" }
|
||||
if(!format.fpReg1) require(fpReg1==null) { "invalid fpReg1" }
|
||||
if(!format.fpReg2) require(fpReg2==null) { "invalid fpReg2" }
|
||||
|
||||
if (type==VmDataType.FLOAT) {
|
||||
if(format.fpValue) require(fpValue!=null || labelSymbol!=null) {"missing a fp-value or labelsymbol"}
|
||||
} else {
|
||||
if(format.value) require(value!=null || labelSymbol!=null) {"missing a value or labelsymbol"}
|
||||
require(fpReg1==null && fpReg2==null) {"integer point instruction can't use floating point registers"}
|
||||
}
|
||||
|
||||
reg1direction = format.reg1direction
|
||||
fpReg1direction = format.fpReg1direction
|
||||
|
||||
if(opcode in setOf(Opcode.BEQ, Opcode.BNE, Opcode.BLT, Opcode.BLTS,
|
||||
Opcode.BGT, Opcode.BGTS, Opcode.BLE, Opcode.BLES,
|
||||
Opcode.BGE, Opcode.BGES,
|
||||
Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS,
|
||||
Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES,
|
||||
Opcode.SGE, Opcode.SGES)) {
|
||||
if(type==VmDataType.FLOAT)
|
||||
require(fpReg1!=fpReg2) {"$opcode: fpReg1 and fpReg2 should be different"}
|
||||
else
|
||||
require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val result = mutableListOf(opcode.name.lowercase())
|
||||
|
||||
when(type) {
|
||||
VmDataType.BYTE -> result.add(".b ")
|
||||
VmDataType.WORD -> result.add(".w ")
|
||||
VmDataType.FLOAT -> result.add(".f ")
|
||||
else -> result.add(" ")
|
||||
}
|
||||
reg1?.let {
|
||||
result.add("r$it")
|
||||
result.add(",")
|
||||
}
|
||||
reg2?.let {
|
||||
result.add("r$it")
|
||||
result.add(",")
|
||||
}
|
||||
fpReg1?.let {
|
||||
result.add("fr$it")
|
||||
result.add(",")
|
||||
}
|
||||
fpReg2?.let {
|
||||
result.add("fr$it")
|
||||
result.add(",")
|
||||
}
|
||||
value?.let {
|
||||
result.add(it.toString())
|
||||
result.add(",")
|
||||
}
|
||||
fpValue?.let {
|
||||
result.add(it.toString())
|
||||
result.add(",")
|
||||
}
|
||||
labelSymbol?.let {
|
||||
if(it.startsWith('&'))
|
||||
result.add(it) // address-of something
|
||||
else
|
||||
result.add("_$it")
|
||||
}
|
||||
if(result.last() == ",")
|
||||
result.removeLast()
|
||||
return result.joinToString("").trimEnd()
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,8 @@ import prog8.code.core.IAssemblyGenerator
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.codegen.intermediate.IRCodeGen
|
||||
import prog8.intermediate.IRFileReader
|
||||
import prog8.intermediate.IRFileWriter
|
||||
import prog8.intermediate.IRProgram
|
||||
import java.nio.file.Path
|
||||
|
||||
class VmCodeGen(private val program: PtProgram,
|
||||
private val symbolTable: SymbolTable,
|
||||
@ -25,13 +23,6 @@ class VmCodeGen(private val program: PtProgram,
|
||||
// no need to check options.keepIR, as the VM file format *is* the IR file.
|
||||
return VmAssemblyProgram(irProgram.name, irProgram)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun compileIR(irFile: Path): IAssemblyProgram {
|
||||
val irProgram = IRFileReader().read(irFile)
|
||||
return VmAssemblyProgram(irProgram.name, irProgram)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user