feat: almost complete clib calls
This commit is contained in:
		| @@ -15,12 +15,15 @@ object asmGenerator { | |||||||
|  |  | ||||||
|     val progAsm = |     val progAsm = | ||||||
|       LabelDef("main") :: |       LabelDef("main") :: | ||||||
|  |         funcPrologue() ++ | ||||||
|  |         alignStack() ++ | ||||||
|         main.flatMap(generateStmt) ++ |         main.flatMap(generateStmt) ++ | ||||||
|  |         funcEpilogue() ++ | ||||||
|         List(assemblyIR.Return()) ++ |         List(assemblyIR.Return()) ++ | ||||||
|         generateFuncs() |         generateFuncs() | ||||||
|  |  | ||||||
|     val strDirs = strings.toList.zipWithIndex.flatMap { case (str, i) => |     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) ++ |     List(Directive.IntelSyntax, Directive.Global("main"), Directive.RoData) ++ | ||||||
| @@ -42,31 +45,47 @@ object asmGenerator { | |||||||
|   )(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] = |   )(using stack: LinkedHashMap[Ident, Int], strings: ListBuffer[String]): List[AsmLine] = | ||||||
|     stmt match { |     stmt match { | ||||||
|       case microWacc.Call(Builtin.Exit, code :: _) => |       case microWacc.Call(Builtin.Exit, code :: _) => | ||||||
|         alignStack() ++ |         // alignStack() ++ | ||||||
|         evalExprIntoReg(code, Register(RegSize.R64, RegName.DI)) ++ |         evalExprIntoReg(code, Register(RegSize.R64, RegName.DI)) ++ | ||||||
|           List(assemblyIR.Call(CLibFunc.Exit)) |           List(assemblyIR.Call(CLibFunc.Exit)) | ||||||
|  |  | ||||||
|       case microWacc.Call(Builtin.Println, expr :: _) => |       case microWacc.Call(Builtin.Println, expr :: _) => | ||||||
|         alignStack() ++ |         // alignStack() ++ | ||||||
|           evalExprIntoReg(expr, Register(RegSize.R64, RegName.DI)) ++ |         printF(expr) ++ | ||||||
|           List( |           printLn() | ||||||
|             assemblyIR.Call(CLibFunc.Puts), |  | ||||||
|             Move(Register(RegSize.R64, RegName.DI), ImmediateVal(0)), |  | ||||||
|             assemblyIR.Call(CLibFunc.Fflush) |  | ||||||
|           ) ++ |  | ||||||
|           restoreStack() |  | ||||||
|  |  | ||||||
|       case microWacc.Call(Builtin.ReadInt, expr :: _) => |       case microWacc.Call(Builtin.Print, expr :: _) => | ||||||
|         List() |         // alignStack() ++ | ||||||
|  |         printF(expr) | ||||||
|  |  | ||||||
|       case Assign(lhs, rhs) => |       case Assign(lhs, rhs) => | ||||||
|         lhs match { |         var dest: IndexAddress = | ||||||
|  |           IndexAddress(Register(RegSize.R64, RegName.SP), 0) // gets overrwitten | ||||||
|  |         (lhs match { | ||||||
|           case ident: Ident => |           case ident: Ident => | ||||||
|             stack += (ident -> stack.size) |             if (!stack.contains(ident)) { | ||||||
|             evalExprIntoReg(rhs, Register(RegSize.R64, RegName.AX)) ++ |               stack += (ident -> (stack.size + 1)) | ||||||
|               List(Push(Register(RegSize.R64, RegName.AX))) |               dest = accessVar(ident) | ||||||
|           case _ => List() |               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() |       case _ => List() | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -74,22 +93,20 @@ object asmGenerator { | |||||||
|       stack: LinkedHashMap[Ident, Int], |       stack: LinkedHashMap[Ident, Int], | ||||||
|       strings: ListBuffer[String] |       strings: ListBuffer[String] | ||||||
|   ): List[AsmLine] = { |   ): List[AsmLine] = { | ||||||
|     var src: Src = ImmediateVal(0) // Placeholder |     expr match { | ||||||
|     (expr match { |  | ||||||
|       case IntLiter(v) => |       case IntLiter(v) => | ||||||
|         src = ImmediateVal(v) |         List(Move(dest, ImmediateVal(v))) | ||||||
|         List() |       case CharLiter(v) => | ||||||
|  |         List(Move(dest, ImmediateVal(v.toInt))) | ||||||
|       case ident: Ident => |       case ident: Ident => | ||||||
|         List( |         List(Move(dest, accessVar(ident))) | ||||||
|           Move( |  | ||||||
|             dest, |  | ||||||
|             IndexAddress(Register(RegSize.R64, RegName.SP), (stack.size - stack(ident)) * 4) |  | ||||||
|           ) |  | ||||||
|         ) |  | ||||||
|       case ArrayLiter(elems) => |       case ArrayLiter(elems) => | ||||||
|         expr.ty match { |         expr.ty match { | ||||||
|           case KnownType.Char => |           case KnownType.String => | ||||||
|             strings += elems.mkString |             strings += elems.map { | ||||||
|  |               case CharLiter(v) => v | ||||||
|  |               case _            => "" | ||||||
|  |             }.mkString | ||||||
|             List( |             List( | ||||||
|               Load( |               Load( | ||||||
|                 dest, |                 dest, | ||||||
| @@ -99,22 +116,59 @@ object asmGenerator { | |||||||
|                 ) |                 ) | ||||||
|               ) |               ) | ||||||
|             ) |             ) | ||||||
|  |           // TODO other array types | ||||||
|           case _ => List() |           case _ => List() | ||||||
|         } |         } | ||||||
|  |       // TODO other expr types | ||||||
|       case _ => List() |       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] = { |   def alignStack()(using stack: LinkedHashMap[Ident, Int]): List[AsmLine] = { | ||||||
|     List( |     List( | ||||||
|       And(Register(RegSize.R64, RegName.SP), ImmediateVal(-16)), |       And(Register(RegSize.R64, RegName.SP), ImmediateVal(-16)) | ||||||
|       // Store stack pointer in rbp as it is callee saved |     ) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Missing a sub instruction but dont think we need it | ||||||
|  |   def funcPrologue(): List[AsmLine] = { | ||||||
|  |     List( | ||||||
|       Push(Register(RegSize.R64, RegName.BP)), |       Push(Register(RegSize.R64, RegName.BP)), | ||||||
|       Move(Register(RegSize.R64, RegName.BP), Register(RegSize.R64, RegName.SP)) |       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( |     List( | ||||||
|       Move(Register(RegSize.R64, RegName.SP), Register(RegSize.R64, RegName.BP)), |       Move(Register(RegSize.R64, RegName.SP), Register(RegSize.R64, RegName.BP)), | ||||||
|       Pop(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 saveRegs(regList: List[Register]): List[AsmLine] = regList.map(Push(_)) | ||||||
|   // def restoreRegs(regList: List[Register]): List[AsmLine] = regList.reverse.map(Pop(_)) |   // 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 Text          => ".text" | ||||||
|       case RoData        => ".section .rodata" |       case RoData        => ".section .rodata" | ||||||
|       case Int(value)    => s".int $value" |       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) |             .drop(outputLineIdx + 1) | ||||||
|             .takeWhile(_.startsWith("#")) |             .takeWhile(_.startsWith("#")) | ||||||
|             .map(_.stripPrefix("#").stripLeading) |             .map(_.stripPrefix("#").stripLeading) | ||||||
|             .mkString("\n") |             .mkString("") | ||||||
|  |  | ||||||
|       val exitLineIdx = contents.indexWhere(_.matches("^# ?[Ee]xit:.*$")) |       val exitLineIdx = contents.indexWhere(_.matches("^# ?[Ee]xit:.*$")) | ||||||
|       val expectedExit = |       val expectedExit = | ||||||
| @@ -79,24 +79,24 @@ class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll with Paral | |||||||
|     Seq( |     Seq( | ||||||
|       // format: off |       // format: off | ||||||
|       // disable formatting to avoid binPack |       // disable formatting to avoid binPack | ||||||
|       "^.*wacc-examples/valid/advanced.*$", |       // "^.*wacc-examples/valid/advanced.*$", | ||||||
|       "^.*wacc-examples/valid/array.*$", |       // "^.*wacc-examples/valid/array.*$", | ||||||
|       "^.*wacc-examples/valid/basic/exit.*$", |       // "^.*wacc-examples/valid/basic/exit.*$", | ||||||
|       "^.*wacc-examples/valid/basic/skip.*$", |       // "^.*wacc-examples/valid/basic/skip.*$", | ||||||
|       "^.*wacc-examples/valid/expressions.*$", |       // "^.*wacc-examples/valid/expressions.*$", | ||||||
|       "^.*wacc-examples/valid/function/nested_functions.*$", |       // "^.*wacc-examples/valid/function/nested_functions.*$", | ||||||
|       "^.*wacc-examples/valid/function/simple_functions.*$", |       // "^.*wacc-examples/valid/function/simple_functions.*$", | ||||||
|       "^.*wacc-examples/valid/if.*$", |       // "^.*wacc-examples/valid/if.*$", | ||||||
|       "^.*wacc-examples/valid/IO/print.*$", |       // "^.*wacc-examples/valid/IO/print.*$", | ||||||
|       "^.*wacc-examples/valid/IO/read.*$", |       // "^.*wacc-examples/valid/IO/read.*$", | ||||||
|       "^.*wacc-examples/valid/IO/IOLoop.wacc.*$", |       // "^.*wacc-examples/valid/IO/IOLoop.wacc.*$", | ||||||
|       "^.*wacc-examples/valid/IO/IOSequence.wacc.*$", |       // "^.*wacc-examples/valid/IO/IOSequence.wacc.*$", | ||||||
|       "^.*wacc-examples/valid/pairs.*$", |       // "^.*wacc-examples/valid/pairs.*$", | ||||||
|       "^.*wacc-examples/valid/runtimeErr.*$", |       // "^.*wacc-examples/valid/runtimeErr.*$", | ||||||
|       "^.*wacc-examples/valid/scope.*$", |       // "^.*wacc-examples/valid/scope.*$", | ||||||
|       "^.*wacc-examples/valid/sequence.*$", |       // "^.*wacc-examples/valid/sequence.*$", | ||||||
|       "^.*wacc-examples/valid/variables.*$", |       // "^.*wacc-examples/valid/variables.*$", | ||||||
|       "^.*wacc-examples/valid/while.*$", |       // "^.*wacc-examples/valid/while.*$", | ||||||
|       // format: on |       // format: on | ||||||
|     ).find(filename.matches).isDefined |     ).find(filename.matches).isDefined | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user