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))
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))
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
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