Пример #1
0
    def _set_bool(self, spotmap, get_reg, asm_code):
        """Emit code for SET command if arg is boolean type."""
        # When any scalar value is converted to _Bool, the result is 0 if the
        # value compares equal to 0; otherwise, the result is 1

        # If arg_asm is a LITERAL or conflicts with output, move to register.
        if (isinstance(spotmap[self.arg], LiteralSpot)
                or spotmap[self.arg] == spotmap[self.output]):
            r = get_reg([], [spotmap[self.output]])
            asm_code.add(
                asm_cmds.Mov(r, spotmap[self.arg], self.arg.ctype.size))
            arg_spot = r
        else:
            arg_spot = spotmap[self.arg]

        label = asm_code.get_label()
        output_spot = spotmap[self.output]

        zero = LiteralSpot("0")
        one = LiteralSpot("1")

        asm_code.add(asm_cmds.Mov(output_spot, zero, self.output.ctype.size))
        asm_code.add(asm_cmds.Cmp(arg_spot, zero, self.arg.ctype.size))
        asm_code.add(asm_cmds.Je(label))
        asm_code.add(asm_cmds.Mov(output_spot, one, self.output.ctype.size))
        asm_code.add(asm_cmds.Label(label))
Пример #2
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        arg1_spot = spotmap[self.arg1]
        arg1_size = self.arg1.ctype.size
        arg2_spot = spotmap[self.arg2]
        arg2_size = self.arg2.ctype.size

        # According Intel® 64 and IA-32 software developer's manual
        # Vol. 2B 4-582 second (count) operand must be represented as
        # imm8 or CL register.
        if not self._is_imm8(arg2_spot) and arg2_spot != spots.RCX:
            if arg1_spot == spots.RCX:
                out_spot = spotmap[self.output]
                temp_spot = get_reg([out_spot, arg1_spot],
                                    [arg2_spot, spots.RCX])
                asm_code.add(asm_cmds.Mov(temp_spot, arg1_spot, arg1_size))
                arg1_spot = temp_spot
            asm_code.add(asm_cmds.Mov(spots.RCX, arg2_spot, arg2_size))
            arg2_spot = spots.RCX

        if spotmap[self.output] == arg1_spot:
            asm_code.add(self.Inst(arg1_spot, arg2_spot, arg1_size, 1))
        else:
            out_spot = spotmap[self.output]
            temp_spot = get_reg([out_spot, arg1_spot], [arg2_spot])
            if arg1_spot != temp_spot:
                asm_code.add(asm_cmds.Mov(temp_spot, arg1_spot, arg1_size))
            asm_code.add(self.Inst(temp_spot, arg2_spot, arg1_size, 1))
            if temp_spot != out_spot:
                asm_code.add(asm_cmds.Mov(out_spot, temp_spot, arg1_size))
Пример #3
0
    def move_data(self, target_spot, start_spot, size, reg, asm_code):
        """Emits code to move data from start to target.

        Given a target spot, start spot, size of data to move,
        and a register that can be clobbered in the move, this function
        emits code to move all the data. It is efficient whether the input
        spots are registers or memory, and in particular this function
        works even if the input size is not in {1, 2, 4, 8}.

        The given register is used as an intermediary for transferring
        values between the target_spot and start_spot. It is *always* safe
        for `reg` to be one of these two, and in fact it is recommended
        that if either of target_spot or start_spot is a register then
        `reg` be equal to that.
        """
        # TODO: consider padding everything to 8 bytes to reduce the
        # number of mov operations emitted for struct copying.
        shift = 0
        while shift < size:
            reg_size = self._reg_size(size - shift)
            start_spot = start_spot.shift(shift)
            target_spot = target_spot.shift(shift)

            if isinstance(start_spot, LiteralSpot):
                reg = start_spot
            elif reg != start_spot:
                asm_code.add(asm_cmds.Mov(reg, start_spot, reg_size))

            if reg != target_spot:
                asm_code.add(asm_cmds.Mov(target_spot, reg, reg_size))

            shift += reg_size
Пример #4
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        regs = []

        result = get_reg([spotmap[self.output]],
                         [spotmap[self.arg1], spotmap[self.arg2]])
        regs.append(result)

        out_size = self.output.ctype.size
        eq_val_spot = LiteralSpot(1)
        asm_code.add(asm_cmds.Mov(result, eq_val_spot, out_size))

        arg1_spot, arg2_spot = self._fix_both_literal_or_mem(
            spotmap[self.arg1], spotmap[self.arg2], regs, get_reg, asm_code)
        arg1_spot, arg2_spot = self._fix_either_literal64(
            arg1_spot, arg2_spot, regs, get_reg, asm_code)
        arg1_spot, arg2_spot = self._fix_literal_wrong_order(
            arg1_spot, arg2_spot)

        arg_size = self.arg1.ctype.size
        neq_val_spot = LiteralSpot(0)
        label = asm_code.get_label()

        asm_code.add(asm_cmds.Cmp(arg1_spot, arg2_spot, arg_size))
        asm_code.add(self.cmp_command()(label))
        asm_code.add(asm_cmds.Mov(result, neq_val_spot, out_size))
        asm_code.add(asm_cmds.Label(label))

        if result != spotmap[self.output]:
            asm_code.add(asm_cmds.Mov(spotmap[self.output], result, out_size))
Пример #5
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        if spotmap[self.arg] != spots.RAX:
            size = self.arg.ctype.size
            asm_code.add(asm_cmds.Mov(spots.RAX, spotmap[self.arg], size))

        asm_code.add(asm_cmds.Mov(spots.RSP, spots.RBP, 8))
        asm_code.add(asm_cmds.Pop(spots.RBP, None, 8))
        asm_code.add(asm_cmds.Ret())
Пример #6
0
    def _shared_asm(self, Inst, comm, out, arg1, arg2, spotmap, get_reg,
                    asm_code):
        """Make the shared ASM for ADD, MULT, and SUB.

        Inst - the instruction for this
        comm (Bool) - whether the instruction is commutative. if not,
        a "neg" instruction is inserted when the order is flipped.
        """
        ctype = arg1.ctype
        size = ctype.size

        arg1_spot = spotmap[arg1]
        arg2_spot = spotmap[arg2]

        # Get temp register for computation.
        temp = get_reg([spotmap[out], arg1_spot, arg2_spot])

        if temp == arg1_spot:
            if not self._is_imm64(arg2_spot):
                asm_code.add(Inst(temp, arg2_spot, size))
            else:
                temp2 = get_reg([], [temp])
                asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size))
                asm_code.add(Inst(temp, temp2, size))
        elif temp == arg2_spot:
            if not self._is_imm64(arg1_spot):
                asm_code.add(Inst(temp, arg1_spot, size))
            else:
                temp2 = get_reg([], [temp])
                asm_code.add(asm_cmds.Mov(temp2, arg1_spot, size))
                asm_code.add(Inst(temp, temp2, size))

            if not comm:
                asm_code.add(asm_cmds.Neg(temp, None, size))

        else:
            if (not self._is_imm64(arg1_spot)
                    and not self._is_imm64(arg2_spot)):
                asm_code.add(asm_cmds.Mov(temp, arg1_spot, size))
                asm_code.add(Inst(temp, arg2_spot, size))
            elif (self._is_imm64(arg1_spot) and not self._is_imm64(arg2_spot)):
                asm_code.add(asm_cmds.Mov(temp, arg1_spot, size))
                asm_code.add(Inst(temp, arg2_spot, size))
            elif (not self._is_imm64(arg1_spot) and self._is_imm64(arg2_spot)):
                asm_code.add(asm_cmds.Mov(temp, arg2_spot, size))
                asm_code.add(Inst(temp, arg1_spot, size))
                if not comm:
                    asm_code.add(asm_cmds.Neg(temp, None, size))

            else:  # both are imm64
                temp2 = get_reg([], [temp])

                asm_code.add(asm_cmds.Mov(temp, arg1_spot, size))
                asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size))
                asm_code.add(Inst(temp, temp2, size))

        if temp != spotmap[out]:
            asm_code.add(asm_cmds.Mov(spotmap[out], temp, size))
Пример #7
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        """Make the ASM for the operation"""
        size = None

        arg1_spot = spotmap[self.arg1]
        arg2_spot = spotmap[self.arg2]
        output_spot = spotmap[self.output]
        r12_spot = spots.RegSpot("r12")
        r13_spot = spots.RegSpot("r13")
        """
        Both arguments are moved to r12 and r13, to make sure they become regspots
        Operation will be done on these two regs, with the result always in r12
        Then, depending on output_spot being a reg or mem (lit should not be possible), a move or write will be added
        """

        self.move(arg1_spot, r12_spot, asm_code)
        self.move(arg2_spot, r13_spot, asm_code)

        asm_code.add(self.Inst(r12_spot, r13_spot, size))

        # output
        if isinstance(output_spot, spots.RegSpot):
            asm_code.add(asm_cmds.Mov(output_spot, r12_spot, size))

        elif isinstance(output_spot, spots.MemSpot):
            asm_code.add(asm_cmds.Write(output_spot, r12_spot, size))
Пример #8
0
 def make_asm(self, spotmap, home_spots, get_reg, asm_code):
     if spotmap[self.output] == self.arg_reg:
         return
     else:
         asm_code.add(
             asm_cmds.Mov(spotmap[self.output], self.arg_reg,
                          self.output.ctype.size))
Пример #9
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        r = get_reg([spotmap[self.output]])
        asm_code.add(asm_cmds.Lea(r, home_spots[self.var]))

        if r != spotmap[self.output]:
            size = self.output.ctype.size
            asm_code.add(asm_cmds.Mov(spotmap[self.output], r, size))
Пример #10
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        if self.output.ctype.weak_compat(ctypes.bool_t):
            return self._set_bool(spotmap, get_reg, asm_code)

        elif isinstance(spotmap[self.arg], LiteralSpot):
            out_spot = spotmap[self.output]
            arg_spot = spotmap[self.arg]
            size = self.output.ctype.size
            asm_code.add(asm_cmds.Mov(out_spot, arg_spot, size))

        elif self.output.ctype.size <= self.arg.ctype.size:
            if spotmap[self.output] == spotmap[self.arg]:
                return

            if isinstance(spotmap[self.output], RegSpot):
                r = spotmap[self.output]
            elif isinstance(spotmap[self.arg], RegSpot):
                r = spotmap[self.arg]
            else:
                r = get_reg()

            self.move_data(spotmap[self.output], spotmap[self.arg],
                           self.output.ctype.size, r, asm_code)

        else:
            r = get_reg([spotmap[self.output], spotmap[self.arg]])

            # Move from arg_asm -> r_asm
            if self.arg.ctype.signed:
                asm_code.add(
                    asm_cmds.Movsx(r, spotmap[self.arg],
                                   self.output.ctype.size,
                                   self.arg.ctype.size))
            elif self.arg.ctype.size == 4:
                asm_code.add(asm_cmds.Mov(r, spotmap[self.arg], 4))
            else:
                asm_code.add(
                    asm_cmds.Movzx(r, spotmap[self.arg],
                                   self.output.ctype.size,
                                   self.arg.ctype.size))

            # If necessary, move from r_asm -> output_asm
            if r != spotmap[self.output]:
                asm_code.add(
                    asm_cmds.Mov(spotmap[self.output], r,
                                 self.output.ctype.size))
Пример #11
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        size = self.arg.ctype.size

        output_spot = spotmap[self.output]
        arg_spot = spotmap[self.arg]

        if output_spot != arg_spot:
            asm_code.add(asm_cmds.Mov(output_spot, arg_spot, size))
        asm_code.add(self.Inst(output_spot, None, size))
Пример #12
0
    def _fix_either_literal64(self, arg1_spot, arg2_spot, regs, get_reg,
                              asm_code):
        """Move any 64-bit immediate operands to register."""

        if self._is_imm64(arg1_spot):
            size = self.arg1.ctype.size
            new_arg1_spot = get_reg([], regs + [arg2_spot])
            asm_code.add(asm_cmds.Mov(new_arg1_spot, arg1_spot, size))
            return new_arg1_spot, arg2_spot

        # We cannot have both cases because _fix_both_literal is called
        # before this.
        elif self._is_imm64(arg2_spot):
            size = self.arg2.ctype.size
            new_arg2_spot = get_reg([], regs + [arg1_spot])
            asm_code.add(asm_cmds.Mov(new_arg2_spot, arg2_spot, size))
            return arg1_spot, new_arg2_spot
        else:
            return arg1_spot, arg2_spot
Пример #13
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        if not isinstance(spotmap[self.base], MemSpot):
            raise NotImplementedError("expected base in memory spot")

        rel_spot = self.get_rel_spot(spotmap, get_reg, asm_code)
        out_spot = self.get_reg_spot(self.output, spotmap, get_reg)
        asm_code.add(asm_cmds.Lea(out_spot, rel_spot))

        if out_spot != spotmap[self.output]:
            asm_code.add(asm_cmds.Mov(spotmap[self.output], out_spot, 8))
Пример #14
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        ctype = self.arg1.ctype
        size = ctype.size

        output_spot = spotmap[self.output]
        arg1_spot = spotmap[self.arg1]
        arg2_spot = spotmap[self.arg2]

        # Move first operand into RAX if we can do so without clobbering
        # other argument
        moved_to_rax = False
        if spotmap[self.arg1] != spots.RAX and spotmap[self.arg2] != spots.RAX:
            moved_to_rax = True
            asm_code.add(asm_cmds.Mov(spots.RAX, arg1_spot, size))

        # If the divisor is a literal or in a bad register, we must move it
        # to a register.
        if (self._is_imm(spotmap[self.arg2])
                or spotmap[self.arg2] in [spots.RAX, spots.RDX]):
            r = get_reg([], [spots.RAX, spots.RDX])
            asm_code.add(asm_cmds.Mov(r, arg2_spot, size))
            arg2_final_spot = r
        else:
            arg2_final_spot = arg2_spot

        # If we did not move to RAX above, do so here.
        if not moved_to_rax and arg1_spot != self.return_reg:
            asm_code.add(asm_cmds.Mov(spots.RAX, arg1_spot, size))

        if ctype.signed:
            if ctype.size == 4:
                asm_code.add(asm_cmds.Cdq())
            elif ctype.size == 8:
                asm_code.add(asm_cmds.Cqo())
            asm_code.add(asm_cmds.Idiv(arg2_final_spot, None, size))
        else:
            # zero out RDX register
            asm_code.add(asm_cmds.Xor(spots.RDX, spots.RDX, size))
            asm_code.add(asm_cmds.Div(arg2_final_spot, None, size))

        if spotmap[self.output] != self.return_reg:
            asm_code.add(asm_cmds.Mov(output_spot, self.return_reg, size))
Пример #15
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        """Make the ASM for ADD, MULT, and SUB."""
        ctype = self.arg1.ctype
        size = ctype.size

        arg1_spot = spotmap[self.arg1]
        arg2_spot = spotmap[self.arg2]

        # Get temp register for computation.
        temp = get_reg([spotmap[self.output], arg1_spot, arg2_spot])

        if temp == arg1_spot:
            if not self._is_imm64(arg2_spot):
                asm_code.add(self.Inst(temp, arg2_spot, size))
            else:
                temp2 = get_reg([], [temp])
                asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size))
                asm_code.add(self.Inst(temp, temp2, size))
        elif temp == arg2_spot:
            if not self._is_imm64(arg1_spot):
                asm_code.add(self.Inst(temp, arg1_spot, size))
            else:
                temp2 = get_reg([], [temp])
                asm_code.add(asm_cmds.Mov(temp2, arg1_spot, size))
                asm_code.add(self.Inst(temp, temp2, size))

            if not self.comm:
                asm_code.add(asm_cmds.Neg(temp, None, size))

        else:
            if (not self._is_imm64(arg1_spot)
                    and not self._is_imm64(arg2_spot)):
                asm_code.add(asm_cmds.Mov(temp, arg1_spot, size))
                asm_code.add(self.Inst(temp, arg2_spot, size))
            elif (self._is_imm64(arg1_spot) and not self._is_imm64(arg2_spot)):
                asm_code.add(asm_cmds.Mov(temp, arg1_spot, size))
                asm_code.add(self.Inst(temp, arg2_spot, size))
            elif (not self._is_imm64(arg1_spot) and self._is_imm64(arg2_spot)):
                asm_code.add(asm_cmds.Mov(temp, arg2_spot, size))
                asm_code.add(self.Inst(temp, arg1_spot, size))
                if not self.comm:
                    asm_code.add(asm_cmds.Neg(temp, None, size))

            else:  # both are imm64
                temp2 = get_reg([], [temp])

                asm_code.add(asm_cmds.Mov(temp, arg1_spot, size))
                asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size))
                asm_code.add(self.Inst(temp, temp2, size))

        if temp != spotmap[self.output]:
            asm_code.add(asm_cmds.Mov(spotmap[self.output], temp, size))
Пример #16
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        size = self.cond.ctype.size

        if isinstance(spotmap[self.cond], LiteralSpot):
            r = get_reg()
            asm_code.add(asm_cmds.Mov(r, spotmap[self.cond], size))
            cond_spot = r
        else:
            cond_spot = spotmap[self.cond]

        zero_spot = LiteralSpot("0")
        asm_code.add(asm_cmds.Cmp(cond_spot, zero_spot, size))
        asm_code.add(self.command(self.label))
Пример #17
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        ctype = self.arg1.ctype

        # Unsigned multiplication
        if not ctype.signed:
            arg1_spot = spotmap[self.arg1]
            arg2_spot = spotmap[self.arg2]
            size = ctype.size

            if arg1_spot == spots.RAX:
                mul_spot = arg2_spot
            elif arg2_spot == spots.RAX:
                mul_spot = arg1_spot
            else:
                # If either is literal, move that one to RAX
                if self._is_imm(arg2_spot):
                    asm_code.add(asm_cmds.Mov(spots.RAX, arg2_spot, size))
                    mul_spot = arg1_spot
                else:
                    asm_code.add(asm_cmds.Mov(spots.RAX, arg1_spot, size))
                    mul_spot = arg2_spot

            # Operand is an immediate, move it to a register
            if self._is_imm(mul_spot):
                r = get_reg([], [spots.RAX])
                asm_code.add(asm_cmds.Mov(r, mul_spot, ctype.size))
                mul_spot = r

            asm_code.add(asm_cmds.Mul(mul_spot, None, ctype.size))

            if spotmap[self.output] != spots.RAX:
                asm_code.add(
                    asm_cmds.Mov(spotmap[self.output], spots.RAX, ctype.size))

        # Signed multiplication
        else:
            self._shared_asm(asm_cmds.Imul, True, self.output, self.arg1,
                             self.arg2, spotmap, get_reg, asm_code)
Пример #18
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        func_spot = spotmap[self.func]

        func_size = self.func.ctype.size
        ret_size = self.func.ctype.arg.ret.size

        # Check if function pointer spot will be clobbered by moving the
        # arguments into the correct registers.
        if spotmap[self.func] in self.arg_regs[0:len(self.args)]:
            # Get a register which isn't one of the unallowed registers.
            r = get_reg([], self.arg_regs[0:len(self.args)])
            asm_code.add(asm_cmds.Mov(r, spotmap[self.func], func_size))
            func_spot = r

        for arg, reg in zip(self.args, self.arg_regs):
            if spotmap[arg] == reg:
                continue
            asm_code.add(asm_cmds.Mov(reg, spotmap[arg], arg.ctype.size))

        asm_code.add(asm_cmds.Call(func_spot, None, self.func.ctype.size))

        if not self.void_return and spotmap[self.ret] != spots.RAX:
            asm_code.add(asm_cmds.Mov(self.ret, spots.RAX, ret_size))
Пример #19
0
    def _generate_asm(self, commands, live_vars, spotmap):
        """Generate assembly code."""

        # This is kinda hacky...
        max_offset = max(spot.rbp_offset() for spot in spotmap.values())
        #if max_offset % 16 != 0:
        #    max_offset += 16 - max_offset % 16

        # Back up rbp and move rsp

        #self.asm_code.add(asm_cmds.Push(spots.RBP, None, 8))
        self.asm_code.add(asm_cmds.Sub(spots.RSP, spots.LiteralSpot(1)))
        self.asm_code.add(asm_cmds.Write(spots.RSP, spots.RBP))

        self.asm_code.add(asm_cmds.Mov(spots.RBP, spots.RSP))

        offset_spot = LiteralSpot(str(max_offset))

        self.asm_code.add(asm_cmds.Sub(spots.RSP, offset_spot))

        # Generate code for each command
        for i, command in enumerate(commands):
            self.asm_code.add(asm_cmds.Comment(type(command).__name__.upper()))

            def get_reg(pref=None, conf=None):
                if not pref: pref = []
                if not conf: conf = []

                # Spot is bad if it is containing a variable that is live both
                # entering and exiting this command.
                bad_vars = set(live_vars[i][0]) & set(live_vars[i][1])
                bad_spots = set(spotmap[var] for var in bad_vars)

                # Spot is free if it is where an output is stored.
                for v in command.outputs():
                    bad_spots.discard(spotmap[v])

                # Spot is bad if it is listed as a conflicting spot.
                bad_spots |= set(conf)

                for s in (pref + self.all_registers):
                    if isinstance(s, RegSpot) and s not in bad_spots:
                        return s

                raise NotImplementedError("spill required for get_reg")

            command.make_asm(spotmap, spotmap, get_reg, self.asm_code)
Пример #20
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        addr_spot = spotmap[self.addr]
        value_spot = spotmap[self.val]

        if isinstance(addr_spot, RegSpot):
            addr_r = addr_spot
        else:
            addr_r = get_reg([], [value_spot])
            asm_code.add(asm_cmds.Mov(addr_r, addr_spot, 8))

        indir_spot = MemSpot(addr_r)
        if isinstance(value_spot, RegSpot):
            temp_reg = value_spot
        else:
            temp_reg = get_reg([], [addr_r])

        self.move_data(indir_spot, value_spot, self.val.ctype.size, temp_reg,
                       asm_code)
Пример #21
0
    def _fix_both_literal_or_mem(self, arg1_spot, arg2_spot, regs, get_reg,
                                 asm_code):
        """Fix arguments if both are literal or memory.

        Adds any called registers to given regs list. Returns tuple where
        first element is new spot of arg1 and second element is new spot of
        arg2.
        """
        if ((isinstance(arg1_spot, LiteralSpot)
             and isinstance(arg2_spot, LiteralSpot))
                or (isinstance(arg1_spot, MemSpot)
                    and isinstance(arg2_spot, MemSpot))):

            # No need to worry about r overlapping with arg1 or arg2 because
            # in this case both are literal/memory.
            r = get_reg([], regs)
            regs.append(r)
            asm_code.add(asm_cmds.Mov(r, arg1_spot, self.arg1.ctype.size))
            return r, arg2_spot
        else:
            return arg1_spot, arg2_spot
Пример #22
0
    def get_rel_spot(self, spotmap, get_reg, asm_code):
        """Get a relative spot for the relative value."""

        # If there's no count, we only need to shift by the chunk
        if not self.count:
            return spotmap[self.base].shift(self.chunk)

        # If there is a count in a literal spot, we're good to go. Also,
        # if count is already in a register, we're good to go by just using
        # that register for the count. (Because we require the count be 32-
        # or 64-bit, we know the full register stores exactly the value of
        # count).
        if (isinstance(spotmap[self.count], LiteralSpot)
                or isinstance(spotmap[self.count], RegSpot)):
            return spotmap[self.base].shift(self.chunk, spotmap[self.count])

        # Otherwise, move count to a register.
        r = get_reg([], [spotmap[self.val]] + self._used_regs)
        self._used_regs.append(r)

        count_size = self.count.ctype.size
        asm_code.add(asm_cmds.Mov(r, spotmap[self.count], count_size))

        return spotmap[self.base].shift(self.chunk, r)
Пример #23
0
    def move(self, src_spot, dst_spot, asm_code):
        # Move data from src_spot to dst_spot
        """
        The following spot type combinations are possible:
        src     dst
        -----------
        lit     reg
        lit     mem
        reg     reg
        reg     mem
        mem     reg
        mem     mem

        Note: moving towards a literal spot makes no sense
        """

        # this stays here until I removed size from all functions
        size = None

        # temporary register spot
        r12_spot = spots.RegSpot("r12")
        r13_spot = spots.RegSpot("r13")
        r7_spot = spots.RegSpot("r7")  # Warning! also used by read/write cmds

        # handle memspots with counts that are registers
        # reminder: base + offset + (chunk * count)
        if isinstance(src_spot, spots.MemSpot):
            if isinstance(src_spot.count, spots.RegSpot):
                asm_code.add(
                    asm_cmds.Load(spots.LiteralSpot(src_spot.chunk), r7_spot,
                                  size))
                asm_code.add(asm_cmds.Mult(r7_spot, src_spot.count, size))
                if src_spot.offset < 0:
                    asm_code.add(
                        asm_cmds.Sub(r7_spot,
                                     spots.LiteralSpot(abs(src_spot.offset)),
                                     size))
                else:
                    asm_code.add(
                        asm_cmds.Add(r7_spot,
                                     spots.LiteralSpot(abs(src_spot.offset)),
                                     size))
                asm_code.add(
                    asm_cmds.Add(r7_spot, spots.LiteralSpot(src_spot.base),
                                 size))
                asm_code.add(asm_cmds.Read(r7_spot, r12_spot, size))
                src_spot = r12_spot

        orig_dst_spot = dst_spot
        changed_dst_spot = False

        # we write to the correct dst_spot later on
        if isinstance(dst_spot, spots.MemSpot):
            if isinstance(dst_spot.count, spots.RegSpot):
                dst_spot = r13_spot
                changed_dst_spot = True

        # lit, reg
        if isinstance(src_spot, spots.LiteralSpot) and isinstance(
                dst_spot, spots.RegSpot):
            # load the literal to the destination reg
            asm_code.add(asm_cmds.Load(src_spot, dst_spot, size))

        # lit, mem
        elif isinstance(src_spot, spots.LiteralSpot) and isinstance(
                dst_spot, spots.MemSpot):
            # load the literal to r12, then write r12 to dst

            # change r12 to r13 if r12 is the destination address
            tmp_spot = r12_spot
            if dst_spot == r12_spot:
                tmp_spot = r13_spot
            asm_code.add(asm_cmds.Load(src_spot, r12_spot, size))
            asm_code.add(asm_cmds.Write(dst_spot, r12_spot, size))

        # reg, reg
        elif isinstance(src_spot, spots.RegSpot) and isinstance(
                dst_spot, spots.RegSpot):
            # move the register content using OR r0
            asm_code.add(asm_cmds.Mov(dst_spot, src_spot, size))

        # reg, mem
        elif isinstance(src_spot, spots.RegSpot) and isinstance(
                dst_spot, spots.MemSpot):
            # write the src reg to dst
            asm_code.add(asm_cmds.Write(dst_spot, src_spot, size))

        # mem, reg
        elif isinstance(src_spot, spots.MemSpot) and isinstance(
                dst_spot, spots.RegSpot):
            # read the src to dst reg
            asm_code.add(asm_cmds.Read(src_spot, dst_spot, size))

        # mem, mem
        elif isinstance(src_spot, spots.MemSpot) and isinstance(
                dst_spot, spots.MemSpot):
            # TODO: add COPY to the assembly list, and use that instead
            # for now, read src to r12, and write r12 to dst
            if dst_spot == r12_spot:
                print(
                    "ERROR: destination is R12. To fix implement copy instruction"
                )
            asm_code.add(asm_cmds.Read(src_spot, r12_spot, size))
            asm_code.add(asm_cmds.Write(dst_spot, r12_spot, size))

        # if we changed the dst_spot, write it to the original dst_spot
        if changed_dst_spot:
            asm_code.add(
                asm_cmds.Load(spots.LiteralSpot(orig_dst_spot.chunk), r7_spot,
                              size))
            asm_code.add(asm_cmds.Mult(r7_spot, orig_dst_spot.count, size))
            if orig_dst_spot.offset < 0:
                asm_code.add(
                    asm_cmds.Sub(r7_spot,
                                 spots.LiteralSpot(abs(orig_dst_spot.offset)),
                                 size))
            else:
                asm_code.add(
                    asm_cmds.Add(r7_spot,
                                 spots.LiteralSpot(orig_dst_spot.offset),
                                 size))
            asm_code.add(
                asm_cmds.Add(r7_spot, spots.LiteralSpot(orig_dst_spot.base),
                             size))
            asm_code.add(asm_cmds.Write(r7_spot, dst_spot, size))