Package compiler.asmcode

Source Code of compiler.asmcode.AsmCodeCreator

package compiler.asmcode;

import java.util.LinkedList;

import compiler.frames.Frame;
import compiler.frames.Label;
import compiler.frames.Temp;
import compiler.imcode.ImcBINOP;
import compiler.imcode.ImcCALL;
import compiler.imcode.ImcCJUMP;
import compiler.imcode.ImcCONST;
import compiler.imcode.ImcEXP;
import compiler.imcode.ImcExpr;
import compiler.imcode.ImcJUMP;
import compiler.imcode.ImcLABEL;
import compiler.imcode.ImcMEM;
import compiler.imcode.ImcMOVE;
import compiler.imcode.ImcNAME;
import compiler.imcode.ImcSEQ;
import compiler.imcode.ImcStmt;
import compiler.imcode.ImcTEMP;

public class AsmCodeCreator
{
  public LinkedList<AsmInstr> instructions = new LinkedList<AsmInstr>();
  private Frame callFrame = null;
 
  public AsmCodeCreator(Frame chunkFrame)
  {
    callFrame = chunkFrame;
  }
 
  public void munch(ImcStmt stmt)
  {
    /** ImcSEQ */
    if (stmt instanceof ImcSEQ)
    {
      for (ImcStmt statement : ((ImcSEQ)stmt).stmts)
      {
        munch(statement);
      }
    }
    /** ImcLABEL */
    else if(stmt instanceof ImcLABEL)
    {
      ImcLABEL label = (ImcLABEL)stmt;
      instructions.add(new AsmLABEL(label.label.name() + ":", label.label));
    }
    /** ImcMOVE */
    else if(stmt instanceof ImcMOVE)
    {
      munch((ImcMOVE)stmt);
    }
    /** ImcEXP */
    else if (stmt instanceof ImcEXP)
    {
      munch(((ImcEXP)stmt).expr);
    }
    /** ImcJUMP */
    else if (stmt instanceof ImcJUMP)
    {
      munch((ImcJUMP)stmt);
    }
    else if (stmt instanceof ImcCJUMP)
    {
      munch((ImcCJUMP)stmt);
    }
    else
    {
      System.err.println(stmt.getClass().toString());
    }
  };
 
  /**
   * Munch expression
   */
  private Temp munch(ImcExpr expr)
  {
    /** TEMP */
    if (expr instanceof ImcTEMP)
    {
      return ((ImcTEMP)expr).temp;
    }
    /** CONST */
    if (expr instanceof ImcCONST)
    {
      return munch((ImcCONST)expr);
    }
    /** MEM */
    else if (expr instanceof ImcMEM)
    {
      return munch((ImcMEM)expr);
    }
    /** BINOP */
    else if (expr instanceof ImcBINOP)
    {
      return munch((ImcBINOP)expr);
    }
    /** CALL */
    else if (expr instanceof ImcCALL)
    {
      return munch((ImcCALL)expr);
    }
    /** NAME */
    else if (expr instanceof ImcNAME)
    {
      // Name as an expression, load label
      Temp val = new Temp();
     
      LinkedList<Temp> defs = new LinkedList<Temp>();
      defs.add(val);
     
      LinkedList<Label> lbls = new LinkedList<Label>();
      lbls.add(((ImcNAME)expr).label);
     
      instructions.add(new AsmOPER("ldr `d0, =" + lbls.get(0).name(), defs, new LinkedList<Temp>(), lbls));
     
      return val;
    }
    else
    {
      System.err.println(" -- " + expr.getClass().toString());
    }
   
    return new Temp();
  };
 
  /**
   * Munch MOVE
   */
  private void munch(ImcMOVE move)
  {
    // MOV
    if (move.src instanceof ImcTEMP && move.dst instanceof ImcTEMP)
    {
      // Create move command
      instructions.add(new AsmMOVE("mov `d0, [`s0]", ((ImcTEMP)move.src).temp, ((ImcTEMP)move.dst).temp));
    }
    // LDR or MOV const
    else if (move.dst instanceof ImcTEMP && move.src instanceof ImcCONST)
    {
      // Create MOV command if the operand is less than 4096 since ARMv5 can't have bigger immediate operands
      int constValue = ((ImcCONST)move.src).value;
     
      // Defs
      LinkedList<Temp> def = new LinkedList<Temp>();
      def.add(((ImcTEMP)move.dst).temp);
     
      if (constValue < 4096)
      {
        instructions.add(new AsmOPER("mov `d0, #" + constValue, def, new LinkedList<Temp>()));
      }
      else
      {
        instructions.add(new AsmOPER("ldr `d0, =" + constValue, def, new LinkedList<Temp>()));
      }
    }
    else if (move.dst instanceof ImcTEMP && move.src instanceof ImcExpr)
    {
      Temp val = munch(move.src);
      instructions.add(new AsmMOVE("mov `d0, [`s0]", ((ImcTEMP)move.dst).temp, val));
    }
    // STR
    else if (move.dst instanceof ImcMEM)
    {
      Temp value = munch((ImcExpr)move.src);
      ImcMEM mem = (ImcMEM)move.dst;
     
      // Check if it's a label or a register with offset
     
      // NAME
      if (mem.expr instanceof ImcNAME)
      {
        LinkedList<Temp> src = new LinkedList<Temp>();
        src.add(value);
       
        instructions.add(new AsmOPER("str `s0, =" + ((ImcNAME)mem.expr).label.name(), new LinkedList<Temp>(), src));
      }
      else if (mem.expr instanceof ImcBINOP && ((ImcBINOP)mem.expr).rimc instanceof ImcCONST)
      {
        LinkedList<Temp> src = new LinkedList<Temp>();
        src.add(value);
        src.add(munch(((ImcBINOP)mem.expr).limc));
       
        int offset = ((ImcCONST)((ImcBINOP)mem.expr).rimc).value;
       
        instructions.add(new AsmOPER("str `s0, [`s1, #" + offset + "]", new LinkedList<Temp>(), src));
      }
      // Address that evaluates
      else if (((ImcBINOP)mem.expr).rimc instanceof ImcCONST)
      {
        Temp addr = munch((ImcExpr)mem.expr);
       
        LinkedList<Temp> src = new LinkedList<Temp>();
        src.add(addr);
        src.add(munch(((ImcBINOP)mem.expr).limc));
       
        int offset = ((ImcCONST)((ImcBINOP)mem.expr).rimc).value;
       
        instructions.add(new AsmOPER("str `s0, [`s1, #" + offset + "]", new LinkedList<Temp>(), src));
      }
    }
    else
    {
      System.err.println("!! " + move.src.getClass().toString());
    }
  }
 
  /**
   * Munch JUMP
   */
  private void munch(ImcJUMP jump)
  {
    LinkedList<Label> lbls = new LinkedList<Label>();
    lbls.add(jump.label);
   
    instructions.add(new AsmOPER("b " + jump.label.name(), new LinkedList<Temp>(), new LinkedList<Temp>(), lbls));
  }
 
  /**
   * Munch CJUMP
   */
  private void munch(ImcCJUMP jump)
  {
    Temp conditionResult = munch(jump.cond);
   
    LinkedList<Temp> src = new LinkedList<Temp>();
    src.add(conditionResult);
   
    // Test if condition is true
    instructions.add(new AsmOPER("tst `s0, #1", new LinkedList<Temp>(), src));
   
    // TRUE
    LinkedList<Label> lbls = new LinkedList<Label>();
    lbls.add(jump.trueLabel);
    instructions.add(new AsmOPER("bne " + jump.trueLabel.name(), new LinkedList<Temp>(), src, lbls));
    // FALSE
    lbls = new LinkedList<Label>();
    lbls.add(jump.falseLabel);
    instructions.add(new AsmOPER("beq " + jump.falseLabel.name(), new LinkedList<Temp>(), src, lbls));
  }
 
  /**
   * Munch CALL
   */
  private Temp munch(ImcCALL call)
  {
    // Save static link on current stack pointer location
    // TODO: check validity
    LinkedList<Temp> uses = new LinkedList<Temp>();
    uses.add(callFrame.FP);
 
    addComment("Store static link");
    instructions.add(new AsmOPER("str `s0, [sp]", new LinkedList<Temp>(), uses));
    addComment("Store arguments");
    int offset = 4;
    for (ImcExpr arg : call.args)
    {
      Temp val = munch(arg);
     
      // Store on stack (r14 is stack pointer) and increment it (!)
      LinkedList<Temp> src = new LinkedList<Temp>();
      src.add(val);

      instructions.add(new AsmOPER("str `s0, [sp, #" + offset + "]", new LinkedList<Temp>(), src));
     
      offset += 4;
    }
   
    // JUMP
    LinkedList<Label> lbls = new LinkedList<Label>();
    lbls.add(call.label);
   
    // Store registers
    instructions.add(new AsmOPER("b " + call.label.name(), new LinkedList<Temp>(), new LinkedList<Temp>(), lbls));
   
    return new Temp();
  }
 
  /**
   * Munch BINOP
   */
  private Temp munch(ImcBINOP binop)
  {
    switch(binop.op)
    {
      case ImcBINOP.ADD:
      case ImcBINOP.SUB:
      case ImcBINOP.MUL:
      case ImcBINOP.DIV:
        return munchArithmetic(binop);
     
      case ImcBINOP.EQU:
      case ImcBINOP.NEQ:
      case ImcBINOP.LEQ:
      case ImcBINOP.LTH:
      case ImcBINOP.GEQ:
      case ImcBINOP.GTH:
      case ImcBINOP.AND:
      case ImcBINOP.OR:
        return munchLogical(binop);
   
      default:
        System.err.println("Unimplemented BINOP operation " + binop.op);
        return new Temp();
    }
  }
 
  /**
   * Munch CONST
   */
  private Temp munch(ImcCONST constant)
  {
    // Load constant to a register and return it
    Temp constreg = new Temp();
    int val = constant.value;
   
    LinkedList<Temp> dst = new LinkedList<Temp>();
    dst.add(constreg);
   
    if (val < 4096)
    {
      instructions.add(new AsmOPER("mov `d0, #" + val, dst, new LinkedList<Temp>()));
    }
    else
    {
      instructions.add(new AsmOPER("ldr `d0, =" + val, dst, new LinkedList<Temp>()));
    }
   
    return constreg;
  }
 
  /**
   * Munch MEM
   */
  private Temp munch(ImcMEM mem)
  {
    // Create LDR command depending on the parameters
    Temp dest = new Temp();
   
    LinkedList<Temp> defs = new LinkedList<Temp>();
    defs.add(dest);
   
    if (mem.expr instanceof ImcNAME)
    {
      Label label = ((ImcNAME)mem.expr).label;
     
      LinkedList<Label> lbls = new LinkedList<Label>();
      lbls.add(label);
     
      instructions.add(new AsmOPER("ldr `d0, =" + label.name(), defs, new LinkedList<Temp>(), lbls));
    }
    else if (mem.expr instanceof ImcBINOP && ((ImcBINOP)mem.expr).rimc instanceof ImcCONST)
    {
      Temp left = munch(((ImcBINOP)mem.expr).limc);
      LinkedList<Temp> src = new LinkedList<Temp>();
      src.add(left);
     
      int offset = ((ImcCONST)((ImcBINOP)mem.expr).rimc).value;
     
      instructions.add(new AsmOPER("ldr `d0, [`s0, #" + offset + "]", defs, src));
    }
    else
    {
      Temp addr = munch(mem.expr);
     
      LinkedList<Temp> src = new LinkedList<Temp>();
      src.add(addr);
     
      instructions.add(new AsmOPER("ldr, `d0, [`s0]", defs, src));
    }
   
    return dest;
  }
 
  /**
   * Handles arithmetic BINOP operations
   */
  private Temp munchArithmetic(ImcBINOP binop)
  {
    // Check if perhaps we have two constant values, convert them to single LDR/MOV order instead
    if (binop.limc instanceof ImcCONST && binop.rimc instanceof ImcCONST)
    {     
      // Calculate operation result
      int val1 = ((ImcCONST)binop.limc).value;
      int val2 = ((ImcCONST)binop.rimc).value;
      int result = 0;
     
      switch(binop.op)
      {
        case ImcBINOP.ADD:
          result = val1 + val2;
          break;
        case ImcBINOP.SUB:
          result = val1 - val2;
          break;
         
        case ImcBINOP.MUL:
          result = val1 * val2;
          break;
       
        case ImcBINOP.DIV:
          result = val1 / val2;
          break;
      }
     
      LinkedList<Temp> def = new LinkedList<Temp>();
      def.add(new Temp());
     
      if (result < 4096)
      {
        instructions.add(new AsmOPER("mov `d0, #" + result, def, new LinkedList<Temp>()));
      }
      else
      {
        instructions.add(new AsmOPER("ldr `d0, =" + result, def, new LinkedList<Temp>()));
      }
     
      return def.getFirst();
    }
    // Check for immediate values
    else
    {
      String command = "";
     
      // Evaulate left and right sides
      Temp val1 = munch((ImcExpr)binop.limc);
      Temp val2 = munch((ImcExpr)binop.rimc);
     
      switch(binop.op)
      {
        case ImcBINOP.ADD:
          command = "add";
          break;
        case ImcBINOP.SUB:
          command = "sub";
          break;
        case ImcBINOP.MUL:
          command = "mul";
          break;
        case ImcBINOP.DIV:
          return inlineDivAlgorithm(val1, val2);         
      }
     
      Temp result = new Temp();
     
      LinkedList<Temp> defs = new LinkedList<Temp>();
      defs.add(result);
     
      LinkedList<Temp> srcs = new LinkedList<Temp>();
      srcs.add(val1);
      srcs.add(val2);
     
      instructions.add(new AsmOPER(command + " `d0, `s0, `s1", defs, srcs));
     
      return result;
    }
  }
 
  // Inserts an inlined division algorithm
  private Temp inlineDivAlgorithm(Temp val1, Temp val2)
  {
    LinkedList<Temp> uses = new LinkedList<Temp>();
    LinkedList<Temp> defs = new LinkedList<Temp>();
   
    Temp result = new Temp();
    defs.add(result);
   
    Temp tmp = new Temp();
   
    // Clear result register for accumulation
    // MOV R0, #0
    instructions.add(new AsmOPER("mov `d0, #0", defs, new LinkedList<Temp>()));
   
    defs = new LinkedList<Temp>();
    defs.add(tmp);
   
    // Put bit 1 in temp register
    // MOV R3, #1
    instructions.add(new AsmOPER("mov `d0, #1", defs, new LinkedList<Temp>()));
   
    // Start label
    Label start = Label.newLabel();
    instructions.add(new AsmLABEL(start.name() + ":", start));
   
    // CMP R2, R1
    uses.add(val1);
    uses.add(val2);
    instructions.add(new AsmOPER("cmp `s0, `s1", new LinkedList<Temp>(), uses));
   
    // MOVLS R2, R2, LSL #1
    defs = new LinkedList<Temp>();
    defs.add(val2);
    uses = new LinkedList<Temp>();
    uses.add(val2);
   
    instructions.add(new AsmOPER("movls `d0, `s0, lsl #1", defs, uses));
   
    // MOVLS R3, R3, LSL #1
    defs = new LinkedList<Temp>();
    defs.add(tmp);
    uses = new LinkedList<Temp>();
    uses.add(tmp);
    instructions.add(new AsmOPER("movls `d0, `s0, lsl #1", defs, uses));
   
    // BLS start
    LinkedList<Label> lbls = new LinkedList<Label>();
    lbls.add(start);
    instructions.add(new AsmOPER("bls " + start.name(), new LinkedList<Temp>(), new LinkedList<Temp>(), lbls));
   
    // Next label
    Label next = Label.newLabel();
    instructions.add(new AsmLABEL(next.name() + ":", next));
   
    // CMP R1, R2
    uses = new LinkedList<Temp>();
    uses.add(val1);
    uses.add(val2);
    instructions.add(new AsmOPER("cmp `s0, `s1", new LinkedList<Temp>(), uses));
   
    // SUBCS R1, R1, R2
    defs = new LinkedList<Temp>();
    defs.add(val1);
    instructions.add(new AsmOPER("subcs `d0, `s0, `s1", defs, uses));
   
    // ADDCS R0, R0, R3
    defs = new LinkedList<Temp>();
    defs.add(result);
    uses = new LinkedList<Temp>();
    uses.add(result);
    uses.add(tmp);
    instructions.add(new AsmOPER("addcs `d0, `s0, `s1", defs, uses));
   
    // MOVS R3, R3, LSR #1
    defs = new LinkedList<Temp>();
    defs.add(tmp);
    uses = new LinkedList<Temp>();
    uses.add(tmp);
    instructions.add(new AsmOPER("movs `d0, `s0, LSR #1", defs, uses));
   
    // MOVCC R2, R2, LSR #1
    defs = new LinkedList<Temp>();
    defs.add(val2);
    uses = new LinkedList<Temp>();
    uses.add(val2);
    instructions.add(new AsmOPER("movcc `d0, `s0, LSR #1", defs, uses));
   
    // BCC next
    lbls = new LinkedList<Label>();
    lbls.add(next);
    instructions.add(new AsmOPER("bcc " + next.name(), new LinkedList<Temp>(), new LinkedList<Temp>(), lbls));
   
    // Done
    return result;
  }
 
  private Temp munchLogical(ImcBINOP binop)
  {
    Temp result = new Temp();
    LinkedList<Temp> dst = new LinkedList<Temp>();
    dst.add(result);
   
    Temp left = munch(binop.limc);
    Temp right = munch(binop.rimc);
   
    LinkedList<Temp> src = new LinkedList<Temp>();
    src.add(left);
    src.add(right);
   
    if (binop.op == ImcBINOP.AND)
    {
      instructions.add(new AsmOPER("and `d0, `s0, `s1", dst, src));
      return result;
    }
    else if (binop.op == ImcBINOP.OR)
    {
      instructions.add(new AsmOPER("orr `d0, `s0, `s1", dst, src));
      return result;
    }
   
    // Compare operators
    instructions.add(new AsmOPER("cmp `s0, `s1", new LinkedList<Temp>(), src));
   
    // Determine correct pair of conditional execution postfixes for the condition
    String truePf = "";
    String falsePf = "";
   
    switch(binop.op)
    {
      case ImcBINOP.EQU:
        truePf = "eq";
        falsePf = "ne";
        break;
       
      case ImcBINOP.NEQ:
        truePf = "ne";
        falsePf = "eq";
        break;
       
      case ImcBINOP.GTH:
        truePf = "gt";
        falsePf = "le";
        break;
       
      case ImcBINOP.GEQ:
        truePf = "ge";
        falsePf = "lt";
        break;
       
      case ImcBINOP.LEQ:
        truePf = "le";
        falsePf = "gt";
        break;
       
      case ImcBINOP.LTH:
        truePf = "lt";
        falsePf = "ge";
        break;
       
      default:
        System.err.println("Unimplemented logical BINOP operator " + binop.op);
    }
   
    // Add value setter instructions with correct postfixes
    instructions.add(new AsmOPER("mov" + truePf + " `d0, #0", dst, new LinkedList<Temp>()));
    instructions.add(new AsmOPER("mov" + falsePf + " `d0, #1", dst, new LinkedList<Temp>()));
   
    return result;
  }
 
  private void addComment(String comment)
  {
    instructions.add(new AsmOPER("; " + comment, new LinkedList<Temp>(), new LinkedList<Temp>()));
  }
}
TOP

Related Classes of compiler.asmcode.AsmCodeCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.