From 6ad627e88dde9b6dc82a9f1b4e593d7f58066d74 Mon Sep 17 00:00:00 2001 From: avan1235 Date: Mon, 31 Jan 2022 18:04:07 +0100 Subject: [PATCH] use gas syntax (don't require nasm) --- .../ml/dev/kotlin/latte/asm/Allocator.kt | 5 +- .../ml/dev/kotlin/latte/asm/Compiler.kt | 17 +++---- .../kotlin/ml/dev/kotlin/latte/asm/Nasm.kt | 3 +- .../kotlin/ml/dev/kotlin/latte/asm/VarLoc.kt | 13 ++--- .../kotlin/ml/dev/kotlin/latte/syntax/Type.kt | 4 +- .../ml/dev/kotlin/latte/typecheck/TypeUtil.kt | 4 +- .../dev/kotlin/latte/asm/CompilerDataTest.kt | 2 +- .../dev/kotlin/latte/asm/CompilerFileTest.kt | 2 +- .../dev/kotlin/latte/asm/OptimizedAsmTest.kt | 2 +- .../latte/quadruple/GlobalFlowAnalyzerTest.kt | 31 ++++++------ .../kotlin/latte/quadruple/IRGeneratorTest.kt | 47 ++++++++++--------- 11 files changed, 68 insertions(+), 62 deletions(-) diff --git a/src/main/kotlin/ml/dev/kotlin/latte/asm/Allocator.kt b/src/main/kotlin/ml/dev/kotlin/latte/asm/Allocator.kt index 61aa4de..f4b48ee 100644 --- a/src/main/kotlin/ml/dev/kotlin/latte/asm/Allocator.kt +++ b/src/main/kotlin/ml/dev/kotlin/latte/asm/Allocator.kt @@ -44,8 +44,9 @@ class Allocator( is LocalValue -> locations[value.id] is BooleanConstValue -> Imm(if (value.bool) "1" else "0", value.type) is IntConstValue -> Imm("${value.int}", value.type) - is StringConstValue -> Imm(strings[value.str]?.name ?: err("Used not labeled string $this"), value.type) - is LabelConstValue -> Imm(value.label.name, value.type) + is StringConstValue -> Imm(strings[value.str]?.name?.let { "OFFSET $it" } + ?: err("Used not labeled string $this"), value.type) + is LabelConstValue -> Imm("OFFSET ${value.label.name}", value.type) is NullConstValue -> Imm("0", value.type) } ?: err("Used not defined variable $value") } diff --git a/src/main/kotlin/ml/dev/kotlin/latte/asm/Compiler.kt b/src/main/kotlin/ml/dev/kotlin/latte/asm/Compiler.kt index 2124289..1c62d9d 100644 --- a/src/main/kotlin/ml/dev/kotlin/latte/asm/Compiler.kt +++ b/src/main/kotlin/ml/dev/kotlin/latte/asm/Compiler.kt @@ -13,13 +13,14 @@ private class Compiler( private val result: StringBuilder = StringBuilder(), ) { fun IR.compile(): String { - STD_LIB_FUNCTIONS.keys.forEach { result.append("extern ").appendLine(it) } - graph.functions.keys.forEach { result.append("global ").appendLine(it.name) } + result.appendLine(".intel_syntax noprefix") + STD_LIB_FUNCTIONS.keys.forEach { result.append(".extern ").appendLine(it) } + graph.functions.keys.forEach { result.append(".global ").appendLine(it.name) } val code = compileFunctions() - result.appendLine("section .data") + result.appendLine(".section .data") strings.defineUsedStrings(code) vTables.defineVTables() - result.appendLine("section .text") + result.appendLine(".section .text") result.appendLine(code) return result.toString() } @@ -34,7 +35,7 @@ private class Compiler( private fun Map.defineUsedStrings(code: String) { entries.forEach { (string, label) -> if (!label.name.toRegex().containsMatchIn(code)) return@forEach - result.append(label.name).append(": db ") + result.append(label.name).append(": .byte ") val bytes = string.toByteArray() bytes.joinTo(result, separator = ", ") if (bytes.isNotEmpty()) result.appendLine(", 0") else result.appendLine("0") @@ -44,8 +45,8 @@ private class Compiler( private fun Map.defineVTables() { entries.forEach { (classType, vTable) -> if (vTable.declarations.isEmpty()) return@forEach - result.append(classType.typeName).append(": dd ") - vTable.declarations.joinTo(result, separator = ", ") { it.name } + result.append(classType.typeName).append(": .long ") + vTable.declarations.joinTo(result, prefix = "OFFSET ", separator = ", OFFSET ") { it.name } result.appendLine() } } @@ -57,6 +58,6 @@ val CLASS_METHOD_ARGS_OFFSET: Bytes = VoidRefType.size const val THIS_ARG_ID: String = "self" val ALLOC_FUN_LABEL: Label = "__alloc".label val CONCAT_STRING_FUN_LABEL: Label = "__concatString".label -val EMPTY_STRING_LABEL: Label = "S@EMPTY".label +val EMPTY_STRING_LABEL: Label = "EMPTY".label diff --git a/src/main/kotlin/ml/dev/kotlin/latte/asm/Nasm.kt b/src/main/kotlin/ml/dev/kotlin/latte/asm/Nasm.kt index 75428c7..aa791f3 100644 --- a/src/main/kotlin/ml/dev/kotlin/latte/asm/Nasm.kt +++ b/src/main/kotlin/ml/dev/kotlin/latte/asm/Nasm.kt @@ -7,9 +7,8 @@ import java.nio.file.Files fun nasm(assembly: File, libFile: File = DEFAULT_LIB_FILE): CompilationResult { val o = assembly.withExtension(".o") val result = assembly.withExtension("") - listOf("nasm", "-f", "elf32", assembly.absolutePath, "-o", o.absolutePath).run() withLibFile(libFile) { lib -> - listOf("gcc", "-m32", "-static", lib.absolutePath, o.absolutePath, "-o", result.absolutePath).run() + listOf("gcc", "-m32", "-static", lib.absolutePath, assembly.absolutePath, "-o", result.absolutePath).run() } return CompilationResult(o, result) } diff --git a/src/main/kotlin/ml/dev/kotlin/latte/asm/VarLoc.kt b/src/main/kotlin/ml/dev/kotlin/latte/asm/VarLoc.kt index ad1629a..6e98c38 100644 --- a/src/main/kotlin/ml/dev/kotlin/latte/asm/VarLoc.kt +++ b/src/main/kotlin/ml/dev/kotlin/latte/asm/VarLoc.kt @@ -3,6 +3,7 @@ package ml.dev.kotlin.latte.asm import ml.dev.kotlin.latte.asm.Reg.EBP import ml.dev.kotlin.latte.quadruple.Named import ml.dev.kotlin.latte.syntax.Bytes +import ml.dev.kotlin.latte.syntax.PrimitiveType.VoidRefType import ml.dev.kotlin.latte.syntax.Type import ml.dev.kotlin.latte.util.LatteIllegalStateException import ml.dev.kotlin.latte.util.msg @@ -11,22 +12,22 @@ sealed interface VarLoc : Named sealed interface Mem : VarLoc data class Imm(private val value: String, private val type: Type) : VarLoc { - override val name = "${type.wordSize} $value" + override val name = value } data class Arg(private val offset: Bytes, private val type: Type) : Mem { - override val name = "${type.wordSize} [$EBP + ${ARG_OFFSET + offset}]" + override val name = "${type.wordSize} PTR [$EBP + ${ARG_OFFSET + offset}]" } data class Loc(private val offset: Bytes, private val type: Type) : Mem { - override val name = "${type.wordSize} [$EBP - ${LOCAL_OFFSET + offset}]" + override val name = "${type.wordSize} PTR [$EBP - ${LOCAL_OFFSET + offset}]" } data class Adr(val loc: Reg, val offset: Bytes = 0) : Named { override val name: String = when { - offset > 0 -> "[${loc.name} + $offset]" - offset < 0 -> "[${loc.name} - ${-offset}]" - else -> "[${loc.name}]" + offset > 0 -> "${VoidRefType.wordSize} PTR [${loc.name} + $offset]" + offset < 0 -> "${VoidRefType.wordSize} PTR [${loc.name} - ${-offset}]" + else -> "${VoidRefType.wordSize} PTR [${loc.name}]" } } diff --git a/src/main/kotlin/ml/dev/kotlin/latte/syntax/Type.kt b/src/main/kotlin/ml/dev/kotlin/latte/syntax/Type.kt index 1987dc8..a18c657 100644 --- a/src/main/kotlin/ml/dev/kotlin/latte/syntax/Type.kt +++ b/src/main/kotlin/ml/dev/kotlin/latte/syntax/Type.kt @@ -16,7 +16,7 @@ enum class PrimitiveType(override val typeName: String, override val size: Bytes IntType("int", 4), StringType("string", 4), BooleanType("boolean", 4), - VoidRefType("void~", 4), + VoidRefType("voidRef", 4), VoidType("void", 4) { override val size: Bytes get() = throw LatteIllegalStateException("Cannot get size of $this type".msg) }; @@ -27,7 +27,7 @@ enum class PrimitiveType(override val typeName: String, override val size: Bytes class RefType(override val typeName: String, override val span: Span? = null) : Type { override val size: Bytes = 4 - override fun toString(): String = "$typeName~" + override fun toString(): String = "${typeName}Ref" override fun hashCode(): Int = typeName.hashCode() override fun equals(other: Any?): Boolean = (other as? RefType)?.typeName == typeName } diff --git a/src/main/kotlin/ml/dev/kotlin/latte/typecheck/TypeUtil.kt b/src/main/kotlin/ml/dev/kotlin/latte/typecheck/TypeUtil.kt index 0b4c468..2df6091 100644 --- a/src/main/kotlin/ml/dev/kotlin/latte/typecheck/TypeUtil.kt +++ b/src/main/kotlin/ml/dev/kotlin/latte/typecheck/TypeUtil.kt @@ -26,7 +26,9 @@ fun createStdLibFunEnv(): LinkedHashMap = STD_LIB. } infix fun String.mangled(args: List): String = - if (this with args in STD_LIB_FUNCTIONS_SIGNATURES) "__$this" else "$this${args.joinToString("") { "@$it" }}" + if (this with args in STD_LIB_FUNCTIONS_SIGNATURES) "__$this" else "$this${args.joinToString("") { "$ARG_SEP$it" }}" + +const val ARG_SEP: String = "$$" data class FunSignature(val name: String, val args: List) data class FunDeclaration(val name: String, val args: List, val ret: Type) diff --git a/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerDataTest.kt b/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerDataTest.kt index 9a1ced2..f90a7a7 100644 --- a/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerDataTest.kt +++ b/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerDataTest.kt @@ -502,7 +502,7 @@ private fun testCompilerWithAllocatorStrategy( val programFile = Files.createTempFile(dataDir, shortcut, ".lat").toFile().apply { writeText(program) } val inputFile = input?.let { programFile.withExtension(".input", it.trimIndent()) } val compiled = programFile.runCompiler(strategy = allocator.strategy) - val asmFile = programFile.withExtension(".asm", compiled) + val asmFile = programFile.withExtension(".s", compiled) val (o, exe) = nasm(asmFile, libFile = File("lib/runtime.o")) val outFile = programFile.withExtension(".outputTest") val errFile = programFile.withExtension(".errorTest") diff --git a/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerFileTest.kt b/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerFileTest.kt index ce7d4ea..69d6b20 100644 --- a/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerFileTest.kt +++ b/src/test/kotlin/ml/dev/kotlin/latte/asm/CompilerFileTest.kt @@ -74,7 +74,7 @@ private fun testCompilerWithAllocatorStrategy( val expected = input.withExtension(".output").readText() val inputFile = input.withExtension(".input").takeIf { it.exists() } val compiled = input.runCompiler(strategy = allocator.strategy) - val asmFile = input.withExtension(".${shortcut}.asm").apply { writeText(compiled) } + val asmFile = input.withExtension(".${shortcut}.s").apply { writeText(compiled) } val (o, exe) = nasm(asmFile, libFile = File("lib/runtime.o")) val outFile = input.withExtension(".${shortcut}.outputTest").apply { createNewFile() } val errFile = input.withExtension(".${shortcut}.errorTest").apply { createNewFile() } diff --git a/src/test/kotlin/ml/dev/kotlin/latte/asm/OptimizedAsmTest.kt b/src/test/kotlin/ml/dev/kotlin/latte/asm/OptimizedAsmTest.kt index 985b12a..461e97c 100644 --- a/src/test/kotlin/ml/dev/kotlin/latte/asm/OptimizedAsmTest.kt +++ b/src/test/kotlin/ml/dev/kotlin/latte/asm/OptimizedAsmTest.kt @@ -219,7 +219,7 @@ private fun configuredRunCompiler( val programFile = Files.createTempFile(dataDir, "opt", ".lat").toFile().apply { writeText(program) } val inputFile = input?.let { programFile.withExtension(".input", it.trimIndent()) } val code = programFile.runCompiler(true, propagateConstants, simplifyExpr, true, lcse, gcse) - val asmFile = programFile.withExtension(".asm", code) + val asmFile = programFile.withExtension(".s", code) val (o, exe) = nasm(asmFile, libFile = File("lib/runtime.o")) val outFile = programFile.withExtension(".outputTest") val errFile = programFile.withExtension(".errorTest") diff --git a/src/test/kotlin/ml/dev/kotlin/latte/quadruple/GlobalFlowAnalyzerTest.kt b/src/test/kotlin/ml/dev/kotlin/latte/quadruple/GlobalFlowAnalyzerTest.kt index 338dc1b..f6e9305 100644 --- a/src/test/kotlin/ml/dev/kotlin/latte/quadruple/GlobalFlowAnalyzerTest.kt +++ b/src/test/kotlin/ml/dev/kotlin/latte/quadruple/GlobalFlowAnalyzerTest.kt @@ -2,6 +2,7 @@ package ml.dev.kotlin.latte.quadruple import ml.dev.kotlin.latte.syntax.PrimitiveType.IntType import ml.dev.kotlin.latte.syntax.parse +import ml.dev.kotlin.latte.typecheck.ARG_SEP import ml.dev.kotlin.latte.typecheck.mangled import ml.dev.kotlin.latte.typecheck.typeCheck import ml.dev.kotlin.latte.util.DefaultMap @@ -27,7 +28,7 @@ internal class GlobalFlowAnalyzerTest { } """, /** - * 0: f@int(x#0): + * 0: f$$int(x#0): * 1: ret x#0 */ label = "f" mangled listOf(IntType), @@ -67,7 +68,7 @@ internal class GlobalFlowAnalyzerTest { } """, /** - * 0: f@int(x#0): + * 0: f$$int(x#0): * 1: y@1#0 = 0 * 2: if x#0 eq 42 goto L2 * 3: y@1#3 = x#0 @@ -154,7 +155,7 @@ internal class GlobalFlowAnalyzerTest { } """, /** - * 0: f@int(x#0): + * 0: f$$int(x#0): * 1: y@1#0 = 0 * 2: y@1#1 = y@1#0 * 3: goto L3 @@ -206,34 +207,34 @@ internal class GlobalFlowAnalyzerTest { } """, /** - * 0: f@int(x#0): + * 0: f$$int(x#0): * 1: ret x#0 */ /** - * 0: f@int(x#0): + * 0: f$$int(x#0): * 1: ret x#0 */ label = "f" mangled listOf(IntType), aliveBefore = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(), 1 to setOf(intArg("x#0", 0)) ), ), aliveAfter = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(intArg("x#0", 0)), 1 to setOf(), ) ), definedAt = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(intArg("x#0", 0)), 1 to setOf(), ) ), usedAt = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(), 1 to setOf(intArg("x#0", 0)), ) @@ -258,7 +259,7 @@ internal class GlobalFlowAnalyzerTest { } """, /** - * 0: f@int(x#0): + * 0: f$$int(x#0): * 1: y@1#0 = 0 * 2: if x#0 eq 42 goto L2 * 3: G6: @@ -276,7 +277,7 @@ internal class GlobalFlowAnalyzerTest { */ label = "f" mangled listOf(IntType), aliveBefore = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(), 1 to setOf(intArg("x#0", 0)), 2 to setOf(intArg("x#0", 0)), @@ -303,7 +304,7 @@ internal class GlobalFlowAnalyzerTest { ) ), aliveAfter = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(intArg("x#0", 0)), 1 to setOf(intArg("x#0", 0)), 2 to setOf(intArg("x#0", 0)), @@ -348,7 +349,7 @@ internal class GlobalFlowAnalyzerTest { } """, /** - * 0: f@int(x#0): + * 0: f$$int(x#0): * 1: y@1#0 = 0 * 2: y@1#1 = y@1#0 * 3: goto L3 @@ -364,7 +365,7 @@ internal class GlobalFlowAnalyzerTest { */ label = "f" mangled listOf(IntType), aliveBefore = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(), 1 to setOf(intArg("x#0", 0)), 2 to setOf(intArg("x#0", 0), intLoc("y@1#0")), @@ -389,7 +390,7 @@ internal class GlobalFlowAnalyzerTest { ), ), aliveAfter = mapOf( - "f@int".label to mapOf( + "f${ARG_SEP}int".label to mapOf( 0 to setOf(intArg("x#0", 0)), 1 to setOf(intArg("x#0", 0), intLoc("y@1#0")), 2 to setOf(intArg("x#0", 0), intLoc("y@1#1")), diff --git a/src/test/kotlin/ml/dev/kotlin/latte/quadruple/IRGeneratorTest.kt b/src/test/kotlin/ml/dev/kotlin/latte/quadruple/IRGeneratorTest.kt index 679d346..5a5db3e 100644 --- a/src/test/kotlin/ml/dev/kotlin/latte/quadruple/IRGeneratorTest.kt +++ b/src/test/kotlin/ml/dev/kotlin/latte/quadruple/IRGeneratorTest.kt @@ -2,6 +2,7 @@ package ml.dev.kotlin.latte.quadruple import ml.dev.kotlin.latte.asm.EMPTY_STRING_LABEL import ml.dev.kotlin.latte.syntax.parse +import ml.dev.kotlin.latte.typecheck.ARG_SEP import ml.dev.kotlin.latte.typecheck.CLASS_DIVIDER import ml.dev.kotlin.latte.typecheck.typeCheck import ml.dev.kotlin.latte.util.nlString @@ -211,15 +212,15 @@ internal class IRGeneratorTest { irRepresentation = """ main(): ret 0 - f@int@boolean(a#0, b#0): + f${ARG_SEP}int${ARG_SEP}boolean(a#0, b#0): goto L1 L0: @T3#0 = not b#1 b#2 = @T3#0 a#2 = dec a#1 L1: - a#1 = phi (L0:a#2, f@int@boolean:a#0) - b#1 = phi (L0:b#2, f@int@boolean:b#0) + a#1 = phi (L0:a#2, f${ARG_SEP}int${ARG_SEP}boolean:a#0) + b#1 = phi (L0:b#2, f${ARG_SEP}int${ARG_SEP}boolean:b#0) if a#1 gt 0 goto L0 ret a#1 """, @@ -288,15 +289,15 @@ internal class IRGeneratorTest { a@1#1 = b@3#0 @T6#0 = call a@1#1.f (42) ret 0 - A${CLASS_DIVIDER}f@int(self#0, x#0): + A${CLASS_DIVIDER}f${ARG_SEP}int(self#0, x#0): ret x#0 - B${CLASS_DIVIDER}f@int(self#0, x#0): + B${CLASS_DIVIDER}f${ARG_SEP}int(self#0, x#0): @T7#0 = 2 times x#0 ret @T7#0 """, virtualTable = mapOf( - "A" to listOf("A${CLASS_DIVIDER}f@int"), - "B" to listOf("B${CLASS_DIVIDER}f@int"), + "A" to listOf("A${CLASS_DIVIDER}f${ARG_SEP}int"), + "B" to listOf("B${CLASS_DIVIDER}f${ARG_SEP}int"), ) ) @@ -341,25 +342,25 @@ internal class IRGeneratorTest { @T7#0 = call b@3#0.f (42) @T8#0 = call c@5#0.f (42) ret 0 - A${CLASS_DIVIDER}f@int(self#0, x#0): + A${CLASS_DIVIDER}f${ARG_SEP}int(self#0, x#0): ret - A${CLASS_DIVIDER}g@int(self#0, x#0): + A${CLASS_DIVIDER}g${ARG_SEP}int(self#0, x#0): ret - A${CLASS_DIVIDER}h@int(self#0, x#0): + A${CLASS_DIVIDER}h${ARG_SEP}int(self#0, x#0): ret - B${CLASS_DIVIDER}g@int(self#0, x#0): + B${CLASS_DIVIDER}g${ARG_SEP}int(self#0, x#0): ret - B${CLASS_DIVIDER}f@int(self#0, x#0): + B${CLASS_DIVIDER}f${ARG_SEP}int(self#0, x#0): ret - C${CLASS_DIVIDER}h@int(self#0, x#0): + C${CLASS_DIVIDER}h${ARG_SEP}int(self#0, x#0): ret - C${CLASS_DIVIDER}f@int(self#0, x#0): + C${CLASS_DIVIDER}f${ARG_SEP}int(self#0, x#0): ret """, virtualTable = mapOf( - "A" to listOf("A${CLASS_DIVIDER}f@int", "A${CLASS_DIVIDER}g@int", "A${CLASS_DIVIDER}h@int"), - "B" to listOf("B${CLASS_DIVIDER}f@int", "B${CLASS_DIVIDER}g@int", "A${CLASS_DIVIDER}h@int"), - "C" to listOf("C${CLASS_DIVIDER}f@int", "B${CLASS_DIVIDER}g@int", "C${CLASS_DIVIDER}h@int"), + "A" to listOf("A${CLASS_DIVIDER}f${ARG_SEP}int", "A${CLASS_DIVIDER}g${ARG_SEP}int", "A${CLASS_DIVIDER}h${ARG_SEP}int"), + "B" to listOf("B${CLASS_DIVIDER}f${ARG_SEP}int", "B${CLASS_DIVIDER}g${ARG_SEP}int", "A${CLASS_DIVIDER}h${ARG_SEP}int"), + "C" to listOf("C${CLASS_DIVIDER}f${ARG_SEP}int", "B${CLASS_DIVIDER}g${ARG_SEP}int", "C${CLASS_DIVIDER}h${ARG_SEP}int"), ) ) @@ -797,11 +798,11 @@ internal class IRGeneratorTest { """, irRepresentation = """ main(): - @T6#0 = call positive@int (1) + @T6#0 = call positive${ARG_SEP}int (1) if @T6#0 goto M5 goto L3 M5: - @T7#0 = call positive@int (-1) + @T7#0 = call positive${ARG_SEP}int (-1) if @T7#0 goto L2 L3: @T1#0 = false @@ -810,18 +811,18 @@ internal class IRGeneratorTest { @T1#1 = true L4: @T1#2 = phi (L2:@T1#1, L3:@T1#0) - @T0#0 = call id@boolean (@T1#2) + @T0#0 = call id${ARG_SEP}boolean (@T1#2) x@8#0 = @T0#0 ret 0 - id@boolean(a#0): + id${ARG_SEP}boolean(a#0): ret a#0 - positive@int(a#0): + positive${ARG_SEP}int(a#0): @T9#0 = false if a#0 le 0 goto F10 G13: @T9#2 = true F10: - @T9#1 = phi (G13:@T9#2, positive@int:@T9#0) + @T9#1 = phi (G13:@T9#2, positive${ARG_SEP}int:@T9#0) ret @T9#1 """ )