ir: write values as hex into p8ir file

This commit is contained in:
Irmen de Jong 2022-11-08 00:06:43 +01:00
parent e426fc0922
commit e614e9787a
10 changed files with 42 additions and 56 deletions

View File

@ -4,7 +4,10 @@ import prog8.code.StRomSub
import prog8.code.StStaticVariable import prog8.code.StStaticVariable
import prog8.code.StSub import prog8.code.StSub
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.* import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.code.core.PassByValueDatatypes
import prog8.code.core.SignedDatatypes
import prog8.intermediate.* import prog8.intermediate.*

View File

@ -1 +1 @@
8.7 8.8-dev

View File

@ -86,7 +86,7 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
val existing = subroutine.lookup(listOf(subroutine.name)) val existing = subroutine.lookup(listOf(subroutine.name))
if (existing != null && existing !== subroutine) { if (existing != null && existing !== subroutine) {
if(existing.parent!==existing.parent) if(existing.parent!==existing.parent) // TODO fix this check
nameShadowWarning(subroutine.name, existing.position, subroutine) nameShadowWarning(subroutine.name, existing.position, subroutine)
else else
nameError(subroutine.name, existing.position, subroutine) nameError(subroutine.name, existing.position, subroutine)
@ -122,7 +122,6 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
errors.err("can't use a cpu opcode name as a symbol: '${label.name}'", label.position) errors.err("can't use a cpu opcode name as a symbol: '${label.name}'", label.position)
if(label.name in BuiltinFunctions) { if(label.name in BuiltinFunctions) {
// the builtin functions can't be redefined
errors.err("builtin function cannot be redefined", label.position) errors.err("builtin function cannot be redefined", label.position)
} else { } else {
val existing = (label.definingSubroutine ?: label.definingBlock).getAllLabels(label.name) val existing = (label.definingSubroutine ?: label.definingBlock).getAllLabels(label.name)

View File

@ -508,6 +508,7 @@ logical: ``not`` ``and`` ``or`` ``xor``
Unlike most other programming languages, there is no short-circuit or McCarthy evaluation Unlike most other programming languages, there is no short-circuit or McCarthy evaluation
for the logical ``and`` and ``or`` operators. This means that prog8 currently always evaluates for the logical ``and`` and ``or`` operators. This means that prog8 currently always evaluates
all operands from these logical expressions, even when one of them already determines the outcome! all operands from these logical expressions, even when one of them already determines the outcome!
If you don't want this to happen, you have to split and nest the if-statements yourself.
range creation: ``to`` range creation: ``to``
Creates a range of values from the LHS value to the RHS value, inclusive. Creates a range of values from the LHS value to the RHS value, inclusive.

View File

@ -3,8 +3,10 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- ir: register allocation per data type a specific allocation, so we are certain when a reg is used it's just for one specific datatype - AstIdentifiersChecker: fix the subroutine name shadow if-condition (see vardecl check)
- ir: write addresses as hex into p8ir file - 6502 codegen: make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway)
then we can get rid of the instruction lists in the machinedefinitions as well. This is already no problem at all in the IR codegen.
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
... ...
@ -20,7 +22,7 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
Compiler: Compiler:
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code - AstIdentifiersChecker: can a subroutine really not have the same name as its enclosing block?
- ir: mechanism to determine for chunks which registers are getting input values from "outside" - ir: mechanism to determine for chunks which registers are getting input values from "outside"
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk) - ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
- ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!) - ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)
@ -33,20 +35,12 @@ Compiler:
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. - createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
but probably better to rewrite the 6502 codegen on top of the new Ast. but probably better to rewrite the 6502 codegen on top of the new Ast.
- generate WASM to eventually run prog8 on a browser canvas? - generate WASM to eventually run prog8 on a browser canvas?
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway)
then we can get rid of the instruction lists in the machinedefinitions as well?
- [problematic due to using 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ... - [problematic due to using 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ...
Perhaps replace all uses of .proc/.pend by .block/.bend will fix that with a compiler flag? Perhaps replace all uses of .proc/.pend by .block/.bend will fix that with a compiler flag?
But all library code written in asm uses .proc already..... (search/replace when writing the actual asm?) But all library code written in asm uses .proc already..... (search/replace when writing the actual asm?)
Once new codegen is written that is based on the IR, this point is moot anyway as that will have its own dead code removal.
- Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) - Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that)
- add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing - add special (u)word array type (or modifier?) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing
- ast: don't rewrite by-reference parameter type to uword, but keep the original type (str, array)
BUT that makes the handling of these types different between the scope they are defined in, and the
scope they get passed in by reference... unless we make str and array types by-reference ALWAYS?
BUT that makes simple code accessing them in the declared scope very slow because that then has to always go through
the pointer rather than directly referencing the variable symbol in the generated asm....
Or maybe make codegen smart to check if it's a subroutine parameter or local declared variable?
Libraries: Libraries:

View File

@ -1,27 +1,17 @@
%import textio %import textio
%import floats
%zeropage basicsafe %zeropage basicsafe
main { main {
ubyte @shared qqq=123
&uword mapped = $ea31
sub start() { sub start() {
float f1 ubyte bb = 99
txt.print_ub(bb)
floats.rndseedf(-1.2345) txt.print("Hello, world!")
txt.spc() uword ww = bb
floats.print_f(floats.rndf()) txt.print_uw(bb)
txt.spc() txt.print_uw(ww)
floats.print_f(floats.rndf())
txt.spc()
floats.print_f(floats.rndf())
txt.nl()
floats.rndseedf(1.2345)
txt.spc()
floats.print_f(floats.rndf())
txt.spc()
floats.print_f(floats.rndf())
txt.spc()
floats.print_f(floats.rndf())
txt.nl()
} }
} }

View File

@ -103,7 +103,7 @@ class IRFileReader {
"zeropage" -> zeropage = ZeropageType.valueOf(value) "zeropage" -> zeropage = ZeropageType.valueOf(value)
"loadAddress" -> loadAddress = value.toUInt() "loadAddress" -> loadAddress = value.toUInt()
"dontReinitGlobals" -> dontReinitGlobals = value.toBoolean() "dontReinitGlobals" -> dontReinitGlobals = value.toBoolean()
"evalStackBaseAddress" -> evalStackBaseAddress = if(value=="null") null else value.toUInt() "evalStackBaseAddress" -> evalStackBaseAddress = if(value=="null") null else parseIRValue(value).toUInt()
"zpReserved" -> { "zpReserved" -> {
val (start, end) = value.split(',') val (start, end) = value.split(',')
zpReserved.add(UIntRange(start.toUInt(), end.toUInt())) zpReserved.add(UIntRange(start.toUInt(), end.toUInt()))
@ -161,7 +161,7 @@ class IRFileReader {
} else { } else {
require(dontReinitGlobals) require(dontReinitGlobals)
bss = false bss = false
initNumeric = value.toDouble() initNumeric = parseIRValue(value).toDouble()
} }
} }
in ArrayDatatypes -> { in ArrayDatatypes -> {
@ -174,7 +174,7 @@ class IRFileReader {
if (it.startsWith('&')) if (it.startsWith('&'))
StArrayElement(null, it.drop(1).split('.')) StArrayElement(null, it.drop(1).split('.'))
else else
StArrayElement(it.toDouble(), null) StArrayElement(parseIRValue(it).toDouble(), null)
} }
} }
} }
@ -206,7 +206,7 @@ class IRFileReader {
val (type, arrayspec, name, address) = match.destructured val (type, arrayspec, name, address) = match.destructured
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
val dt: DataType = parseDatatype(type, arraysize!=null) val dt: DataType = parseDatatype(type, arraysize!=null)
memvars.add(StMemVar(name, dt, address.toUInt(), arraysize, Position.DUMMY)) memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, Position.DUMMY))
} }
return memvars return memvars
} }
@ -286,7 +286,7 @@ class IRFileReader {
return blocks return blocks
} }
private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.+) ALIGN=(.+) POS=(.+)>") private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.*) ALIGN=(.+) POS=(.+)>")
private val inlineAsmPattern = Regex("<INLINEASM LABEL=(.*) IR=(.+)>") private val inlineAsmPattern = Regex("<INLINEASM LABEL=(.*) IR=(.+)>")
private val bytesPattern = Regex("<BYTES LABEL=(.*)>") private val bytesPattern = Regex("<BYTES LABEL=(.*)>")
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>") private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
@ -299,7 +299,7 @@ class IRFileReader {
throw IRParseException("invalid BLOCK") throw IRParseException("invalid BLOCK")
val match = blockPattern.matchEntire(line) ?: throw IRParseException("invalid BLOCK") val match = blockPattern.matchEntire(line) ?: throw IRParseException("invalid BLOCK")
val (name, address, align, position) = match.destructured val (name, address, align, position) = match.destructured
val addressNum = if(address=="null") null else address.toUInt() val addressNum = if(address=="null") null else parseIRValue(address).toUInt()
val block = IRBlock(name, addressNum, IRBlock.BlockAlignment.valueOf(align), parsePosition(position)) val block = IRBlock(name, addressNum, IRBlock.BlockAlignment.valueOf(align), parsePosition(position))
while(true) { while(true) {
line = lines.next() line = lines.next()
@ -367,7 +367,7 @@ class IRFileReader {
} }
return IRAsmSubroutine( return IRAsmSubroutine(
scopedname, scopedname,
if(address=="null") null else address.toUInt(), if(address=="null") null else parseIRValue(address).toUInt(),
clobberRegs.toSet(), clobberRegs.toSet(),
params, params,
returns, returns,

View File

@ -1,9 +1,6 @@
package prog8.intermediate package prog8.intermediate
import prog8.code.core.ArrayDatatypes import prog8.code.core.*
import prog8.code.core.DataType
import prog8.code.core.InternalCompilerException
import prog8.code.core.NumericDatatypes
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.bufferedWriter import kotlin.io.path.bufferedWriter
import kotlin.io.path.div import kotlin.io.path.div
@ -47,7 +44,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private fun writeBlocks() { private fun writeBlocks() {
irProgram.blocks.forEach { block -> irProgram.blocks.forEach { block ->
out.write("\n<BLOCK NAME=${block.name} ADDRESS=${block.address} ALIGN=${block.alignment} POS=${block.position}>\n") out.write("\n<BLOCK NAME=${block.name} ADDRESS=${block.address?.toHex()} ALIGN=${block.alignment} POS=${block.position}>\n")
block.inlineAssembly.forEach { block.inlineAssembly.forEach {
writeInlineAsm(it) writeInlineAsm(it)
} }
@ -73,7 +70,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if(reg.registerOrPair!=null) "${reg.registerOrPair}:${dt.toString().lowercase()}" if(reg.registerOrPair!=null) "${reg.registerOrPair}:${dt.toString().lowercase()}"
else "${reg.statusflag}:${dt.toString().lowercase()}" else "${reg.statusflag}:${dt.toString().lowercase()}"
}.joinToString(",") }.joinToString(",")
out.write("<ASMSUB NAME=${it.name} ADDRESS=${it.address} CLOBBERS=$clobbers RETURNS=$returns POS=${it.position}>\n") out.write("<ASMSUB NAME=${it.name} ADDRESS=${it.address?.toHex()} CLOBBERS=$clobbers RETURNS=$returns POS=${it.position}>\n")
out.write("<PARAMS>\n") out.write("<PARAMS>\n")
it.parameters.forEach { (dt, regOrSf) -> it.parameters.forEach { (dt, regOrSf) ->
val reg = if(regOrSf.registerOrPair!=null) regOrSf.registerOrPair.toString() val reg = if(regOrSf.registerOrPair!=null) regOrSf.registerOrPair.toString()
@ -126,10 +123,10 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
for(range in irProgram.options.zpReserved) { for(range in irProgram.options.zpReserved) {
out.write("zpReserved=${range.first},${range.last}\n") out.write("zpReserved=${range.first},${range.last}\n")
} }
out.write("loadAddress=${irProgram.options.loadAddress}\n") out.write("loadAddress=${irProgram.options.loadAddress.toHex()}\n")
out.write("optimize=${irProgram.options.optimize}\n") out.write("optimize=${irProgram.options.optimize}\n")
out.write("dontReinitGlobals=${irProgram.options.dontReinitGlobals}\n") out.write("dontReinitGlobals=${irProgram.options.dontReinitGlobals}\n")
out.write("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress}\n") out.write("evalStackBaseAddress=${irProgram.options.evalStackBaseAddress?.toHex()}\n")
out.write("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n") out.write("outputDir=${irProgram.options.outputDir.toAbsolutePath()}\n")
// other options not yet useful here? // other options not yet useful here?
out.write("</OPTIONS>\n") out.write("</OPTIONS>\n")
@ -142,7 +139,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
val typeStr = getTypeString(variable) val typeStr = getTypeString(variable)
val value: String = when(variable.dt) { val value: String = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString() DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt() ?: "").toString() in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString()
DataType.STR -> { DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u) val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() } encoded.joinToString(",") { it.toInt().toString() }
@ -158,7 +155,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if(variable.onetimeInitializationArrayValue!==null) { if(variable.onetimeInitializationArrayValue!==null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { variable.onetimeInitializationArrayValue!!.joinToString(",") {
if(it.number!=null) if(it.number!=null)
it.number!!.toInt().toString() it.number!!.toInt().toHex()
else else
"&${it.addressOf!!.joinToString(".")}" "&${it.addressOf!!.joinToString(".")}"
} }
@ -175,7 +172,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
out.write("\n<MEMORYMAPPEDVARIABLES>\n") out.write("\n<MEMORYMAPPEDVARIABLES>\n")
for (variable in irProgram.st.allMemMappedVariables()) { for (variable in irProgram.st.allMemMappedVariables()) {
val typeStr = getTypeString(variable) val typeStr = getTypeString(variable)
out.write("&$typeStr ${variable.name}=${variable.address}\n") out.write("&$typeStr ${variable.name}=${variable.address.toHex()}\n")
} }
out.write("</MEMORYMAPPEDVARIABLES>\n") out.write("</MEMORYMAPPEDVARIABLES>\n")

View File

@ -1,5 +1,7 @@
package prog8.intermediate package prog8.intermediate
import prog8.code.core.toHex
/* /*
Intermediate Representation instructions for the IR Virtual machine. Intermediate Representation instructions for the IR Virtual machine.
@ -807,7 +809,7 @@ data class IRInstruction(
result.add(",") result.add(",")
} }
value?.let { value?.let {
result.add(it.toString()) result.add(it.toHex())
result.add(",") result.add(",")
} }
fpValue?.let { fpValue?.let {

View File

@ -30,7 +30,7 @@ class TestInstructions: FunSpec({
ins.reg2 shouldBe null ins.reg2 shouldBe null
ins.value shouldBe 99 ins.value shouldBe 99
ins.labelSymbol shouldBe null ins.labelSymbol shouldBe null
ins.toString() shouldBe "bz.b r42,99" ins.toString() shouldBe "bz.b r42,$63"
} }
test("with label") { test("with label") {