Author: Richard Plangger <planri...@gmail.com> Branch: s390x-backend Changeset: r82174:2b50cfaee409 Date: 2016-02-12 12:39 +0100 http://bitbucket.org/pypy/pypy/changeset/2b50cfaee409/
Log: replaced arith left shift with logical (other backends do not use arith shift there!), do not call memcpy for strings anymore, s390x has a dedicated instr. to do just that. this removes the overhead for calling simplifications to the register allocator and assembler some small testsn diff --git a/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py b/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py --- a/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py +++ b/rpython/jit/backend/llsupport/test/test_pinned_object_rewrite.py @@ -127,7 +127,7 @@ i0 = getfield_gc_i(ConstPtr(pinned_obj_gcref), descr=pinned_obj_my_int_descr) """, """ [] - p1 = gc_load_indexed_r(ConstPtr(ptr_array_gcref), %(0 * ptr_array_descr.itemsize + 1)s, 1, 0, %(ptr_array_descr.itemsize)s) + p1 = gc_load_r(ConstPtr(ptr_array_gcref), %(0 * ptr_array_descr.itemsize + 1)s, %(ptr_array_descr.itemsize)s) i0 = gc_load_i(p1, 0, -%(pinned_obj_my_int_descr.field_size)s) """) assert len(self.gc_ll_descr.last_moving_obj_tracker._indexes) == 1 diff --git a/rpython/jit/backend/zarch/opassembler.py b/rpython/jit/backend/zarch/opassembler.py --- a/rpython/jit/backend/zarch/opassembler.py +++ b/rpython/jit/backend/zarch/opassembler.py @@ -589,7 +589,7 @@ # set SCRATCH2 to 1 << r1 mc.LGHI(r.SCRATCH2, l.imm(1)) - mc.SLAG(r.SCRATCH2, r.SCRATCH2, l.addr(0,r.SCRATCH)) + mc.SLLG(r.SCRATCH2, r.SCRATCH2, l.addr(0,r.SCRATCH)) # set this bit inside the byte of interest @@ -1002,20 +1002,17 @@ if src_ofs.is_imm(): value = src_ofs.value << scale if check_imm_value(value): - if dst is not src_ptr: - self.mc.LGR(dst, src_ptr) - if value != 0: - self.mc.AGHI(dst, l.imm(value)) + self.mc.AGHIK(dst, src_ptr, l.imm(value)) else: - self.mc.load_imm(dst, value) - self.mc.AGR(dst, src_ptr) + # it is fine to use r1 here, because it will + # only hold a value before invoking the memory copy + self.mc.load_imm(r.SCRATCH, value) + self.mc.AGRK(dst, src_ptr, r.SCRATCH) elif scale == 0: - if dst is not src_ptr: - self.mc.LGR(dst, src_ptr) - self.mc.AGR(dst, src_ofs) + self.mc.AGRK(dst, src_ptr, src_ofs) else: - self.mc.SLLG(dst, src_ofs, l.addr(scale)) - self.mc.AGR(dst, src_ptr) + self.mc.SLLG(r.SCRATCH, src_ofs, l.addr(scale)) + self.mc.AGRK(dst, src_ptr, r.SCRATCH) def _emit_copycontent(self, arglocs, is_unicode): [src_ptr_loc, dst_ptr_loc, @@ -1033,34 +1030,40 @@ assert itemsize == 1 scale = 0 - self._emit_load_for_copycontent(r.SCRATCH, src_ptr_loc, src_ofs_loc, scale) - self._emit_load_for_copycontent(r.SCRATCH2, dst_ptr_loc, dst_ofs_loc, scale) - # - # DO NOT USE r2-r6 before this line! - # either of the parameter (e.g. str_ptr_loc, ...) locations might be allocated + # 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(r.r4, length << scale) + self.mc.load_imm(dst_len, length << scale) else: if scale > 0: - self.mc.SLAG(r.r4, length_loc, l.addr(scale)) - elif length_loc is not r.r4: - self.mc.LGR(r.r4, length_loc) + 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.LGR(r.r3, r.SCRATCH) - self.mc.LGR(r.r2, r.SCRATCH2) - if basesize != 0: - self.mc.AGHI(r.r3, l.imm(basesize)) - if basesize != 0: - self.mc.AGHI(r.r2, l.imm(basesize)) + self.mc.AGHI(src, l.imm(basesize)) + self.mc.AGHI(dst, l.imm(basesize)) - self.mc.load_imm(self.mc.RAW_CALL_REG, self.memcpy_addr) - self.mc.raw_call() + # 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_zero_array(self, op, arglocs, regalloc): base_loc, startindex_loc, length_loc, \ - ofs_loc, itemsize_loc, pad_byte_loc = arglocs + ofs_loc, itemsize_loc = arglocs if ofs_loc.is_imm(): assert check_imm_value(ofs_loc.value) @@ -1073,24 +1076,21 @@ else: self.mc.AGR(base_loc, startindex_loc) assert not length_loc.is_imm() - self.mc.XGR(pad_byte_loc, pad_byte_loc) - pad_plus = r.odd_reg(pad_byte_loc) - self.mc.XGR(pad_plus, pad_plus) - self.mc.XGR(r.SCRATCH, r.SCRATCH) + # contents of r0 do not matter because r1 is zero, so + # no copying takes place + self.mc.XGR(r.r1, r.r1) + + assert base_loc.is_even() + assert length_loc.value == base_loc.value + 1 + # s390x has memset directly as a hardware instruction!! # it needs 5 registers allocated - # dst = rX, length = rX+1 (ensured by the regalloc) - # pad_byte is rY to rY+1 - # scratch register holds the value written to dst - assert pad_byte_loc.is_even() - assert pad_plus.value == pad_byte_loc.value + 1 - assert base_loc.is_even() - assert length_loc.value == base_loc.value + 1 - assert base_loc.value != pad_byte_loc.value + # dst = rX, dst len = rX+1 (ensured by the regalloc) + # src = r0, src len = r1 + self.mc.MVCLE(base_loc, r.r0, l.addr(0)) # 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.MVCLE(base_loc, pad_byte_loc, l.addr(0, r.SCRATCH)) self.mc.BRC(c.OF, l.imm(-self.mc.MVCLE_byte_count)) diff --git a/rpython/jit/backend/zarch/regalloc.py b/rpython/jit/backend/zarch/regalloc.py --- a/rpython/jit/backend/zarch/regalloc.py +++ b/rpython/jit/backend/zarch/regalloc.py @@ -161,6 +161,14 @@ def ensure_even_odd_pair(self, var, bindvar, bind_first=True, must_exist=True, load_loc_odd=True, move_regs=True): + """ Allocates two registers that can be used by the instruction. + var: is the original register holding the value + bindvar: is the variable that will be bound + (= self.reg_bindings[bindvar] = new register) + bind_first: the even register will be bound to bindvar, + if bind_first == False: the odd register will + be bound + """ self._check_type(var) prev_loc = self.loc(var, must_exist=must_exist) var2 = TempVar() @@ -592,13 +600,23 @@ return imm(box.getint()) return self.rm.ensure_reg(box, force_in_reg=True, selected_reg=selected_reg) - def ensure_reg_or_any_imm(self, box): + def ensure_reg_or_20bit_imm(self, box, selected_reg=None): if box.type == FLOAT: return self.fprm.ensure_reg(box, True) else: + if helper.check_imm20(box): + return imm(box.getint()) + return self.rm.ensure_reg(box, force_in_reg=True, selected_reg=selected_reg) + + def ensure_reg_or_any_imm(self, box, selected_reg=None): + if box.type == FLOAT: + return self.fprm.ensure_reg(box, True, + selected_reg=selected_reg) + else: if isinstance(box, Const): return imm(box.getint()) - return self.rm.ensure_reg(box, force_in_reg=True) + return self.rm.ensure_reg(box, force_in_reg=True, + selected_reg=selected_reg) def get_scratch_reg(self, type, selected_reg=None): if type == FLOAT: @@ -798,7 +816,7 @@ def _prepare_gc_load(self, op): base_loc = self.ensure_reg(op.getarg(0), force_in_reg=True) - index_loc = self.ensure_reg_or_any_imm(op.getarg(1)) + index_loc = self.ensure_reg_or_20bit_imm(op.getarg(1)) size_box = op.getarg(2) assert isinstance(size_box, ConstInt) size = abs(size_box.value) @@ -815,7 +833,7 @@ def _prepare_gc_load_indexed(self, op): base_loc = self.ensure_reg(op.getarg(0), force_in_reg=True) - index_loc = self.ensure_reg(op.getarg(1), force_in_reg=True) + index_loc = self.ensure_reg_or_20bit_imm(op.getarg(1)) scale_box = op.getarg(2) offset_box = op.getarg(3) size_box = op.getarg(4) @@ -841,7 +859,7 @@ def prepare_gc_store(self, op): base_loc = self.ensure_reg(op.getarg(0), force_in_reg=True) - index_loc = self.ensure_reg_or_any_imm(op.getarg(1)) + index_loc = self.ensure_reg_or_20bit_imm(op.getarg(1)) value_loc = self.ensure_reg(op.getarg(2)) size_box = op.getarg(3) assert isinstance(size_box, ConstInt) @@ -852,7 +870,7 @@ def prepare_gc_store_indexed(self, op): args = op.getarglist() base_loc = self.ensure_reg(op.getarg(0), force_in_reg=True) - index_loc = self.ensure_reg_or_any_imm(op.getarg(1)) + index_loc = self.ensure_reg_or_20bit_imm(op.getarg(1)) value_loc = self.ensure_reg(op.getarg(2)) scale_box = op.getarg(3) offset_box = op.getarg(4) @@ -953,21 +971,20 @@ return self._prepare_call_default(op) def prepare_zero_array(self, op): + # args: base, start, len, scale_start, scale_len itemsize, ofs, _ = unpack_arraydescr(op.getdescr()) startindex_loc = self.ensure_reg_or_16bit_imm(op.getarg(1)) tempvar = TempInt() self.rm.temp_boxes.append(tempvar) ofs_loc = self.ensure_reg_or_16bit_imm(ConstInt(ofs)) - pad_byte, _ = self.rm.ensure_even_odd_pair(tempvar, tempvar, - bind_first=True, must_exist=False, move_regs=False) - base_loc, length_loc = self.rm.ensure_even_odd_pair(op.getarg(0), op, + base_loc, length_loc = self.rm.ensure_even_odd_pair(op.getarg(0), tempvar, bind_first=True, must_exist=False, load_loc_odd=False) length_box = op.getarg(2) ll = self.rm.loc(length_box) if length_loc is not ll: self.assembler.regalloc_mov(ll, length_loc) - return [base_loc, startindex_loc, length_loc, ofs_loc, imm(itemsize), pad_byte] + return [base_loc, startindex_loc, length_loc, ofs_loc, imm(itemsize)] def prepare_cond_call(self, op): self.load_condition_into_cc(op.getarg(0)) @@ -1102,12 +1119,25 @@ return [loc0, loc1] def prepare_copystrcontent(self, op): - src_ptr_loc = self.ensure_reg(op.getarg(0), force_in_reg=True) + """ this function needs five registers. + src & src_len: are allocated using ensure_even_odd_pair. + note that these are tmp registers, thus the actual variable + value is not modified. + src_len: when entering the assembler, src_ofs_loc's value is contained + in src_len register. + """ + src_tmp = TempVar() + src_ptr_loc, _ = \ + self.rm.ensure_even_odd_pair(op.getarg(0), + src_tmp, bind_first=True, + must_exist=False, load_loc_odd=False) + src_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(2)) + self.rm.temp_boxes.append(src_tmp) dst_ptr_loc = self.ensure_reg(op.getarg(1), force_in_reg=True) - src_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(2)) dst_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(3)) length_loc = self.ensure_reg_or_any_imm(op.getarg(4)) - self._spill_before_call(save_all_regs=False) + # no need to spill, we do not call memcpy, but we use s390x's + # hardware instruction to copy memory return [src_ptr_loc, dst_ptr_loc, src_ofs_loc, dst_ofs_loc, length_loc] diff --git a/rpython/jit/backend/zarch/test/test_assembler.py b/rpython/jit/backend/zarch/test/test_assembler.py --- a/rpython/jit/backend/zarch/test/test_assembler.py +++ b/rpython/jit/backend/zarch/test/test_assembler.py @@ -226,6 +226,35 @@ self.a.mc.BCR(con.ANY, r.r14) assert run_asm(self.a) == 15 + def test_shift_same_register(self): + self.a.mc.load_imm(r.r3, 0x1) + self.a.mc.SLLG(r.r2, r.r3, loc.addr(1)) + self.a.mc.BCR(con.ANY, r.r14) + assert run_asm(self.a) == 2 + + def test_shift_arith(self): + self.a.mc.load_imm(r.r2, -14) + self.a.mc.SLAG(r.r2, r.r2, loc.addr(1)) + self.a.mc.BCR(con.ANY, r.r14) + assert run_asm(self.a) == -28 + + def test_shift_negative_logical(self): + self.a.mc.load_imm(r.r2, -14) + self.a.mc.SLLG(r.r2, r.r2, loc.addr(1)) + self.a.mc.BCR(con.ANY, r.r14) + assert run_asm(self.a) == -28 + + def test_shift_negative_logical_2(self): + self.a.mc.load_imm(r.r2, -2) + self.a.mc.SLLG(r.r2, r.r2, loc.addr(63)) + self.a.mc.BCR(con.ANY, r.r14) + assert run_asm(self.a) == 0 + + def test_shift_negative_logical_3(self): + self.a.mc.load_imm(r.r2, -2) + self.a.mc.SLLG(r.r3, r.r2, loc.addr(1)) + self.a.mc.BCR(con.ANY, r.r14) + assert run_asm(self.a) == -2 def test_load_small_int_to_reg(self): self.a.mc.LGHI(r.r2, loc.imm(123)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit