def handle_prologue(self, func_name, *operands):
    """Handles the prologue of the function definition in IR.
    """
    self.memory_offset = 0

    # Allocate memory for both the defined variables and the formal parameters.
    # Symbol table will have entry for all of them.
    for symtab_entry in self.ir.local_symbol_table.values():
      if 'memory' in symtab_entry:
        symtab_entry['memory'].offset = self.memory_offset
        symtab_entry['memory'].size = MEMORY_WIDTH
        symtab_entry['memory'].base = 0

        self.memory_offset += MEMORY_WIDTH

      elif symtab_entry.get('dimensions'):
        if 'memory' not in symtab_entry:
          symtab_entry['memory'] = Memory()

        symtab_entry['memory'].offset = self.memory_offset
        total_size = 1
        for dimension in symtab_entry['dimensions']:
          total_size *= dimension

        symtab_entry['memory'].size = total_size * MEMORY_WIDTH
        symtab_entry['memory'].base = 0

        self.memory_offset += total_size * MEMORY_WIDTH

    self.create_stack()
  def handle_load(self, label, result, *operands):
    """Handles the load instruction of IR.
    """
    register = result

    if isinstance(operands[0], Immediate) and isinstance(operands[1], Memory):
      memory = Memory(
          base=operands[1].base,
          offset=operands[1].offset + (operands[0].value * MEMORY_WIDTH))
    elif isinstance(operands[0], Register):
      # This happens only in case of arrays
      memory = Memory(base=operands[1], offset=operands[0])
    elif isinstance(operands[0], Memory):
      memory = operands[0]
      if memory.offset == None:
        memory.offset = self.memory_offset
        self.memory_offset += MEMORY_WIDTH

    mov = MOV(register, memory)
    self.add_instruction(label, mov)
def allocate_global_memory(global_symbol_table):
  """Allocate memory for global datastructures.

  Args:
    global_symbol_table: Dictionary containing the global symbol table whose
        keys are symbol names and values are symbol table data like memory
        object for this symbol and type.
  """
  memory_offset = 0
  for symbol, symtab_entry in global_symbol_table.iteritems():
    if symtab_entry.get('type') == 'function_name' or (
        symbol in ['InputNum', 'OutputNum', 'OutputNewLine']):
      # These symbols are function names, don't do anything for them here.
      continue
    elif symtab_entry.get('dimensions', None) != None:
      # This entry is an array
      if 'memory' not in symtab_entry:
        symtab_entry['memory'] = Memory()

      symtab_entry['memory'].offset = memory_offset
      total_size = 1
      for dimension in symtab_entry['dimensions']:
        total_size *= dimension

      symtab_entry['memory'].size = total_size * MEMORY_WIDTH
      symtab_entry['memory'].base = 'rip'

      memory_offset += total_size * MEMORY_WIDTH
    else:
      # This entry is a regular integer.
      if 'memory' not in symtab_entry:
        symtab_entry['memory'] = Memory()

      symtab_entry['memory'].offset = memory_offset
      symtab_entry['memory'].size = MEMORY_WIDTH
      symtab_entry['memory'].base = 'rip'

      memory_offset += MEMORY_WIDTH

  return memory_offset
  def handle_store(self, label, result, *operands):
    """Handles the store instruction of IR.
    """
    if isinstance(operands[1], Immediate) and isinstance(operands[2], Memory):
      memory = Memory(
          base=operands[2].base,
          offset=operands[2].offset + (operands[1].value * MEMORY_WIDTH))
    elif isinstance(operands[1], Register):
      memory = Memory()
      memory.base = operands[2]
      memory.offset = operands[1]
    elif isinstance(operands[1], Memory):
      memory = operands[1]
      memory.offset = self.memory_offset

      self.memory_offset += MEMORY_WIDTH

    if isinstance(operands[0], Memory) or (isinstance(operands[0], Register)
        and isinstance(operands[0].color, Memory)):

      # Take the set difference
      free_registers = (REGISTERS_COLOR_SET -
          set(self.instruction_live_registers[label].keys()))
      if free_registers:
        # Create a dummy register for this color
        register = Register()
        # pop and add back since sets don't support indexing
        register.color = free_registers.pop()
        free_registers.add(register.color)

        mov1 = MOV(register, operands[0])
        self.add_instruction(label, mov1)

        mov2 = MOV(memory, register)
        self.add_instruction(label, mov2)
      else:
        # We don't have any free registers :(
        # We can't do much, randomly pick a register, push it to the stack,
        # do the memory move from the source to this register and then use
        # this register to move the source to the destination and then
        # pop back our register.
        # NOTE: We pick %rax for this temporary operation
        # Create a dummy register for %rax
        register = Register()
        register.color = 0
        push = PUSH(register)
        self.add_instruction(label, push)

        mov1 = MOV(register, operands[0])
        self.add_instruction(label, mov1)

        mov2 = MOV(memory, register)
        self.add_instruction(label, mov2)

        pop = POP(register)
        self.add_instruction(label, pop)
    else:
      register = operands[0]

      mov = MOV(memory, register)
      self.add_instruction(label, mov)