feat: almost complete clib calls
This commit is contained in:
parent
7f2870e340
commit
24dddcadab
@ -15,12 +15,15 @@ object asmGenerator {
|
||||
|
||||
val progAsm =
|
||||
LabelDef("main") ::
|
||||
funcPrologue() ++
|
||||
alignStack() ++
|
||||
main.flatMap(generateStmt) ++
|
||||
funcEpilogue() ++
|
||||
List(assemblyIR.Return()) ++
|
||||
generateFuncs()
|
||||
|
||||
val strDirs = strings.toList.zipWithIndex.flatMap { case (str, i) =>
|
||||
List(Directive.Int(str.size), LabelDef(s".L.str$i:"), Directive.Asciz(str))
|
||||
List(Directive.Int(str.size), LabelDef(s".L.str$i"), Directive.Asciz(str))
|
||||
}
|
||||
|
||||
List(Directive.IntelSyntax, Directive.Global("main"), Directive.RoData) ++
|
||||
@ -42,31 +45,47 @@ object asmGenerator {
|
||||
)(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] =
|
||||
stmt match {
|
||||
case microWacc.Call(Builtin.Exit, code :: _) =>
|
||||
alignStack() ++
|
||||
// alignStack() ++
|
||||
evalExprIntoReg(code, Register(RegSize.R64, RegName.DI)) ++
|
||||
List(assemblyIR.Call(CLibFunc.Exit))
|
||||
|
||||
case microWacc.Call(Builtin.Println, expr :: _) =>
|
||||
alignStack() ++
|
||||
evalExprIntoReg(expr, Register(RegSize.R64, RegName.DI)) ++
|
||||
List(
|
||||
assemblyIR.Call(CLibFunc.Puts),
|
||||
Move(Register(RegSize.R64, RegName.DI), ImmediateVal(0)),
|
||||
assemblyIR.Call(CLibFunc.Fflush)
|
||||
) ++
|
||||
restoreStack()
|
||||
// alignStack() ++
|
||||
printF(expr) ++
|
||||
printLn()
|
||||
|
||||
case microWacc.Call(Builtin.ReadInt, expr :: _) =>
|
||||
List()
|
||||
case microWacc.Call(Builtin.Print, expr :: _) =>
|
||||
// alignStack() ++
|
||||
printF(expr)
|
||||
|
||||
case Assign(lhs, rhs) =>
|
||||
lhs match {
|
||||
var dest: IndexAddress =
|
||||
IndexAddress(Register(RegSize.R64, RegName.SP), 0) // gets overrwitten
|
||||
(lhs match {
|
||||
case ident: Ident =>
|
||||
stack += (ident -> stack.size)
|
||||
evalExprIntoReg(rhs, Register(RegSize.R64, RegName.AX)) ++
|
||||
List(Push(Register(RegSize.R64, RegName.AX)))
|
||||
case _ => List()
|
||||
if (!stack.contains(ident)) {
|
||||
stack += (ident -> (stack.size + 1))
|
||||
dest = accessVar(ident)
|
||||
List(Subtract(Register(RegSize.R64, RegName.SP), ImmediateVal(16)))
|
||||
} else {
|
||||
dest = accessVar(ident)
|
||||
List()
|
||||
}
|
||||
// TODO lhs = arrayElem
|
||||
case _ =>
|
||||
// dest = ???
|
||||
List()
|
||||
}) ++
|
||||
(rhs match {
|
||||
case microWacc.Call(Builtin.ReadInt, _) =>
|
||||
readIntoVar(dest, Builtin.ReadInt)
|
||||
case microWacc.Call(Builtin.ReadChar, _) =>
|
||||
readIntoVar(dest, Builtin.ReadChar)
|
||||
case _ =>
|
||||
evalExprIntoReg(rhs, Register(RegSize.R64, RegName.AX)) ++
|
||||
List(Move(dest, Register(RegSize.R64, RegName.AX)))
|
||||
})
|
||||
// TODO other statements
|
||||
case _ => List()
|
||||
}
|
||||
|
||||
@ -74,22 +93,20 @@ object asmGenerator {
|
||||
stack: LinkedHashMap[Ident, Int],
|
||||
strings: ListBuffer[String]
|
||||
): List[AsmLine] = {
|
||||
var src: Src = ImmediateVal(0) // Placeholder
|
||||
(expr match {
|
||||
expr match {
|
||||
case IntLiter(v) =>
|
||||
src = ImmediateVal(v)
|
||||
List()
|
||||
List(Move(dest, ImmediateVal(v)))
|
||||
case CharLiter(v) =>
|
||||
List(Move(dest, ImmediateVal(v.toInt)))
|
||||
case ident: Ident =>
|
||||
List(
|
||||
Move(
|
||||
dest,
|
||||
IndexAddress(Register(RegSize.R64, RegName.SP), (stack.size - stack(ident)) * 4)
|
||||
)
|
||||
)
|
||||
List(Move(dest, accessVar(ident)))
|
||||
case ArrayLiter(elems) =>
|
||||
expr.ty match {
|
||||
case KnownType.Char =>
|
||||
strings += elems.mkString
|
||||
case KnownType.String =>
|
||||
strings += elems.map {
|
||||
case CharLiter(v) => v
|
||||
case _ => ""
|
||||
}.mkString
|
||||
List(
|
||||
Load(
|
||||
dest,
|
||||
@ -99,22 +116,59 @@ object asmGenerator {
|
||||
)
|
||||
)
|
||||
)
|
||||
// TODO other array types
|
||||
case _ => List()
|
||||
}
|
||||
// TODO other expr types
|
||||
case _ => List()
|
||||
}) ++ List(Move(dest, src))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO make sure EOF doenst override the value in the stack
|
||||
// probably need labels implemented for conditional jumps
|
||||
def readIntoVar(dest: IndexAddress, readType: Builtin.ReadInt.type | Builtin.ReadChar.type)(using
|
||||
stack: LinkedHashMap[Ident, Int],
|
||||
strings: ListBuffer[String]
|
||||
): List[AsmLine] = {
|
||||
readType match {
|
||||
case Builtin.ReadInt =>
|
||||
strings += PrintFormat.Int.toString
|
||||
case Builtin.ReadChar =>
|
||||
strings += PrintFormat.Char.toString
|
||||
}
|
||||
List(
|
||||
Load(
|
||||
Register(RegSize.R64, RegName.DI),
|
||||
IndexAddress(
|
||||
Register(RegSize.R64, RegName.IP),
|
||||
LabelArg(s".L.str${strings.size - 1}")
|
||||
)
|
||||
),
|
||||
Load(Register(RegSize.R64, RegName.SI), dest)
|
||||
) ++
|
||||
// alignStack() ++
|
||||
List(assemblyIR.Call(CLibFunc.Scanf))
|
||||
|
||||
}
|
||||
|
||||
def accessVar(ident: Ident)(using stack: LinkedHashMap[Ident, Int]): IndexAddress =
|
||||
IndexAddress(Register(RegSize.R64, RegName.SP), (stack.size - stack(ident)) * 16)
|
||||
|
||||
def alignStack()(using stack: LinkedHashMap[Ident, Int]): List[AsmLine] = {
|
||||
List(
|
||||
And(Register(RegSize.R64, RegName.SP), ImmediateVal(-16)),
|
||||
// Store stack pointer in rbp as it is callee saved
|
||||
And(Register(RegSize.R64, RegName.SP), ImmediateVal(-16))
|
||||
)
|
||||
}
|
||||
|
||||
// Missing a sub instruction but dont think we need it
|
||||
def funcPrologue(): List[AsmLine] = {
|
||||
List(
|
||||
Push(Register(RegSize.R64, RegName.BP)),
|
||||
Move(Register(RegSize.R64, RegName.BP), Register(RegSize.R64, RegName.SP))
|
||||
)
|
||||
}
|
||||
|
||||
def restoreStack()(using stack: LinkedHashMap[Ident, Int]): List[AsmLine] = {
|
||||
def funcEpilogue(): List[AsmLine] = {
|
||||
List(
|
||||
Move(Register(RegSize.R64, RegName.SP), Register(RegSize.R64, RegName.BP)),
|
||||
Pop(Register(RegSize.R64, RegName.BP))
|
||||
@ -123,4 +177,84 @@ object asmGenerator {
|
||||
|
||||
// def saveRegs(regList: List[Register]): List[AsmLine] = regList.map(Push(_))
|
||||
// def restoreRegs(regList: List[Register]): List[AsmLine] = regList.reverse.map(Pop(_))
|
||||
|
||||
// TODO: refactor, really ugly function
|
||||
def printF(expr: Expr)(using
|
||||
stack: LinkedHashMap[Ident, Int],
|
||||
strings: ListBuffer[String]
|
||||
): List[AsmLine] = {
|
||||
// determine the format string
|
||||
expr.ty match {
|
||||
case KnownType.String =>
|
||||
strings += PrintFormat.String.toString
|
||||
case KnownType.Char =>
|
||||
strings += PrintFormat.Char.toString
|
||||
case KnownType.Int =>
|
||||
strings += PrintFormat.Int.toString
|
||||
case _ =>
|
||||
strings += PrintFormat.String.toString
|
||||
}
|
||||
List(
|
||||
Load(
|
||||
Register(RegSize.R64, RegName.DI),
|
||||
IndexAddress(
|
||||
Register(RegSize.R64, RegName.IP),
|
||||
LabelArg(s".L.str${strings.size - 1}")
|
||||
)
|
||||
)
|
||||
)
|
||||
++
|
||||
// determine the actual value to print
|
||||
(if (expr.ty == KnownType.Bool) {
|
||||
expr match {
|
||||
case BoolLiter(true) => {
|
||||
strings += "true"
|
||||
}
|
||||
case _ => {
|
||||
strings += "false"
|
||||
}
|
||||
}
|
||||
List(
|
||||
Load(
|
||||
Register(RegSize.R64, RegName.DI),
|
||||
IndexAddress(
|
||||
Register(RegSize.R64, RegName.IP),
|
||||
LabelArg(s".L.str${strings.size - 1}")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
} else {
|
||||
evalExprIntoReg(expr, Register(RegSize.R64, RegName.SI))
|
||||
})
|
||||
// print the value
|
||||
++
|
||||
List(
|
||||
assemblyIR.Call(CLibFunc.PrintF),
|
||||
Move(Register(RegSize.R64, RegName.DI), ImmediateVal(0)),
|
||||
assemblyIR.Call(CLibFunc.Fflush)
|
||||
)
|
||||
}
|
||||
|
||||
// prints a new line
|
||||
def printLn()(using
|
||||
stack: LinkedHashMap[Ident, Int],
|
||||
strings: ListBuffer[String]
|
||||
): List[AsmLine] = {
|
||||
strings += ""
|
||||
Load(
|
||||
Register(RegSize.R64, RegName.DI),
|
||||
IndexAddress(
|
||||
Register(RegSize.R64, RegName.IP),
|
||||
LabelArg(s".L.str${strings.size - 1}")
|
||||
)
|
||||
)
|
||||
::
|
||||
List(
|
||||
assemblyIR.Call(CLibFunc.Puts),
|
||||
Move(Register(RegSize.R64, RegName.DI), ImmediateVal(0)),
|
||||
assemblyIR.Call(CLibFunc.Fflush)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -143,8 +143,17 @@ object assemblyIR {
|
||||
case Text => ".text"
|
||||
case RoData => ".section .rodata"
|
||||
case Int(value) => s".int $value"
|
||||
case Asciz(string) => s".asciz $string"
|
||||
case Asciz(string) => s".asciz \"$string\""
|
||||
}
|
||||
}
|
||||
|
||||
enum PrintFormat {
|
||||
case Int, Char, String
|
||||
|
||||
override def toString(): String = this match {
|
||||
case Int => "%d"
|
||||
case Char => "%c"
|
||||
case String => "%s"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll with Paral
|
||||
.drop(outputLineIdx + 1)
|
||||
.takeWhile(_.startsWith("#"))
|
||||
.map(_.stripPrefix("#").stripLeading)
|
||||
.mkString("\n")
|
||||
.mkString("")
|
||||
|
||||
val exitLineIdx = contents.indexWhere(_.matches("^# ?[Ee]xit:.*$"))
|
||||
val expectedExit =
|
||||
@ -79,24 +79,24 @@ class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll with Paral
|
||||
Seq(
|
||||
// format: off
|
||||
// disable formatting to avoid binPack
|
||||
"^.*wacc-examples/valid/advanced.*$",
|
||||
"^.*wacc-examples/valid/array.*$",
|
||||
"^.*wacc-examples/valid/basic/exit.*$",
|
||||
"^.*wacc-examples/valid/basic/skip.*$",
|
||||
"^.*wacc-examples/valid/expressions.*$",
|
||||
"^.*wacc-examples/valid/function/nested_functions.*$",
|
||||
"^.*wacc-examples/valid/function/simple_functions.*$",
|
||||
"^.*wacc-examples/valid/if.*$",
|
||||
"^.*wacc-examples/valid/IO/print.*$",
|
||||
"^.*wacc-examples/valid/IO/read.*$",
|
||||
"^.*wacc-examples/valid/IO/IOLoop.wacc.*$",
|
||||
"^.*wacc-examples/valid/IO/IOSequence.wacc.*$",
|
||||
"^.*wacc-examples/valid/pairs.*$",
|
||||
"^.*wacc-examples/valid/runtimeErr.*$",
|
||||
"^.*wacc-examples/valid/scope.*$",
|
||||
"^.*wacc-examples/valid/sequence.*$",
|
||||
"^.*wacc-examples/valid/variables.*$",
|
||||
"^.*wacc-examples/valid/while.*$",
|
||||
// "^.*wacc-examples/valid/advanced.*$",
|
||||
// "^.*wacc-examples/valid/array.*$",
|
||||
// "^.*wacc-examples/valid/basic/exit.*$",
|
||||
// "^.*wacc-examples/valid/basic/skip.*$",
|
||||
// "^.*wacc-examples/valid/expressions.*$",
|
||||
// "^.*wacc-examples/valid/function/nested_functions.*$",
|
||||
// "^.*wacc-examples/valid/function/simple_functions.*$",
|
||||
// "^.*wacc-examples/valid/if.*$",
|
||||
// "^.*wacc-examples/valid/IO/print.*$",
|
||||
// "^.*wacc-examples/valid/IO/read.*$",
|
||||
// "^.*wacc-examples/valid/IO/IOLoop.wacc.*$",
|
||||
// "^.*wacc-examples/valid/IO/IOSequence.wacc.*$",
|
||||
// "^.*wacc-examples/valid/pairs.*$",
|
||||
// "^.*wacc-examples/valid/runtimeErr.*$",
|
||||
// "^.*wacc-examples/valid/scope.*$",
|
||||
// "^.*wacc-examples/valid/sequence.*$",
|
||||
// "^.*wacc-examples/valid/variables.*$",
|
||||
// "^.*wacc-examples/valid/while.*$",
|
||||
// format: on
|
||||
).find(filename.matches).isDefined
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user