ir: fix inlineasm linking

This commit is contained in:
Irmen de Jong 2022-10-31 23:59:33 +01:00
parent 890f55f91a
commit b22804efaf
10 changed files with 64 additions and 34 deletions

View File

@ -1083,13 +1083,17 @@ class IRCodeGen(
}
is PtAsmSub -> {
val assemblyChild = if(child.children.isEmpty()) null else (child.children.single() as PtInlineAssembly)
val asmChunk = IRInlineAsmChunk(
child.name, assemblyChild?.assembly ?: "", assemblyChild?.isIR==true, child.position, null
)
irBlock += IRAsmSubroutine(
child.name, child.position, child.address,
child.name,
child.address,
child.clobbers,
child.parameters.map { Pair(it.first.type, it.second) }, // note: the name of the asmsub param is not used anymore.
child.returnTypes.zip(child.retvalRegisters),
assemblyChild?.isIR==true,
assemblyChild?.assembly ?: ""
asmChunk,
child.position
)
}
is PtInlineAssembly -> {

View File

@ -7,7 +7,6 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.code.core.*
import prog8.code.target.VMTarget
import prog8.compiler.BuiltinFunctions
import prog8.compiler.InplaceModifyingBuiltinFunctions
import prog8.compiler.builtinFunctionReturnType

View File

@ -87,7 +87,7 @@ class TestCompilerOptionSourcedirs: FunSpec({
test("testFilePathOutsideWorkingDirRelativeTo1stInSourcedirs") {
val filepath = assumeReadableFile(fixturesDir, "ast_simple_main.p8")
val sourcedirs = listOf("${fixturesDir}")
val sourcedirs = listOf("$fixturesDir")
compileFile(filepath.fileName, sourcedirs) shouldNotBe null
}

View File

@ -10,7 +10,6 @@ import prog8.ast.statements.InlineAssembly
import prog8.ast.statements.VarDecl
import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.compiler.printProgram
import prog8tests.helpers.compileText
class TestVarious: FunSpec({

View File

@ -57,7 +57,7 @@ class PathsHelpersTests: FunSpec({
test("on existing directory") {
shouldThrow<java.lang.AssertionError> {
assumeNotExists("${fixturesDir}")
assumeNotExists("$fixturesDir")
}
}
}
@ -157,13 +157,13 @@ class PathsHelpersTests: FunSpec({
context("WithStringAndStringArgs") {
test("on non-existing path") {
shouldThrow<AssertionError> {
assumeDirectory("${fixturesDir}", "i_do_not_exist")
assumeDirectory("$fixturesDir", "i_do_not_exist")
}
}
test("on existing file") {
shouldThrow<AssertionError> {
assumeDirectory("${fixturesDir}", "ast_simple_main.p8")
assumeDirectory("$fixturesDir", "ast_simple_main.p8")
}
}
@ -178,13 +178,13 @@ class PathsHelpersTests: FunSpec({
context("WithStringAndPathArgs") {
test("on non-existing path") {
shouldThrow<AssertionError> {
assumeDirectory("${fixturesDir}", Path("i_do_not_exist"))
assumeDirectory("$fixturesDir", Path("i_do_not_exist"))
}
}
test("on existing file") {
shouldThrow<AssertionError> {
assumeDirectory("${fixturesDir}", Path("ast_simple_main.p8"))
assumeDirectory("$fixturesDir", Path("ast_simple_main.p8"))
}
}
@ -240,7 +240,7 @@ class PathsHelpersTests: FunSpec({
test("on directory") {
shouldThrow<AssertionError> {
assumeReadableFile("${fixturesDir}")
assumeReadableFile("$fixturesDir")
}
}
}
@ -289,7 +289,7 @@ class PathsHelpersTests: FunSpec({
context("WithStringAndStringArgs") {
test("on non-existing path") {
shouldThrow<java.lang.AssertionError> {
assumeReadableFile("${fixturesDir}", "i_do_not_exist")
assumeReadableFile("$fixturesDir", "i_do_not_exist")
}
}
@ -301,7 +301,7 @@ class PathsHelpersTests: FunSpec({
test("on directory") {
shouldThrow<AssertionError> {
assumeReadableFile("${fixturesDir}", "..")
assumeReadableFile("$fixturesDir", "..")
}
}
}

View File

@ -1,8 +1,10 @@
package prog8tests.vm
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import prog8.ast.expressions.BuiltinFunctionCall
import prog8.ast.statements.Assignment
import prog8.code.target.C64Target
@ -212,4 +214,32 @@ main {
vm.stepCount shouldBe 49
}
}
test("asmsub for virtual target") {
val src = """
main {
sub start() {
void test(42)
}
asmsub test(ubyte xx @A) -> ubyte @Y {
%asm {{
lda #99
tay
rts
return
}}
}
}"""
val othertarget = Cx16Target()
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
val target = VMTarget()
val result = compileText(target, false, src, writeAssembly = true)!!
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
val exc = shouldThrow<Exception> {
VmRunner().runProgram(virtfile.readText())
}
exc.message shouldContain("does not support asmsubs")
}
})

View File

@ -368,12 +368,12 @@ class IRFileReader {
}
return IRAsmSubroutine(
scopedname,
parsePosition(pos), if(address=="null") null else address.toUInt(),
if(address=="null") null else address.toUInt(),
clobberRegs.toSet(),
params,
returns,
asm.isIR,
asm.assembly
asm,
parsePosition(pos)
)
}

View File

@ -81,9 +81,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
out.write("${dt.toString().lowercase()} $reg\n")
}
out.write("</PARAMS>\n")
out.write("<INLINEASM IR=${it.isIR} POS=${it.position}>\n")
out.write(it.assembly)
out.write("\n</INLINEASM>\n</ASMSUB>\n")
writeInlineAsm(it.asmChunk)
out.write("</ASMSUB>\n")
}
out.write("</BLOCK>\n")
}

View File

@ -69,7 +69,12 @@ class IRProgram(val name: String,
}
fun linkChunks() {
val labeledChunks = blocks.flatMap { it.subroutines }.flatMap { it.chunks }.associateBy { it.label }
fun getLabeledChunks(): Map<String?, IRCodeChunkBase> {
return blocks.flatMap { it.subroutines }.flatMap { it.chunks }.associateBy { it.label } +
blocks.flatMap { it.asmSubroutines }.map { it.asmChunk }.associateBy { it.label }
}
val labeledChunks = getLabeledChunks()
if(globalInits.isNotEmpty()) {
if(globalInits.next==null) {
@ -109,10 +114,8 @@ class IRProgram(val name: String,
// link all jump and branching instructions to their target
chunk.instructions.forEach {
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.labelSymbol!=null) {
val targetChunk = labeledChunks.getValue(it.labelSymbol)
it.branchTarget = targetChunk
}
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.labelSymbol!=null)
it.branchTarget = labeledChunks.getValue(it.labelSymbol)
// note: branches with an address value cannot be linked to something...
}
}
@ -240,22 +243,19 @@ class IRSubroutine(val name: String,
class IRAsmSubroutine(
val name: String,
val position: Position,
val address: UInt?,
val clobbers: Set<CpuRegister>,
val parameters: List<Pair<DataType, RegisterOrStatusflag>>,
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
val isIR: Boolean,
val assembly: String
val asmChunk: IRInlineAsmChunk,
val position: Position
) {
init {
require('.' in name) { "subroutine name is not scoped: $name" }
require(!name.startsWith("main.main.")) { "subroutine name invalid main prefix: $name" }
require(!assembly.startsWith('\n') && !assembly.startsWith('\r')) { "inline assembly should be trimmed" }
require(!assembly.endsWith('\n') && !assembly.endsWith('\r')) { "inline assembly should be trimmed" }
}
private val registersUsed by lazy { registersUsedInAssembly(isIR, assembly) }
private val registersUsed by lazy { registersUsedInAssembly(asmChunk.isIR, asmChunk.assembly) }
fun usedRegisters() = registersUsed
}

View File

@ -87,13 +87,12 @@ class TestVm: FunSpec( {
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRAsmSubroutine(
"main.asmstart",
Position.DUMMY,
0x2000u,
emptySet(),
emptyList(),
emptyList(),
true,
"inlined asm here"
IRInlineAsmChunk("main.asmstart", "inlined asm here", true, Position.DUMMY, null),
Position.DUMMY
)
block += startSub
program.addBlock(block)