mirror of
https://github.com/irmen/prog8.git
synced 2025-01-28 02:34:01 +00:00
ir: change inline binary a bit
This commit is contained in:
parent
7b722a0001
commit
39d6d2857e
@ -240,12 +240,10 @@ class IRCodeGen(
|
||||
is PtConditionalBranch -> translate(node)
|
||||
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.isIR, node.position)
|
||||
is PtIncludeBinary -> {
|
||||
val chunk = IRCodeChunk(node.position)
|
||||
val data = node.file.readBytes()
|
||||
.drop(node.offset?.toInt() ?: 0)
|
||||
.take(node.length?.toInt() ?: Int.MAX_VALUE)
|
||||
chunk += IRCodeInlineBinary(data.map { it.toUByte() })
|
||||
return chunk
|
||||
return IRInlineBinaryChunk(data.map { it.toUByte() }, node.position)
|
||||
}
|
||||
is PtAddressOf,
|
||||
is PtContainmentCheck,
|
||||
|
@ -39,8 +39,6 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
|
||||
fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean {
|
||||
if(previous is IRCodeChunk && chunk is IRCodeChunk) {
|
||||
if(chunk.lines.any{ it is IRCodeInlineBinary})
|
||||
return false
|
||||
return true
|
||||
|
||||
// TODO: only if all instructions are non-branching, allow it to join?
|
||||
|
@ -3,5 +3,7 @@ main {
|
||||
ubyte aa = 42
|
||||
ubyte bb = 99
|
||||
aa += bb
|
||||
|
||||
%asmbinary "build.gradle"
|
||||
}
|
||||
}
|
||||
|
@ -286,6 +286,7 @@ class IRFileReader {
|
||||
|
||||
private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.+) ALIGN=(.+) POS=(.+)>")
|
||||
private val inlineAsmPattern = Regex("<INLINEASM IR=(.+) POS=(.+)>")
|
||||
private val bytesPattern = Regex("<BYTES POS=(.+)>")
|
||||
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
|
||||
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
||||
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
||||
@ -387,6 +388,8 @@ class IRFileReader {
|
||||
return sub
|
||||
val chunk = if(line=="<C>")
|
||||
parseCodeChunk(line, lines)
|
||||
else if(line.startsWith("<BYTES "))
|
||||
parseBinaryBytes(line, lines)
|
||||
else if(line.startsWith("<INLINEASM "))
|
||||
parseInlineAssembly(line, lines)
|
||||
else
|
||||
@ -403,6 +406,20 @@ class IRFileReader {
|
||||
return sub
|
||||
}
|
||||
|
||||
private fun parseBinaryBytes(startline: String, lines: Iterator<String>): IRInlineBinaryChunk {
|
||||
val match = bytesPattern.matchEntire(startline) ?: throw IRParseException("invalid BYTES")
|
||||
val pos = parsePosition(match.groupValues[1])
|
||||
val bytes = mutableListOf<UByte>()
|
||||
var line = lines.next()
|
||||
while(line!="</BYTES>") {
|
||||
line.trimEnd().windowed(size=2, step=2) {
|
||||
bytes.add(it.toString().toUByte(16))
|
||||
}
|
||||
line = lines.next()
|
||||
}
|
||||
return IRInlineBinaryChunk(bytes, pos)
|
||||
}
|
||||
|
||||
private fun parseParameters(lines: Iterator<String>, variables: List<StStaticVariable>): List<IRSubroutine.IRParam> {
|
||||
var line = lines.next()
|
||||
if(line!="<PARAMS>")
|
||||
@ -428,24 +445,12 @@ class IRFileReader {
|
||||
}
|
||||
val chunk = IRCodeChunk(Position.DUMMY)
|
||||
while(true) {
|
||||
var line = lines.next()
|
||||
val line = lines.next()
|
||||
if (line == "</C>")
|
||||
return chunk
|
||||
if (line.isBlank() || line.startsWith(';'))
|
||||
continue
|
||||
if(line=="<BYTES>") {
|
||||
val bytes = mutableListOf<UByte>()
|
||||
line = lines.next()
|
||||
while(line!="</BYTES>") {
|
||||
line.trimEnd().windowed(size=2, step=2) {
|
||||
bytes.add(it.toString().toUByte(16))
|
||||
}
|
||||
line = lines.next()
|
||||
}
|
||||
chunk += IRCodeInlineBinary(bytes)
|
||||
} else {
|
||||
chunk += parseIRCodeLine(line, 0, mutableMapOf())
|
||||
}
|
||||
chunk += parseIRCodeLine(line, 0, mutableMapOf())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,17 +58,19 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
out.write("</PARAMS>\n")
|
||||
it.chunks.forEach { chunk ->
|
||||
numChunks++
|
||||
if(chunk is IRInlineAsmChunk) {
|
||||
writeInlineAsm(chunk)
|
||||
} else {
|
||||
out.write("<C>\n")
|
||||
if (chunk.lines.isEmpty())
|
||||
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
|
||||
chunk.lines.forEach { line ->
|
||||
numLines++
|
||||
out.writeLine(line)
|
||||
when (chunk) {
|
||||
is IRInlineAsmChunk -> writeInlineAsm(chunk)
|
||||
is IRInlineBinaryChunk -> writeInlineBytes(chunk)
|
||||
else -> {
|
||||
out.write("<C>\n")
|
||||
if (chunk.lines.isEmpty())
|
||||
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
|
||||
chunk.lines.forEach { line ->
|
||||
numLines++
|
||||
out.writeLine(line)
|
||||
}
|
||||
out.write("</C>\n")
|
||||
}
|
||||
out.write("</C>\n")
|
||||
}
|
||||
}
|
||||
out.write("</SUB>\n")
|
||||
@ -95,6 +97,16 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeInlineBytes(chunk: IRInlineBinaryChunk) {
|
||||
out.write("<BYTES POS=${chunk.position}>\n")
|
||||
chunk.data.withIndex().forEach {(index, byte) ->
|
||||
out.write(byte.toString(16).padStart(2,'0'))
|
||||
if(index and 63 == 63 && index < chunk.data.size-1)
|
||||
out.write("\n")
|
||||
}
|
||||
out.write("\n</BYTES>\n")
|
||||
}
|
||||
|
||||
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
|
||||
out.write("<INLINEASM IR=${chunk.isIR} POS=${chunk.position}>\n")
|
||||
out.write(chunk.assembly)
|
||||
@ -170,18 +182,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
|
||||
private fun BufferedWriter.writeLine(line: IRCodeLine) {
|
||||
when(line) {
|
||||
is IRCodeComment -> write("; ${line.comment}\n")
|
||||
is IRInstruction -> write(line.toString() + "\n")
|
||||
is IRCodeLabel -> write("_${line.name}:\n")
|
||||
is IRCodeInlineBinary -> {
|
||||
write("<BYTES>\n")
|
||||
line.data.withIndex().forEach {(index, byte) ->
|
||||
write(byte.toString(16).padStart(2,'0'))
|
||||
if(index and 63 == 63 && index < line.data.size-1)
|
||||
write("\n")
|
||||
}
|
||||
write("\n</BYTES>\n")
|
||||
}
|
||||
else -> throw AssemblyError("invalid vm code line")
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ PROGRAM:
|
||||
...
|
||||
C (CODE)
|
||||
C (CODE)
|
||||
BYTES
|
||||
...
|
||||
SUB
|
||||
SUB
|
||||
@ -174,10 +175,6 @@ sealed class IRCodeLine
|
||||
|
||||
class IRCodeLabel(val name: String): IRCodeLine()
|
||||
|
||||
class IRCodeComment(val comment: String): IRCodeLine()
|
||||
|
||||
class IRCodeInlineBinary(val data: Collection<UByte>): IRCodeLine()
|
||||
|
||||
abstract class IRCodeChunkBase(val position: Position) {
|
||||
val lines = mutableListOf<IRCodeLine>()
|
||||
|
||||
@ -211,6 +208,26 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
|
||||
}
|
||||
}
|
||||
|
||||
class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(position) {
|
||||
// note: no lines, asm is in the property
|
||||
override fun isEmpty() = assembly.isBlank()
|
||||
override fun isNotEmpty() = assembly.isNotBlank()
|
||||
private val registersUsed by lazy { registersUsedInAssembly(isIR, assembly) }
|
||||
|
||||
init {
|
||||
require(!assembly.startsWith('\n') && !assembly.startsWith('\r')) { "inline assembly should be trimmed" }
|
||||
require(!assembly.endsWith('\n') && !assembly.endsWith('\r')) { "inline assembly should be trimmed" }
|
||||
}
|
||||
|
||||
override fun usedRegisters() = registersUsed
|
||||
}
|
||||
|
||||
class IRInlineBinaryChunk(val data: Collection<UByte>, position: Position): IRCodeChunkBase(position) {
|
||||
override fun isEmpty() = data.isEmpty()
|
||||
override fun isNotEmpty() = data.isNotEmpty()
|
||||
override fun usedRegisters() = RegistersUsed(emptyMap(), emptyMap(), emptyMap(), emptyMap())
|
||||
}
|
||||
|
||||
class RegistersUsed(
|
||||
// register num -> number of uses
|
||||
val inputRegs: Map<Int, Int>,
|
||||
@ -226,20 +243,6 @@ class RegistersUsed(
|
||||
fun isNotEmpty() = !isEmpty()
|
||||
}
|
||||
|
||||
class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(position) {
|
||||
// note: no lines, asm is in the property
|
||||
override fun isEmpty() = assembly.isBlank()
|
||||
override fun isNotEmpty() = assembly.isNotBlank()
|
||||
private val registersUsed by lazy { registersUsedInAssembly(isIR, assembly) }
|
||||
|
||||
init {
|
||||
require(!assembly.startsWith('\n') && !assembly.startsWith('\r')) { "inline assembly should be trimmed" }
|
||||
require(!assembly.endsWith('\n') && !assembly.endsWith('\r')) { "inline assembly should be trimmed" }
|
||||
}
|
||||
|
||||
override fun usedRegisters() = registersUsed
|
||||
}
|
||||
|
||||
private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersUsed {
|
||||
val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
|
||||
|
@ -36,10 +36,11 @@ class VmProgramLoader {
|
||||
block.subroutines.forEach {
|
||||
symbolAddresses[it.name] = program.size
|
||||
it.chunks.forEach { chunk ->
|
||||
if(chunk is IRInlineAsmChunk)
|
||||
addAssemblyToProgram(chunk, program, symbolAddresses)
|
||||
else
|
||||
addToProgram(chunk.lines, program, symbolAddresses)
|
||||
when (chunk) {
|
||||
is IRInlineAsmChunk -> addAssemblyToProgram(chunk, program, symbolAddresses)
|
||||
is IRInlineBinaryChunk -> program += IRInstruction(Opcode.BINARYDATA, binaryData = chunk.data)
|
||||
else -> addToProgram(chunk.lines, program, symbolAddresses)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(block.asmSubroutines.any())
|
||||
@ -217,8 +218,6 @@ class VmProgramLoader {
|
||||
program += it
|
||||
}
|
||||
}
|
||||
is IRCodeInlineBinary -> program += IRInstruction(Opcode.BINARYDATA, binaryData = it.data)
|
||||
is IRCodeComment -> { /* just ignore */ }
|
||||
is IRCodeLabel -> { symbolAddresses[it.name] = program.size }
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user