Ejemplo n.º 1
0
  def handle_move(self, label, result, *operands):
    """Handles the move instruction of IR.
    """
    source = operands[0]

    # If both the operands are memory locations, use %r15 as an intermediate
    # register
    if isinstance(source, Memory) and isinstance(operands[1], Memory):
      r15 = Register()
      r15.color = 13
      mov = MOV(r15, operands[0])
      self.add_instruction(label, mov)

      source = r15

    mov = MOV(operands[1], source)
    self.add_instruction(label, mov)
Ejemplo n.º 2
0
  def handle_ret(self, label, result, *operands):
    """Handles the return instruction of IR.
    """
    # Return is nothing but the jump to the end of the function.
    # If it has an operand it should be returned in %rax, according to Linux
    # Application Binary Interface (ABI).
    if operands:
      # 0 is the Register color for %rax.
      if operands[0]:
        # Create a dummy register for %rax.
        rax = Register()
        rax.color = 0
        mov = MOV(rax, operands[0])
        self.add_instruction(label, mov)

    jmp = JMP()
    self.add_instruction(label, jmp)
    self.returns_to_process.append(jmp)
Ejemplo n.º 3
0
  def create_stack(self):
    """Creates the stack with the current memory offset value.
    """
    # Create a dummy register and give it a color to keep the API consistent.
    rbp = Register()
    rbp.color = 'rbp'        # The color of %rbp
    push = PUSH(rbp)
    self.add_instruction(0, push)

    # Another dummy register for %rsp
    rsp = Register()
    rsp.color = 'rsp'
    mov = MOV(rbp, rsp)
    self.add_instruction(0, mov)

    if self.memory_offset:
      # Allocate memory for locals
      sub = SUB(rsp, Immediate(self.memory_offset))
      self.add_instruction(0, sub)
Ejemplo n.º 4
0
def entry():
  """Returns the precompiled code for starting the code.
  """
  call = CALL()

  # Move exit status to %rdi
  rdi = Register()
  rdi.color = 5
  mov_status = MOV(rdi, Immediate(0))

  # Move exit SYSCALL descriptor number to %rax
  rax = Register()
  rax.color = 0
  mov_sycall = MOV(rax, Immediate(60))

  # Make syscall
  syscall = SYSCALL()

  return (len(call) + len(mov_status) + len(mov_sycall)
          + len(syscall), [call, mov_status, mov_sycall, syscall])
Ejemplo n.º 5
0
  def handle_cmp(self, label, result, *operands):
    """Handles the cmp instruction of IR.
    """
    dest = operands[0]

    if isinstance(operands[0], Memory) and isinstance(operands[1], Memory):
      mov = MOV(result, operands[0])
      self.add_instruction(label, mov)

      dest = result
    elif isinstance(operands[0], Immediate):
      # FIXME: If the destination is an immediate operand, this is moved to
      # a temporary scratch register and then compared, however this calls for
      # a better mechanism. Please see issue #6.
      r15 = Register()
      r15.color = 13

      mov = MOV(r15, operands[0])
      self.add_instruction(label, mov)

      dest = r15

    cmp_instruction = CMP(dest, operands[1])
    self.add_instruction(label, cmp_instruction)
Ejemplo n.º 6
0
  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)
Ejemplo n.º 7
0
  def handle_div(self, label, result, *operands):
    """Handles the div instruction of IR.
    """
    restore_rax = True
    restore_rdx = True

    # This will be true only if the second operand is immediate.
    restore_r15 = False

    # Create dummy register objects for RAX and RDX and force color them to
    # ensure they take RAX and RDX values. So we can spill these two registers.
    # Also create memory object to where they get spilled.
    if self.is_register(result):
      if result.color == 0:
        restore_rax = False
      elif result.color == 3:
        restore_rdx = False

    # We may want %rax register to move the first dividend to %rax if it is
    # not already in %rax, so create a dummy %rax register in any case.
    rax = Register()
    rax.color = 0     # Color of RAX

    # We want to clear the contents of %rdx no matter what, so create a dummy
    # register for it.
    rdx = Register()
    rdx.color = 3     # Color of RDX

    # Store %rax and %rdx in memory if they have to be restored
    if restore_rax:
      rax.memory = Memory()

      rax_operands = (rax, rax.memory)
      self.handle_store(label, None, *rax_operands)

    if restore_rdx:
      rdx.memory = Memory()

      rdx_operands = (rdx, rdx.memory)
      self.handle_store(label, None, *rdx_operands)

    if not (self.is_register(operands[0]) and operands[0].color == 0):
      mov = MOV(rax, operands[0])
      self.add_instruction(label, mov)

    # Clear %rdx, because x86_64 DIV instruction uses both %rax and %rdx as
    # the divisor
    xor = XOR(rdx, rdx)
    self.add_instruction(label, xor)

    if isinstance(operands[1], Immediate):
      # Create a dummy register object for %r15 for moving the operand to it.
      r15 = Register()
      r15.color = 13

      if not(self.is_register(result) and result.color == 13):
        restore_r15 = True
        r15.memory = Memory()
        r15_operands = (r15, r15.memory)
        self.handle_store(label, None, *r15_operands)

      mov = MOV(r15, operands[1])
      self.add_instruction(label, mov)

      idiv = IDIV(r15)
    else:
      idiv = IDIV(operands[1])

    self.add_instruction(label, idiv)

    mov = MOV(result, rax)
    self.add_instruction(label, mov)

    if restore_rax:
      self.handle_load(label, rax, rax.memory)
    if restore_rdx:
      self.handle_load(label, rdx, rdx.memory)
    if restore_r15:
      self.handle_load(label, r15, r15.memory)
Ejemplo n.º 8
0
  def handle_call(self, function_name, label, result, *operands):
    """Handles the call instruction of IR.
    """
    pushed_registers = []
    if 0 in self.instruction_live_registers[label]:
      self.instruction_live_registers[label].pop(0)
      if not self.is_register(result) or result.color != 0:
        # Create a dummy register
        register = Register()
        register.color = 0
        push = PUSH(register)
        self.add_instruction(label, push)
        pushed_registers.append(register)


    for register_color in self.instruction_live_registers[label]:
      # Create a dummy register
      register = Register()
      register.color = register_color
      push = PUSH(register)
      self.add_instruction(label, push)
      pushed_registers.append(register)

    # Arguments are passed through %rdi, %rsi, %rdx, %rcx, %r8, %r9
    for argument, register_color in zip(operands, FUNCTION_ARGUMENTS_COLORS):
      if not (isinstance(argument, Register) and
          argument.color == register_color):
        # Create a dummy register for %rax.
        new_register = Register()
        new_register.color = register_color
        mov = MOV(new_register, argument)
        self.add_instruction(label, mov)

    # If there are more than arguments to the function, push them on to the
    # stack in the right-to-left order
    if len(operands) > 6:
      # Note we run this upto 5 but not including 5 which is the 6th argument.
      for argument in operands[-1:5:-1]:
        push = PUSH(argument)
        self.add_instruction(label, push)

    call = CALL()
    self.add_instruction(label, call)
    self.calls_to_link.append((call, function_name))

    # Popping should be in the reverse order
    pop_rax_later = False
    for register in pushed_registers[-1::-1]:
      # Don't pop %rax yet, if result exists, we need to mov %rax to
      # actual result register and then pop
      if register.color == 0:
        pop_rax_later = True
        continue

      pop = POP(register)
      self.add_instruction(label, pop)

    # NOTE: The following move is done after popping all the values because
    # popping overwrites the values otherwise.
    # If the result of the call instruction is to be passed on to some other
    # register than %rax, we need to insert a move for it.
    if self.is_register(result) and result.color != 0:
      rax = Register()
      rax.color = 0

      mov = MOV(result, rax)
      self.add_instruction(label, mov)

    # We should pop_rax if we rax has been pushed to the stack, but we can only
    # pop it after moving the result to the right location.
    if pop_rax_later:
      register = Register()
      register.color = 0
      pop = POP(register)
      self.add_instruction(label, pop)