From 1a39950a7b165d4882b7039e192578125eae4a2c Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 28 Feb 2025 16:26:40 +0000 Subject: [PATCH 1/7] refactor: merge MemLocation with IndexedAddress --- src/main/wacc/backend/RuntimeError.scala | 12 +++---- src/main/wacc/backend/Stack.scala | 8 ++--- src/main/wacc/backend/asmGenerator.scala | 33 ++++++++++--------- src/main/wacc/backend/assemblyIR.scala | 40 +++++++++++++++--------- src/test/wacc/instructionSpec.scala | 9 +++++- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/main/wacc/backend/RuntimeError.scala b/src/main/wacc/backend/RuntimeError.scala index 8e12831..aa0ebd3 100644 --- a/src/main/wacc/backend/RuntimeError.scala +++ b/src/main/wacc/backend/RuntimeError.scala @@ -28,7 +28,7 @@ object RuntimeError { protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( stackAlign, - Load(RDI, IndexAddress(RIP, getErrLabel)), + Load(RDI, MemLocation(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(-1)), assemblyIR.Call(CLibFunc.Exit) @@ -43,7 +43,7 @@ object RuntimeError { protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( Pop(RSI), stackAlign, - Load(RDI, IndexAddress(RIP, getErrLabel)), + Load(RDI, MemLocation(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) @@ -57,7 +57,7 @@ object RuntimeError { protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( stackAlign, - Load(RDI, IndexAddress(RIP, getErrLabel)), + Load(RDI, MemLocation(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) @@ -71,7 +71,7 @@ object RuntimeError { protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( stackAlign, - Load(RDI, IndexAddress(RIP, getErrLabel)), + Load(RDI, MemLocation(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) @@ -86,7 +86,7 @@ object RuntimeError { protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( Move(RSI, RCX), stackAlign, - Load(RDI, IndexAddress(RIP, getErrLabel)), + Load(RDI, MemLocation(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) @@ -99,7 +99,7 @@ object RuntimeError { def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( stackAlign, - Load(RDI, IndexAddress(RIP, getErrLabel)), + Load(RDI, MemLocation(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) diff --git a/src/main/wacc/backend/Stack.scala b/src/main/wacc/backend/Stack.scala index 94b329a..1c57726 100644 --- a/src/main/wacc/backend/Stack.scala +++ b/src/main/wacc/backend/Stack.scala @@ -79,12 +79,12 @@ class Stack { lines } - /** Get an IndexAddress for a variable in the stack. */ - def accessVar(ident: mw.Ident): IndexAddress = - IndexAddress(RSP, sizeBytes - stack(ident).bottom) + /** Get an MemLocation for a variable in the stack. */ + def accessVar(ident: mw.Ident): MemLocation = + MemLocation(RSP, sizeBytes - stack(ident).bottom, opSize = Some(ident.ty.size)) def contains(ident: mw.Ident): Boolean = stack.contains(ident) - def head: MemLocation = MemLocation(RSP, stack.last._2.size) + def head: MemLocation = MemLocation(RSP, opSize = Some(stack.last._2.size)) override def toString(): String = stack.toString } diff --git a/src/main/wacc/backend/asmGenerator.scala b/src/main/wacc/backend/asmGenerator.scala index 2a7366d..e2a0fec 100644 --- a/src/main/wacc/backend/asmGenerator.scala +++ b/src/main/wacc/backend/asmGenerator.scala @@ -112,8 +112,8 @@ object asmGenerator { Builtin.PrintCharArray, Chain( stackAlign, - Load(RDX, IndexAddress(RSI, KnownType.Int.size.toInt)), - Move(Register(D32, SI), MemLocation(RSI, D32)), + Load(RDX, MemLocation(RSI, KnownType.Int.size.toInt)), + Move(Register(D32, SI), MemLocation(RSI, opSize = Some(D32))), assemblyIR.Call(CLibFunc.PrintF), Xor(RDI, RDI), assemblyIR.Call(CLibFunc.Fflush) @@ -148,7 +148,7 @@ object asmGenerator { stackAlign, Subtract(Register(Q64, SP), ImmediateVal(8)), Push(RSI), - Load(RSI, MemLocation(Register(Q64, SP), Q64)), + Load(RSI, MemLocation(Register(Q64, SP), opSize = Some(Q64))), assemblyIR.Call(CLibFunc.Scanf), Pop(RAX) ) @@ -167,9 +167,10 @@ object asmGenerator { lhs match { case ident: Ident => if (!stack.contains(ident)) asm += stack.reserve(ident) + val dest = Register(ident.ty.size, AX) asm ++= evalExprOntoStack(rhs) asm += stack.pop(RAX) - asm += Move(stack.accessVar(ident), RAX) + asm += Move(stack.accessVar(ident), dest) case ArrayElem(x, i) => asm ++= evalExprOntoStack(rhs) asm ++= evalExprOntoStack(i) @@ -182,12 +183,12 @@ object asmGenerator { asm += stack.pop(RCX) asm += Compare(EAX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(NullPtrError), Cond.Equal) - asm += Compare(MemLocation(RAX, D32), ECX) + asm += Compare(MemLocation(RAX, opSize = Some(D32)), ECX) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.LessEqual) asm += stack.pop(RDX) asm += Move( - IndexAddress(RAX, KnownType.Int.size.toInt, RCX, x.ty.elemSize.toInt), + MemLocation(RAX, KnownType.Int.size.toInt, (RCX, x.ty.elemSize.toInt)), Register(x.ty.elemSize, DX) ) } @@ -248,13 +249,17 @@ object asmGenerator { expr match { case IntLiter(v) => asm += stack.push(KnownType.Int.size, ImmediateVal(v)) case CharLiter(v) => asm += stack.push(KnownType.Char.size, ImmediateVal(v.toInt)) - case ident: Ident => asm += stack.push(ident.ty.size, stack.accessVar(ident)) + case ident: Ident => + val location = stack.accessVar(ident) + // items in stack are guaranteed to be in Q64 slots, + // so we are safe to wipe the opSize from the memory location + asm += stack.push(ident.ty.size, location.copy(opSize = None)) case array @ ArrayLiter(elems) => expr.ty match { case KnownType.String => val str = elems.collect { case CharLiter(v) => v }.mkString - asm += Load(RAX, IndexAddress(RIP, labelGenerator.getLabelArg(str))) + asm += Load(RAX, MemLocation(RIP, labelGenerator.getLabelArg(str))) asm += stack.push(Q64, RAX) case ty => asm ++= generateCall( @@ -263,12 +268,12 @@ object asmGenerator { ) asm += stack.push(Q64, RAX) // Store the length of the array at the start - asm += Move(MemLocation(RAX, D32), ImmediateVal(elems.size)) + asm += Move(MemLocation(RAX, opSize = Some(D32)), ImmediateVal(elems.size)) elems.zipWithIndex.foldMap { (elem, i) => asm ++= evalExprOntoStack(elem) asm += stack.pop(RCX) asm += stack.pop(RAX) - asm += Move(IndexAddress(RAX, 4 + i * ty.elemSize.toInt), Register(ty.elemSize, CX)) + asm += Move(MemLocation(RAX, 4 + i * ty.elemSize.toInt), Register(ty.elemSize, CX)) asm += stack.push(Q64, RAX) } } @@ -289,12 +294,12 @@ object asmGenerator { asm += stack.pop(RAX) asm += Compare(EAX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(NullPtrError), Cond.Equal) - asm += Compare(MemLocation(RAX, D32), ECX) + asm += Compare(MemLocation(RAX, opSize = Some(D32)), ECX) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.LessEqual) // + Int because we store the length of the array at the start asm += Move( Register(x.ty.elemSize, AX), - IndexAddress(RAX, KnownType.Int.size.toInt, RCX, x.ty.elemSize.toInt) + MemLocation(RAX, KnownType.Int.size.toInt, (RCX, x.ty.elemSize.toInt)) ) asm += stack.push(x.ty.elemSize, RAX) case UnaryOp(x, op) => @@ -308,7 +313,7 @@ object asmGenerator { case UnaryOperator.Ord => // No op needed case UnaryOperator.Len => asm += stack.pop(RAX) - asm += Move(EAX, MemLocation(RAX, D32)) + asm += Move(EAX, MemLocation(RAX, opSize = Some(D32))) asm += stack.push(D32, RAX) case UnaryOperator.Negate => asm += Xor(EAX, EAX) @@ -376,7 +381,7 @@ object asmGenerator { stack.size == stackSizeStart + 1, "Sanity check: ONLY the evaluated expression should have been pushed onto the stack" ) - asm ++= zeroRest(MemLocation(stack.head.pointer, Q64), expr.ty.size) + asm ++= zeroRest(MemLocation(base = stack.head.base, opSize = Some(Q64)), expr.ty.size) asm } diff --git a/src/main/wacc/backend/assemblyIR.scala b/src/main/wacc/backend/assemblyIR.scala index 9ba65ea..d265358 100644 --- a/src/main/wacc/backend/assemblyIR.scala +++ b/src/main/wacc/backend/assemblyIR.scala @@ -97,22 +97,33 @@ object assemblyIR { } } - case class MemLocation(pointer: Register, opSize: Size) extends Dest with Src { - override def toString = - opSize.toString + s"[$pointer]" - } - - case class IndexAddress( + case class MemLocation( base: Register, - offset: Int | LabelArg, - indexReg: Register = Register(Size.Q64, RegName.AX), - scale: Int = 0 + offset: Int | LabelArg = 0, + // scale 0 will make register irrelevant, no other reason as to why it's RAX + scaledIndex: (Register, Int) = (Register(Size.Q64, RegName.AX), 0), + opSize: Option[Size] = None ) extends Dest with Src { - override def toString = if (scale != 0) { - s"[$base + $indexReg * $scale + $offset]" - } else { - s"[$base + $offset]" + def copy( + base: Register = this.base, + offset: Int | LabelArg = this.offset, + scaledIndex: (Register, Int) = this.scaledIndex, + opSize: Option[Size] = this.opSize + ): MemLocation = MemLocation(base, offset, scaledIndex, opSize) + + override def toString(): String = { + val opSizeStr = opSize.map(_.toString).getOrElse("") + val baseStr = base.toString + val offsetStr = offset match { + case 0 => "" + case off => s" + $off" + } + val scaledIndexStr = scaledIndex match { + case (reg, scale) if scale != 0 => s" + $reg * $scale" + case _ => "" + } + s"$opSizeStr[$baseStr$scaledIndexStr$offsetStr]" } } @@ -145,8 +156,7 @@ object assemblyIR { case class Pop(op1: Src) extends Operation("pop", op1) // move operations case class Move(op1: Dest, op2: Src) extends Operation("mov", op1, op2) - case class Load(op1: Register, op2: MemLocation | IndexAddress) - extends Operation("lea ", op1, op2) + case class Load(op1: Register, op2: MemLocation) extends Operation("lea ", op1, op2) // function call operations case class Call(op1: CLibFunc | LabelArg) extends Operation("call", op1) diff --git a/src/test/wacc/instructionSpec.scala b/src/test/wacc/instructionSpec.scala index feef0d4..569297e 100644 --- a/src/test/wacc/instructionSpec.scala +++ b/src/test/wacc/instructionSpec.scala @@ -29,12 +29,19 @@ class instructionSpec extends AnyFunSuite { assert(scratch32BitRegister.toString == "r8d") } - val memLocationWithRegister = MemLocation(named64BitRegister, Q64) + val memLocationWithRegister = MemLocation(named64BitRegister, opSize = Some(Q64)) test("mem location with register toString") { assert(memLocationWithRegister.toString == "qword ptr [rax]") } + val memLocationFull = + MemLocation(named64BitRegister, 32, (scratch64BitRegister, 10), Some(B8)) + + test("mem location with all fields toString") { + assert(memLocationFull.toString == "byte ptr [rax + r8 * 10 + 32]") + } + val immediateVal = ImmediateVal(123) test("immediate value toString") { From e1d90eabf91abb70ca9dcb23a34aec6cce2c71bc Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 28 Feb 2025 16:40:58 +0000 Subject: [PATCH 2/7] fix: use MemLocation.copy for zeroRest --- src/main/wacc/backend/asmGenerator.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/wacc/backend/asmGenerator.scala b/src/main/wacc/backend/asmGenerator.scala index e2a0fec..0b05b6f 100644 --- a/src/main/wacc/backend/asmGenerator.scala +++ b/src/main/wacc/backend/asmGenerator.scala @@ -381,7 +381,7 @@ object asmGenerator { stack.size == stackSizeStart + 1, "Sanity check: ONLY the evaluated expression should have been pushed onto the stack" ) - asm ++= zeroRest(MemLocation(base = stack.head.base, opSize = Some(Q64)), expr.ty.size) + asm ++= zeroRest(stack.head.copy(opSize = Some(Q64)), expr.ty.size) asm } From 68903f5b699891535182d37344e62759f8f17a0b Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 28 Feb 2025 17:21:45 +0000 Subject: [PATCH 3/7] refactor: use explicit sizes in asmGenerator --- src/main/wacc/backend/asmGenerator.scala | 65 ++++++++++++---------- src/main/wacc/backend/sizeExtensions.scala | 2 - 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/main/wacc/backend/asmGenerator.scala b/src/main/wacc/backend/asmGenerator.scala index 0b05b6f..db2e694 100644 --- a/src/main/wacc/backend/asmGenerator.scala +++ b/src/main/wacc/backend/asmGenerator.scala @@ -8,7 +8,6 @@ object asmGenerator { import microWacc._ import assemblyIR._ import assemblyIR.commonRegisters._ - import assemblyIR.Size._ import assemblyIR.RegName._ import types._ import sizeExtensions._ @@ -75,12 +74,12 @@ object asmGenerator { given stack: Stack = Stack() // Setup the stack with param 7 and up func.params.drop(argRegs.size).foreach(stack.reserve(_)) - stack.reserve(Q64) // Reserve return pointer slot + stack.reserve(Size.Q64) // Reserve return pointer slot var asm = Chain.one[AsmLine](labelGenerator.getLabelDef(func.name)) asm ++= funcPrologue() // Push the rest of params onto the stack for simplicity argRegs.zip(func.params).foreach { (reg, param) => - asm += stack.push(param, Register(Q64, reg)) + asm += stack.push(param, Register(Size.Q64, reg)) } asm ++= func.body.foldMap(generateStmt(_)) // No need for epilogue here since all user functions must return explicitly @@ -113,7 +112,7 @@ object asmGenerator { Chain( stackAlign, Load(RDX, MemLocation(RSI, KnownType.Int.size.toInt)), - Move(Register(D32, SI), MemLocation(RSI, opSize = Some(D32))), + Move(Register(KnownType.Int.size, SI), MemLocation(RSI, opSize = Some(KnownType.Int.size))), assemblyIR.Call(CLibFunc.PrintF), Xor(RDI, RDI), assemblyIR.Call(CLibFunc.Fflush) @@ -146,9 +145,9 @@ object asmGenerator { Builtin.Read, Chain( stackAlign, - Subtract(Register(Q64, SP), ImmediateVal(8)), + Subtract(Register(Size.Q64, SP), ImmediateVal(8)), Push(RSI), - Load(RSI, MemLocation(Register(Q64, SP), opSize = Some(Q64))), + Load(RSI, MemLocation(Register(Size.Q64, SP), opSize = Some(Size.Q64))), assemblyIR.Call(CLibFunc.Scanf), Pop(RAX) ) @@ -177,13 +176,13 @@ object asmGenerator { asm += stack.pop(RCX) asm += Compare(ECX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.Less) - asm += stack.push(Q64, RCX) + asm += stack.push(KnownType.Int.size, RCX) asm ++= evalExprOntoStack(x) asm += stack.pop(RAX) asm += stack.pop(RCX) - asm += Compare(EAX, ImmediateVal(0)) + asm += Compare(RAX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(NullPtrError), Cond.Equal) - asm += Compare(MemLocation(RAX, opSize = Some(D32)), ECX) + asm += Compare(MemLocation(RAX, opSize = Some(KnownType.Int.size)), ECX) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.LessEqual) asm += stack.pop(RDX) @@ -260,21 +259,27 @@ object asmGenerator { case KnownType.String => val str = elems.collect { case CharLiter(v) => v }.mkString asm += Load(RAX, MemLocation(RIP, labelGenerator.getLabelArg(str))) - asm += stack.push(Q64, RAX) + asm += stack.push(KnownType.String.size, RAX) case ty => asm ++= generateCall( microWacc.Call(Builtin.Malloc, List(IntLiter(array.heapSize))), isTail = false ) - asm += stack.push(Q64, RAX) + asm += stack.push(KnownType.Array(?).size, RAX) // Store the length of the array at the start - asm += Move(MemLocation(RAX, opSize = Some(D32)), ImmediateVal(elems.size)) + asm += Move( + MemLocation(RAX, opSize = Some(KnownType.Int.size)), + ImmediateVal(elems.size) + ) elems.zipWithIndex.foldMap { (elem, i) => asm ++= evalExprOntoStack(elem) asm += stack.pop(RCX) asm += stack.pop(RAX) - asm += Move(MemLocation(RAX, 4 + i * ty.elemSize.toInt), Register(ty.elemSize, CX)) - asm += stack.push(Q64, RAX) + asm += Move( + MemLocation(RAX, KnownType.Int.size.toInt + i * ty.elemSize.toInt), + Register(ty.elemSize, CX) + ) + asm += stack.push(KnownType.Array(?).size, RAX) } } @@ -292,9 +297,9 @@ object asmGenerator { asm += Compare(RCX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.Less) asm += stack.pop(RAX) - asm += Compare(EAX, ImmediateVal(0)) + asm += Compare(RAX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(NullPtrError), Cond.Equal) - asm += Compare(MemLocation(RAX, opSize = Some(D32)), ECX) + asm += Compare(MemLocation(RAX, opSize = Some(KnownType.Int.size)), ECX) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.LessEqual) // + Int because we store the length of the array at the start asm += Move( @@ -313,14 +318,14 @@ object asmGenerator { case UnaryOperator.Ord => // No op needed case UnaryOperator.Len => asm += stack.pop(RAX) - asm += Move(EAX, MemLocation(RAX, opSize = Some(D32))) - asm += stack.push(D32, RAX) + asm += Move(EAX, MemLocation(RAX, opSize = Some(KnownType.Int.size))) + asm += stack.push(KnownType.Int.size, RAX) case UnaryOperator.Negate => asm += Xor(EAX, EAX) asm += Subtract(EAX, stack.head) asm += Jump(labelGenerator.getLabelArg(OverflowError), Cond.Overflow) asm += stack.drop() - asm += stack.push(Q64, RAX) + asm += stack.push(KnownType.Int.size, RAX) case UnaryOperator.Not => asm += Xor(stack.head, ImmediateVal(1)) } @@ -381,7 +386,7 @@ object asmGenerator { stack.size == stackSizeStart + 1, "Sanity check: ONLY the evaluated expression should have been pushed onto the stack" ) - asm ++= zeroRest(stack.head.copy(opSize = Some(Q64)), expr.ty.size) + asm ++= zeroRest(stack.head.copy(opSize = Some(Size.Q64)), expr.ty.size) asm } @@ -402,7 +407,7 @@ object asmGenerator { // And set the appropriate registers .reverse .foreach { reg => - asm += stack.pop(Register(Q64, reg)) + asm += stack.pop(Register(Size.Q64, reg)) } // Evaluate arguments 7 and up and push them onto the stack @@ -431,33 +436,33 @@ object asmGenerator { var asm = Chain.empty[AsmLine] asm += Compare(destX, stack.head) - asm += Set(Register(B8, AX), cond) - asm ++= zeroRest(RAX, B8) + asm += Set(Register(Size.B8, AX), cond) + asm ++= zeroRest(RAX, Size.B8) asm += stack.drop() - asm += stack.push(B8, RAX) + asm += stack.push(Size.B8, RAX) asm } private def funcPrologue()(using stack: Stack): Chain[AsmLine] = { var asm = Chain.empty[AsmLine] - asm += stack.push(Q64, RBP) - asm += Move(RBP, Register(Q64, SP)) + asm += stack.push(Size.Q64, RBP) + asm += Move(RBP, Register(Size.Q64, SP)) asm } private def funcEpilogue(): Chain[AsmLine] = { var asm = Chain.empty[AsmLine] - asm += Move(Register(Q64, SP), RBP) + asm += Move(Register(Size.Q64, SP), RBP) asm += Pop(RBP) asm += assemblyIR.Return() asm } - def stackAlign: AsmLine = And(Register(Q64, SP), ImmediateVal(-16)) + def stackAlign: AsmLine = And(Register(Size.Q64, SP), ImmediateVal(-16)) private def zeroRest(dest: Dest, size: Size): Chain[AsmLine] = size match { - case Q64 | D32 => Chain.empty - case _ => Chain.one(And(dest, ImmediateVal((1 << (size.toInt * 8)) - 1))) + case Size.Q64 | Size.D32 => Chain.empty + case _ => Chain.one(And(dest, ImmediateVal((1 << (size.toInt * 8)) - 1))) } private val escapedCharsMapping = escapedChars.map { case (k, v) => v -> s"\\$k" } diff --git a/src/main/wacc/backend/sizeExtensions.scala b/src/main/wacc/backend/sizeExtensions.scala index 798e290..37468ca 100644 --- a/src/main/wacc/backend/sizeExtensions.scala +++ b/src/main/wacc/backend/sizeExtensions.scala @@ -9,8 +9,6 @@ object sizeExtensions { /** Calculate the size (bytes) of the heap required for the expression. */ def heapSize: Int = (expr, expr.ty) match { - case (ArrayLiter(elems), KnownType.Array(KnownType.Char)) => - KnownType.Int.size.toInt + elems.size.toInt * KnownType.Char.size.toInt case (ArrayLiter(elems), ty) => KnownType.Int.size.toInt + elems.size * ty.elemSize.toInt case _ => expr.ty.size.toInt From 5ae65d3190d136c78f078e102035256229f4fe06 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 28 Feb 2025 17:22:49 +0000 Subject: [PATCH 4/7] fix: sanity check --- src/main/wacc/backend/Stack.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/wacc/backend/Stack.scala b/src/main/wacc/backend/Stack.scala index 1c57726..06b52c7 100644 --- a/src/main/wacc/backend/Stack.scala +++ b/src/main/wacc/backend/Stack.scala @@ -81,7 +81,7 @@ class Stack { /** Get an MemLocation for a variable in the stack. */ def accessVar(ident: mw.Ident): MemLocation = - MemLocation(RSP, sizeBytes - stack(ident).bottom, opSize = Some(ident.ty.size)) + MemLocation(RSP, sizeBytes - stack(ident).bottom) def contains(ident: mw.Ident): Boolean = stack.contains(ident) def head: MemLocation = MemLocation(RSP, opSize = Some(stack.last._2.size)) From 0eaf2186b676d0b189fb494e899f6b32bf04385f Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 28 Feb 2025 17:51:06 +0000 Subject: [PATCH 5/7] fix: zero-out D32 as well --- src/main/wacc/backend/asmGenerator.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/wacc/backend/asmGenerator.scala b/src/main/wacc/backend/asmGenerator.scala index db2e694..500d398 100644 --- a/src/main/wacc/backend/asmGenerator.scala +++ b/src/main/wacc/backend/asmGenerator.scala @@ -174,7 +174,7 @@ object asmGenerator { asm ++= evalExprOntoStack(rhs) asm ++= evalExprOntoStack(i) asm += stack.pop(RCX) - asm += Compare(ECX, ImmediateVal(0)) + asm += Compare(RCX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.Less) asm += stack.push(KnownType.Int.size, RCX) asm ++= evalExprOntoStack(x) @@ -461,8 +461,8 @@ object asmGenerator { def stackAlign: AsmLine = And(Register(Size.Q64, SP), ImmediateVal(-16)) private def zeroRest(dest: Dest, size: Size): Chain[AsmLine] = size match { - case Size.Q64 | Size.D32 => Chain.empty - case _ => Chain.one(And(dest, ImmediateVal((1 << (size.toInt * 8)) - 1))) + case Size.Q64 => Chain.empty + case _ => Chain.one(And(dest, ImmediateVal(((BigInt(1) << (size.toInt * 8)) - 1).toInt))) } private val escapedCharsMapping = escapedChars.map { case (k, v) => v -> s"\\$k" } From 578a28a222815cbfb7a781731a16953ef5b6df62 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 28 Feb 2025 18:28:50 +0000 Subject: [PATCH 6/7] Revert "fix: zero-out D32 as well" This reverts commit 0eaf2186b676d0b189fb494e899f6b32bf04385f. --- src/main/wacc/backend/asmGenerator.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/wacc/backend/asmGenerator.scala b/src/main/wacc/backend/asmGenerator.scala index 500d398..db2e694 100644 --- a/src/main/wacc/backend/asmGenerator.scala +++ b/src/main/wacc/backend/asmGenerator.scala @@ -174,7 +174,7 @@ object asmGenerator { asm ++= evalExprOntoStack(rhs) asm ++= evalExprOntoStack(i) asm += stack.pop(RCX) - asm += Compare(RCX, ImmediateVal(0)) + asm += Compare(ECX, ImmediateVal(0)) asm += Jump(labelGenerator.getLabelArg(OutOfBoundsError), Cond.Less) asm += stack.push(KnownType.Int.size, RCX) asm ++= evalExprOntoStack(x) @@ -461,8 +461,8 @@ object asmGenerator { def stackAlign: AsmLine = And(Register(Size.Q64, SP), ImmediateVal(-16)) private def zeroRest(dest: Dest, size: Size): Chain[AsmLine] = size match { - case Size.Q64 => Chain.empty - case _ => Chain.one(And(dest, ImmediateVal(((BigInt(1) << (size.toInt * 8)) - 1).toInt))) + case Size.Q64 | Size.D32 => Chain.empty + case _ => Chain.one(And(dest, ImmediateVal((1 << (size.toInt * 8)) - 1))) } private val escapedCharsMapping = escapedChars.map { case (k, v) => v -> s"\\$k" } From 37812fb5a7cc3c71506ac0e12d44cb811f29508c Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Fri, 28 Feb 2025 18:41:31 +0000 Subject: [PATCH 7/7] fix: copy whole register on assignment --- src/main/wacc/backend/asmGenerator.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/wacc/backend/asmGenerator.scala b/src/main/wacc/backend/asmGenerator.scala index db2e694..b1b90b9 100644 --- a/src/main/wacc/backend/asmGenerator.scala +++ b/src/main/wacc/backend/asmGenerator.scala @@ -161,15 +161,15 @@ object asmGenerator { labelGenerator: LabelGenerator ): Chain[AsmLine] = { var asm = Chain.empty[AsmLine] + asm += Comment(stmt.toString) stmt match { case Assign(lhs, rhs) => lhs match { case ident: Ident => if (!stack.contains(ident)) asm += stack.reserve(ident) - val dest = Register(ident.ty.size, AX) asm ++= evalExprOntoStack(rhs) asm += stack.pop(RAX) - asm += Move(stack.accessVar(ident), dest) + asm += Move(stack.accessVar(ident).copy(opSize = Some(Size.Q64)), RAX) case ArrayElem(x, i) => asm ++= evalExprOntoStack(rhs) asm ++= evalExprOntoStack(i)