Ejemplo n.º 1
0
    def _emit_copycontent(self, arglocs, is_unicode):
        [src_ptr_loc, dst_ptr_loc, src_ofs_loc, dst_ofs_loc,
         length_loc] = arglocs

        if is_unicode:
            basesize, itemsize, _ = symbolic.get_array_token(
                rstr.UNICODE, self.cpu.translate_support_code)
            if itemsize == 2: scale = 1
            elif itemsize == 4: scale = 2
            else: raise AssertionError
        else:
            basesize, itemsize, _ = symbolic.get_array_token(
                rstr.STR, self.cpu.translate_support_code)
            assert itemsize == 1
            basesize -= 1  # for the extra null character
            scale = 0

        # src and src_len are tmp registers
        src = src_ptr_loc
        src_len = r.odd_reg(src)
        dst = r.r0
        dst_len = r.r1
        self._emit_load_for_copycontent(src, src_ptr_loc, src_ofs_loc, scale)
        self._emit_load_for_copycontent(dst, dst_ptr_loc, dst_ofs_loc, scale)

        if length_loc.is_imm():
            length = length_loc.getint()
            self.mc.load_imm(dst_len, length << scale)
        else:
            if scale > 0:
                self.mc.SLLG(dst_len, length_loc, l.addr(scale))
            else:
                self.mc.LGR(dst_len, length_loc)
        # ensure that src_len is as long as dst_len, otherwise
        # padding bytes are written to dst
        self.mc.LGR(src_len, dst_len)

        self.mc.AGHI(src, l.imm(basesize))
        self.mc.AGHI(dst, l.imm(basesize))

        # s390x has memset directly as a hardware instruction!!
        # 0xB8 means we might reference dst later
        self.mc.MVCLE(dst, src, l.addr(0xB8))
        # NOTE this instruction can (determined by the cpu), just
        # quit the movement any time, thus it is looped until all bytes
        # are copied!
        self.mc.BRC(c.OF, l.imm(-self.mc.MVCLE_byte_count))
Ejemplo n.º 2
0
    def _emit_copycontent(self, arglocs, is_unicode):
        [src_ptr_loc, dst_ptr_loc,
         src_ofs_loc, dst_ofs_loc, length_loc] = arglocs

        if is_unicode:
            basesize, itemsize, _ = symbolic.get_array_token(rstr.UNICODE,
                                        self.cpu.translate_support_code)
            if   itemsize == 2: scale = 1
            elif itemsize == 4: scale = 2
            else: raise AssertionError
        else:
            basesize, itemsize, _ = symbolic.get_array_token(rstr.STR,
                                        self.cpu.translate_support_code)
            assert itemsize == 1
            scale = 0

        # src and src_len are tmp registers
        src = src_ptr_loc
        src_len = r.odd_reg(src)
        dst = r.r0
        dst_len = r.r1
        self._emit_load_for_copycontent(src, src_ptr_loc, src_ofs_loc, scale)
        self._emit_load_for_copycontent(dst, dst_ptr_loc, dst_ofs_loc, scale)

        if length_loc.is_imm():
            length = length_loc.getint()
            self.mc.load_imm(dst_len, length << scale)
        else:
            if scale > 0:
                self.mc.SLLG(dst_len, length_loc, l.addr(scale))
            else:
                self.mc.LGR(dst_len, length_loc)
        # ensure that src_len is as long as dst_len, otherwise
        # padding bytes are written to dst
        self.mc.LGR(src_len, dst_len)

        self.mc.AGHI(src, l.imm(basesize))
        self.mc.AGHI(dst, l.imm(basesize))

        # s390x has memset directly as a hardware instruction!!
        # 0xB8 means we might reference dst later
        self.mc.MVCLE(dst, src, l.addr(0xB8))
        # NOTE this instruction can (determined by the cpu), just
        # quit the movement any time, thus it is looped until all bytes
        # are copied!
        self.mc.BRC(c.OF, l.imm(-self.mc.MVCLE_byte_count))
Ejemplo n.º 3
0
    def force_allocate_reg_pair(self, even_var, odd_var, forbidden_vars):
        """ Forcibly allocate a register for the new variable even_var.
            even_var will have an even register (odd_var, you guessed it,
            will have an odd register).
        """
        self._check_type(even_var)
        self._check_type(odd_var)
        if isinstance(even_var, TempVar):
            self.longevity[even_var] = (self.position, self.position)
        if isinstance(odd_var, TempVar):
            self.longevity[odd_var] = (self.position, self.position)

        # this function steps through the following:
        # 1) maybe there is an even/odd pair that is always
        #    free, then allocate them!
        # 2) try to just spill one variable in either the even
        #    or the odd reg
        # 3) spill two variables

        # start in 1)
        SPILL_EVEN = 0
        SPILL_ODD = 1
        even, odd = None, None
        candidates = []
        i = len(self.free_regs)-1
        while i >= 0:
            even = self.free_regs[i]
            if even.value == 13:
                i -= 1
                continue
            if even.is_even():
                # found an even registers that is actually free
                odd = r.odd_reg(even)
                if odd not in self.free_regs:
                    # sadly odd is not free, but for spilling
                    # we found a candidate
                    candidates.append((even, odd, SPILL_ODD))
                    i -= 1
                    continue
                # even is free and so is odd! allocate these
                # two registers
                assert even_var not in self.reg_bindings
                assert odd_var not in self.reg_bindings
                self.reg_bindings[even_var] = even
                self.reg_bindings[odd_var] = odd
                self.free_regs = [fr for fr in self.free_regs \
                                  if fr is not even and \
                                     fr is not odd]
                return even, odd
            else:
                # an odd free register, maybe the even one is
                # a candidate?
                odd = even
                even = r.even_reg(odd)
                if even not in self.free_regs:
                    # yes even might be a candidate
                    # this means that odd is free, but not even
                    candidates.append((even, odd, SPILL_EVEN))
            i -= 1

        reverse_mapping = {}
        for v, reg in self.reg_bindings.items():
            reverse_mapping[reg] = v

        # needs to spill one variable
        for even, odd, which_to_spill in candidates:
            # no heuristic, pick the first
            if which_to_spill == SPILL_EVEN:
                orig_var_even = reverse_mapping[even]
                if orig_var_even in forbidden_vars:
                    continue # duh!
                self._sync_var(orig_var_even)
                del self.reg_bindings[orig_var_even]
            elif which_to_spill == SPILL_ODD:
                orig_var_odd = reverse_mapping[odd]
                if orig_var_odd in forbidden_vars:
                    continue # duh!
                self._sync_var(orig_var_odd)
                del self.reg_bindings[orig_var_odd]
            
            # well, we got away with a single spill :)
            self.free_regs = [fr for fr in self.free_regs \
                              if fr is not even and \
                                 fr is not odd]
            self.reg_bindings[even_var] = even
            self.reg_bindings[odd_var] = odd
            return even, odd

        # there is no candidate pair that only would
        # require one spill, thus we need to spill two!
        # this is a rare case!
        for even, odd in r.MANAGED_REG_PAIRS:
            orig_var_even = reverse_mapping.get(even,None)
            orig_var_odd = reverse_mapping.get(odd,None)
            if orig_var_even in forbidden_vars or \
               orig_var_odd in forbidden_vars:
                continue

            if orig_var_even is not None:
                self._sync_var(orig_var_even)
                del self.reg_bindings[orig_var_even]
            if orig_var_odd is not None:
                self._sync_var(orig_var_odd)
                del self.reg_bindings[orig_var_odd]

            self.reg_bindings[even_var] = even
            self.reg_bindings[odd_var] = odd
            break
        else:
            # no break! this is bad. really bad
            raise NoVariableToSpill()

        return even, odd
Ejemplo n.º 4
0
    def force_allocate_reg_pair(self, even_var, odd_var, forbidden_vars):
        """ Forcibly allocate a register for the new variable even_var.
            even_var will have an even register (odd_var, you guessed it,
            will have an odd register).
        """
        self._check_type(even_var)
        self._check_type(odd_var)
        if isinstance(even_var, TempVar):
            self.longevity[even_var] = (self.position, self.position)
        if isinstance(odd_var, TempVar):
            self.longevity[odd_var] = (self.position, self.position)

        # this function steps through the following:
        # 1) maybe there is an even/odd pair that is always
        #    free, then allocate them!
        # 2) try to just spill one variable in either the even
        #    or the odd reg
        # 3) spill two variables

        # start in 1)
        SPILL_EVEN = 0
        SPILL_ODD = 1
        even, odd = None, None
        candidates = []
        i = len(self.free_regs) - 1
        while i >= 0:
            even = self.free_regs[i]
            if even.value == 13:
                i -= 1
                continue
            if even.is_even():
                # found an even registers that is actually free
                odd = r.odd_reg(even)
                if odd not in self.free_regs:
                    # sadly odd is not free, but for spilling
                    # we found a candidate
                    candidates.append((even, odd, SPILL_ODD))
                    i -= 1
                    continue
                # even is free and so is odd! allocate these
                # two registers
                assert even_var not in self.reg_bindings
                assert odd_var not in self.reg_bindings
                self.reg_bindings[even_var] = even
                self.reg_bindings[odd_var] = odd
                self.free_regs = [fr for fr in self.free_regs \
                                  if fr is not even and \
                                     fr is not odd]
                return even, odd
            else:
                # an odd free register, maybe the even one is
                # a candidate?
                odd = even
                even = r.even_reg(odd)
                if even not in self.free_regs:
                    # yes even might be a candidate
                    # this means that odd is free, but not even
                    candidates.append((even, odd, SPILL_EVEN))
            i -= 1

        reverse_mapping = {}
        for v, reg in self.reg_bindings.items():
            reverse_mapping[reg] = v

        # needs to spill one variable
        for even, odd, which_to_spill in candidates:
            # no heuristic, pick the first
            if which_to_spill == SPILL_EVEN:
                orig_var_even = reverse_mapping[even]
                if orig_var_even in forbidden_vars:
                    continue  # duh!
                self._sync_var(orig_var_even)
                del self.reg_bindings[orig_var_even]
            elif which_to_spill == SPILL_ODD:
                orig_var_odd = reverse_mapping[odd]
                if orig_var_odd in forbidden_vars:
                    continue  # duh!
                self._sync_var(orig_var_odd)
                del self.reg_bindings[orig_var_odd]

            # well, we got away with a single spill :)
            self.free_regs = [fr for fr in self.free_regs \
                              if fr is not even and \
                                 fr is not odd]
            self.reg_bindings[even_var] = even
            self.reg_bindings[odd_var] = odd
            return even, odd

        # there is no candidate pair that only would
        # require one spill, thus we need to spill two!
        # this is a rare case!
        for even, odd in r.MANAGED_REG_PAIRS:
            orig_var_even = reverse_mapping.get(even, None)
            orig_var_odd = reverse_mapping.get(odd, None)
            if orig_var_even in forbidden_vars or \
               orig_var_odd in forbidden_vars:
                continue

            if orig_var_even is not None:
                self._sync_var(orig_var_even)
                del self.reg_bindings[orig_var_even]
            if orig_var_odd is not None:
                self._sync_var(orig_var_odd)
                del self.reg_bindings[orig_var_odd]

            self.reg_bindings[even_var] = even
            self.reg_bindings[odd_var] = odd
            break
        else:
            # no break! this is bad. really bad
            raise NoVariableToSpill()

        return even, odd