ir: change inline binary a bit

This commit is contained in:
Irmen de Jong 2022-10-04 00:47:51 +02:00
parent 7b722a0001
commit 39d6d2857e
7 changed files with 70 additions and 63 deletions

View File

@ -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,

View File

@ -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?

View File

@ -3,5 +3,7 @@ main {
ubyte aa = 42
ubyte bb = 99
aa += bb
%asmbinary "build.gradle"
}
}

View File

@ -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())
}
}

View File

@ -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")
}
}

View File

@ -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 }

View File

@ -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 }
}
}