package cd.backend.codegen; import cd.backend.codegen.RegisterManager.Register; import cd.ir.Ast; import cd.ir.Ast.*; import cd.ir.AstVisitor; import cd.util.debug.AstOneLine; import java.util.*; /** * Generates code to process statements and declarations. */ class StmtGenerator extends AstVisitor { protected final AstCodeGenerator cg; StmtGenerator(AstCodeGenerator astCodeGenerator) { cg = astCodeGenerator; } public void gen(Ast ast) { visit(ast, null); } @Override public Register visit(Ast ast, Void arg) { try { cg.emit.increaseIndent("Emitting " + AstOneLine.toString(ast)); return super.visit(ast, arg); } finally { cg.emit.decreaseIndent(); } } /** * Declares a variable in the data segment. This method was implemented because it was necessary * to create the data segment * @param ast Variable declaration node * @param arg Extra arguments * @return null */ @Override public Register varDecl(Ast.VarDecl ast, Void arg) { cg.emit.emitLabel(ast.getLabel()); cg.emit.emitConstantData("0"); return null; } @Override public Register methodCall(MethodCall ast, Void dummy) { { throw new RuntimeException("Not required"); } } @Override public Register methodDecl(MethodDecl ast, Void arg) { // Prologue: in future version a more complex prologue that // takes care of parameters and return values is necessary // Method code cg.rm.initRegisters(); cg.emit.emitRaw(".section .data"); Interrupts.reserveMemory(cg); // Variables cg.sg.visit(ast.decls(), arg); cg.emit.emitRaw(".section .text"); cg.emit.emitRaw(".globl " + ast.name); cg.emit.emitLabel(ast.name); Register result = cg.sg.visit(ast.body(), arg); // Epilogue: not needed in the simple HW1 return null; } @Override public Register ifElse(IfElse ast, Void arg) { { throw new RuntimeException("Not required"); } } @Override public Register whileLoop(WhileLoop ast, Void arg) { { throw new RuntimeException("Not required"); } } @Override public Register assign(Assign ast, Void arg) { // Because we only handle very simple programs in HW1, // you can just emit the prologue here! Register value = cg.eg.visit(ast.right(), arg); Ast.Var variable = (Var) ast.left(); cg.emit.emitMove(value, variable.getLabel()); cg.rm.releaseRegister(value); return null; } @Override public Register builtInWrite(BuiltInWrite ast, Void arg) { String printNonZero = cg.emit.uniqueLabel(); String end = cg.emit.uniqueLabel(); String printPositive = cg.emit.uniqueLabel(); String stackLoop = cg.emit.uniqueLabel(); String printLoop = cg.emit.uniqueLabel(); Register value = cg.eg.visit(ast.arg(), arg); // Begin: decide if print 0 or print number cg.emit.emit("cmp", 0, value); cg.emit.emit("jne", printNonZero); // value != 0 // Print 0 Interrupts.printChar(cg, '0'); // print 0 cg.emit.emit("jmp", end); // Not 0: positive or negative? cg.emit.emitLabel(printNonZero); cg.emit.emit("jg", printPositive); // value > 0 // Number is negative, print '-' then number (with sign changed) Interrupts.printChar(cg, '-'); cg.emit.emit("negl", value); // Print number: extract and print all digits of number cg.emit.emitLabel(printPositive); // In order to avoid using EAX and EDX, we are going to guarantee // that there will be at least 2 other registers available List auxRegs = Arrays.asList(Register.EDI, Register.ESI); List divRegs = Arrays.asList(Register.EAX, Register.EDX); Map isPushed = new HashMap<>(); boolean usingAuxRegs = cg.rm.availableRegisters() < 4; if (usingAuxRegs) for (int i = 0; i < auxRegs.size(); i++) isPushed.put(auxRegs.get(i), cg.rm.isInUse(auxRegs.get(i))); // Free EAX and EDX for div operand use isPushed.put(Register.EAX, cg.rm.isInUse(Register.EAX) && !value.equals(Register.EAX)); isPushed.put(Register.EDX, cg.rm.isInUse(Register.EDX)); // Push all elements for (Register r : isPushed.keySet()) if (isPushed.get(r)) cg.emit.emit("push", r); // Force counter and divisor to not be EDX/EAX, as they need to coexist Register counter = cg.rm.getRegister(); Register divisor = cg.rm.getRegister(); while (divRegs.contains(counter)) { Register aux = cg.rm.getRegister(); cg.rm.releaseRegister(counter); counter = aux; } while (divRegs.contains(divisor)) { Register aux = cg.rm.getRegister(); cg.rm.releaseRegister(divisor); divisor = aux; } // Divide by 10 to extract the remainders and push them to the stack // Registers used: EAX is the remaining digits (initially the value) // in div it is used for the lower half of the dividend and for quotient // divisor // EDX is used as the high half of the dividend and as remainder cg.emit.emitMove(value, Register.EAX); cg.rm.releaseRegister(value); cg.emit.emitMove(AssemblyEmitter.constant(0), counter); cg.emit.emitLabel(stackLoop); cg.emit.emitMove(AssemblyEmitter.constant(0), Register.EDX); cg.emit.emitMove(AssemblyEmitter.constant(10), divisor); cg.emit.emit("div", divisor); cg.emit.emit("add", '0', Register.EDX); cg.emit.emit("push", Register.EDX); cg.emit.emit("inc", counter); cg.emit.emit("cmp", 0, Register.EAX); cg.emit.emit("je", printLoop); cg.emit.emit("jmp", stackLoop); // Release divisor register cg.rm.releaseRegister(divisor); // Print digits from the stack cg.emit.emitLabel(printLoop); cg.emit.emit("cmp", 0, counter); cg.emit.emit("jz", end); cg.emit.emit("dec", counter); cg.emit.emit("pop", Interrupts.Mem.BUFFER.pos); Interrupts.printChar(cg); cg.emit.emit("jmp", printLoop); cg.emit.emitLabel(end); cg.rm.releaseRegister(counter); // Restore original registers for (Register r : isPushed.keySet()) if (isPushed.get(r)) cg.emit.emit("pop", r); return null; } @Override public Register builtInWriteln(BuiltInWriteln ast, Void arg) { Interrupts.printChar(cg, '\n'); return null; } }