feat: implemented println and exit
This commit is contained in:
parent
67f7e64b95
commit
02e741c52e
111
src/main/wacc/backend/asmGenerator.scala
Normal file
111
src/main/wacc/backend/asmGenerator.scala
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package wacc
|
||||||
|
|
||||||
|
import scala.collection.mutable.LinkedHashMap
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
|
object asmGenerator {
|
||||||
|
import microWacc._
|
||||||
|
import assemblyIR._
|
||||||
|
import wacc.types._
|
||||||
|
|
||||||
|
def generateAsm(microProg: Program): List[AsmLine] = {
|
||||||
|
given stack: LinkedHashMap[Ident, Int] = LinkedHashMap[Ident, Int]()
|
||||||
|
given strings: ListBuffer[String] = ListBuffer[String]()
|
||||||
|
val Program(funcs, main) = microProg
|
||||||
|
|
||||||
|
val progAsm =
|
||||||
|
LabelDef("main") ::
|
||||||
|
main.flatMap(generateStmt) ++
|
||||||
|
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.IntelSyntax, Directive.Global("main"), Directive.RoData) ++
|
||||||
|
strDirs ++
|
||||||
|
List(Directive.Text) ++
|
||||||
|
progAsm
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
def generateFuncs()(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] = {
|
||||||
|
List()
|
||||||
|
}
|
||||||
|
|
||||||
|
def generateStmt(stmt: Stmt)(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] =
|
||||||
|
stmt match {
|
||||||
|
case microWacc.Call(Builtin.Exit, code :: _) =>
|
||||||
|
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()
|
||||||
|
|
||||||
|
case microWacc.Call(Builtin.ReadInt, expr :: _) =>
|
||||||
|
List()
|
||||||
|
|
||||||
|
case Assign(lhs, rhs) =>
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
case _ => List()
|
||||||
|
}
|
||||||
|
|
||||||
|
def evalExprIntoReg(expr: Expr, dest: Register)
|
||||||
|
(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] = {
|
||||||
|
var src: Src = ImmediateVal(0) // Placeholder
|
||||||
|
(expr match {
|
||||||
|
case IntLiter(v) =>
|
||||||
|
src = ImmediateVal(v)
|
||||||
|
List()
|
||||||
|
case ident: Ident =>
|
||||||
|
List(
|
||||||
|
Move(
|
||||||
|
dest,
|
||||||
|
IndexAddress(Register(RegSize.R64, RegName.SP), (stack.size - stack(ident)) * 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case ArrayLiter(elems) => expr.ty match {
|
||||||
|
case KnownType.Char =>
|
||||||
|
strings += elems.mkString
|
||||||
|
List(
|
||||||
|
Load(dest, IndexAddress(Register(RegSize.R64, RegName.IP),LabelArg(s".L.str${strings.size - 1}")))
|
||||||
|
)
|
||||||
|
case _ => List()
|
||||||
|
}
|
||||||
|
case _ => List()
|
||||||
|
}) ++ List(Move(dest, src))
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
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] = {
|
||||||
|
List(
|
||||||
|
Move(Register(RegSize.R64, RegName.SP), Register(RegSize.R64, RegName.BP)),
|
||||||
|
Pop(Register(RegSize.R64, RegName.BP))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// def saveRegs(regList: List[Register]): List[AsmLine] = regList.map(Push(_))
|
||||||
|
// def restoreRegs(regList: List[Register]): List[AsmLine] = regList.reverse.map(Pop(_))
|
||||||
|
}
|
@ -16,6 +16,29 @@ object assemblyIR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum RegName {
|
||||||
|
case AX, BX, CX, DX, SI, DI, SP, BP, IP, Reg8, Reg9, Reg10, Reg11, Reg12, Reg13, Reg14, Reg15
|
||||||
|
override def toString = this match {
|
||||||
|
case AX => "ax"
|
||||||
|
case BX => "bx"
|
||||||
|
case CX => "cx"
|
||||||
|
case DX => "dx"
|
||||||
|
case SI => "si"
|
||||||
|
case DI => "di"
|
||||||
|
case SP => "sp"
|
||||||
|
case BP => "bp"
|
||||||
|
case IP => "ip"
|
||||||
|
case Reg8 => "8"
|
||||||
|
case Reg9 => "9"
|
||||||
|
case Reg10 => "10"
|
||||||
|
case Reg11 => "11"
|
||||||
|
case Reg12 => "12"
|
||||||
|
case Reg13 => "13"
|
||||||
|
case Reg14 => "14"
|
||||||
|
case Reg15 => "15"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// arguments
|
// arguments
|
||||||
enum CLibFunc extends Operand {
|
enum CLibFunc extends Operand {
|
||||||
case Scanf,
|
case Scanf,
|
||||||
@ -35,13 +58,8 @@ object assemblyIR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Register extends Dest with Src {
|
case class Register(size: RegSize, name: RegName) extends Dest with Src {
|
||||||
case Named(name: String, size: RegSize)
|
override def toString = s"${size}${name}"
|
||||||
case Scratch(num: Int, size: RegSize)
|
|
||||||
override def toString = this match {
|
|
||||||
case Named(name, size) => s"${size}${name.toLowerCase()}"
|
|
||||||
case Scratch(num, size) => s"r${num}${if (size == RegSize.E32) "d" else ""}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case class MemLocation(pointer: Long | Register) extends Dest with Src {
|
case class MemLocation(pointer: Long | Register) extends Dest with Src {
|
||||||
override def toString = pointer match {
|
override def toString = pointer match {
|
||||||
@ -49,6 +67,9 @@ object assemblyIR {
|
|||||||
case reg: Register => s"[$reg]"
|
case reg: Register => s"[$reg]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case class IndexAddress(base: Register, offset: Int | LabelArg) extends Dest with Src {
|
||||||
|
override def toString = s"[$base + $offset]"
|
||||||
|
}
|
||||||
|
|
||||||
case class ImmediateVal(value: Int) extends Src {
|
case class ImmediateVal(value: Int) extends Src {
|
||||||
override def toString = value.toString
|
override def toString = value.toString
|
||||||
@ -74,10 +95,10 @@ object assemblyIR {
|
|||||||
// stack operations
|
// stack operations
|
||||||
case class Push(op1: Src) extends Operation("push", op1)
|
case class Push(op1: Src) extends Operation("push", op1)
|
||||||
case class Pop(op1: Src) extends Operation("pop", op1)
|
case class Pop(op1: Src) extends Operation("pop", op1)
|
||||||
case class Call(op1: CLibFunc) extends Operation("call", op1)
|
case class Call(op1: CLibFunc | LabelArg) extends Operation("call", op1)
|
||||||
|
|
||||||
case class Move(op1: Dest, op2: Src) extends Operation("mov", op1, op2)
|
case class Move(op1: Dest, op2: Src) extends Operation("mov", op1, op2)
|
||||||
case class Load(op1: Register, op2: MemLocation) extends Operation("lea ", op1, op2)
|
case class Load(op1: Register, op2: MemLocation | IndexAddress) extends Operation("lea ", op1, op2)
|
||||||
|
|
||||||
case class Return() extends Operation("ret")
|
case class Return() extends Operation("ret")
|
||||||
|
|
||||||
@ -108,4 +129,21 @@ object assemblyIR {
|
|||||||
case Always => "mp"
|
case Always => "mp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Directive extends AsmLine {
|
||||||
|
case IntelSyntax, RoData, Text
|
||||||
|
case Global(name: String)
|
||||||
|
case Int(value: scala.Int)
|
||||||
|
case Asciz(string: String)
|
||||||
|
|
||||||
|
override def toString(): String = this match {
|
||||||
|
case IntelSyntax => ".intel_syntax noprefix"
|
||||||
|
case Global(name) => s".globl $name"
|
||||||
|
case Text => ".text"
|
||||||
|
case RoData => ".section .rodata"
|
||||||
|
case Int(value) => s".int $value"
|
||||||
|
case Asciz(string) => s".asciz $string"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user