From 39d6d2857e3dcd252d5b4c60cc817a0b45bd9bb2 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 4 Oct 2022 00:47:51 +0200 Subject: [PATCH] ir: change inline binary a bit --- .../prog8/codegen/intermediate/IRCodeGen.kt | 4 +- .../intermediate/IRPeepholeOptimizer.kt | 2 - examples/test.p8 | 2 + .../src/prog8/intermediate/IRFileReader.kt | 33 ++++++++------- .../src/prog8/intermediate/IRFileWriter.kt | 42 ++++++++++--------- .../src/prog8/intermediate/IRProgram.kt | 39 +++++++++-------- .../src/prog8/vm/VmProgramLoader.kt | 11 +++-- 7 files changed, 70 insertions(+), 63 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 169cf20ed..8ce9b74d7 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -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, diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index 1e085af88..41da392ef 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -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? diff --git a/examples/test.p8 b/examples/test.p8 index abc9d6d99..b14e51429 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,5 +3,7 @@ main { ubyte aa = 42 ubyte bb = 99 aa += bb + + %asmbinary "build.gradle" } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 8f522208e..df2f79efd 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -286,6 +286,7 @@ class IRFileReader { private val blockPattern = Regex("") private val inlineAsmPattern = Regex("") + private val bytesPattern = Regex("") private val asmsubPattern = Regex("") private val subPattern = Regex("") private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]") @@ -387,6 +388,8 @@ class IRFileReader { return sub val chunk = if(line=="") parseCodeChunk(line, lines) + else if(line.startsWith("): IRInlineBinaryChunk { + val match = bytesPattern.matchEntire(startline) ?: throw IRParseException("invalid BYTES") + val pos = parsePosition(match.groupValues[1]) + val bytes = mutableListOf() + var line = lines.next() + while(line!="") { + 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, variables: List): List { var line = lines.next() if(line!="") @@ -428,24 +445,12 @@ class IRFileReader { } val chunk = IRCodeChunk(Position.DUMMY) while(true) { - var line = lines.next() + val line = lines.next() if (line == "") return chunk if (line.isBlank() || line.startsWith(';')) continue - if(line=="") { - val bytes = mutableListOf() - line = lines.next() - while(line!="") { - 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()) } } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index e9914437f..3be3d4586 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -58,17 +58,19 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { out.write("\n") it.chunks.forEach { chunk -> numChunks++ - if(chunk is IRInlineAsmChunk) { - writeInlineAsm(chunk) - } else { - out.write("\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("\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("\n") } - out.write("\n") } } out.write("\n") @@ -95,6 +97,16 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { } } + private fun writeInlineBytes(chunk: IRInlineBinaryChunk) { + out.write("\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\n") + } + private fun writeInlineAsm(chunk: IRInlineAsmChunk) { out.write("\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("\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\n") - } else -> throw AssemblyError("invalid vm code line") } } diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index a4ffccfe7..69ad39495 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -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): IRCodeLine() - abstract class IRCodeChunkBase(val position: Position) { val lines = mutableListOf() @@ -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, 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, @@ -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().withDefault { 0 } val inputFpRegs = mutableMapOf().withDefault { 0 } diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 9757b1772..d8eaff316 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -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 } } }