[pypy-commit] pypy s390x-backend: more skeleton structure
plan_rich
noreply at buildbot.pypy.org
Mon Oct 26 04:57:56 EDT 2015
Author: Richard Plangger <planrichi at gmail.com>
Branch: s390x-backend
Changeset: r80458:b0d5eccd58d1
Date: 2015-10-26 09:56 +0100
http://bitbucket.org/pypy/pypy/changeset/b0d5eccd58d1/
Log: more skeleton structure
diff --git a/rpython/jit/backend/zarch/helper/__init__.py b/rpython/jit/backend/zarch/helper/__init__.py
new file mode 100644
diff --git a/rpython/jit/backend/zarch/helper/assembler.py b/rpython/jit/backend/zarch/helper/assembler.py
new file mode 100644
diff --git a/rpython/jit/backend/zarch/helper/regalloc.py b/rpython/jit/backend/zarch/helper/regalloc.py
new file mode 100644
diff --git a/rpython/jit/backend/zarch/regalloc.py b/rpython/jit/backend/zarch/regalloc.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/zarch/regalloc.py
@@ -0,0 +1,468 @@
+from rpython.jit.backend.llsupport.regalloc import (RegisterManager, FrameManager,
+ TempVar, compute_vars_longevity,
+ BaseRegalloc)
+from rpython.jit.backend.zarch.arch import WORD
+from rpython.jit.codewriter import longlong
+from rpython.jit.backend.zarch.locations import imm, get_fp_offset
+from rpython.jit.metainterp.history import (Const, ConstInt, ConstFloat, ConstPtr,
+ INT, REF, FLOAT, VOID)
+from rpython.jit.metainterp.history import JitCellToken, TargetToken
+from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.backend.zarch import locations
+from rpython.rtyper.lltypesystem import rffi, lltype, rstr, llmemory
+from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.annlowlevel import cast_instance_to_gcref
+from rpython.jit.backend.llsupport import symbolic
+from rpython.jit.backend.llsupport.descr import ArrayDescr
+import rpython.jit.backend.zarch.registers as r
+import rpython.jit.backend.zarch.conditions as c
+from rpython.jit.backend.llsupport.descr import unpack_arraydescr
+from rpython.jit.backend.llsupport.descr import unpack_fielddescr
+from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr
+from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.debug import debug_print
+from rpython.jit.codewriter.effectinfo import EffectInfo
+from rpython.rlib import rgc
+from rpython.rlib.rarithmetic import r_uint
+
+LIMIT_LOOP_BREAK = 15000 # should be much smaller than 32 KB
+
+
+class TempInt(TempVar):
+ type = INT
+
+ def __repr__(self):
+ return "<TempInt at %s>" % (id(self),)
+
+class TempPtr(TempVar):
+ type = REF
+
+ def __repr__(self):
+ return "<TempPtr at %s>" % (id(self),)
+
+class TempFloat(TempVar):
+ type = FLOAT
+
+ def __repr__(self):
+ return "<TempFloat at %s>" % (id(self),)
+
+
+class FPRegisterManager(RegisterManager):
+ all_regs = r.MANAGED_FP_REGS
+ box_types = [FLOAT]
+ save_around_call_regs = r.VOLATILES_FLOAT
+ assert set(save_around_call_regs).issubset(all_regs)
+
+ def convert_to_adr(self, c):
+ assert isinstance(c, ConstFloat)
+ adr = self.assembler.datablockwrapper.malloc_aligned(8, 8)
+ x = c.getfloatstorage()
+ rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), adr)[0] = x
+ return adr
+
+ def convert_to_imm(self, c):
+ adr = self.convert_to_adr(c)
+ return locations.ConstFloatLoc(adr)
+
+ def __init__(self, longevity, frame_manager=None, assembler=None):
+ RegisterManager.__init__(self, longevity, frame_manager, assembler)
+
+ def call_result_location(self, v):
+ return r.f1
+
+ def ensure_reg(self, box):
+ if isinstance(box, Const):
+ loc = self.get_scratch_reg()
+ immadrvalue = self.convert_to_adr(box)
+ mc = self.assembler.mc
+ mc.load_imm(r.SCRATCH, immadrvalue)
+ mc.lfdx(loc.value, 0, r.SCRATCH.value)
+ else:
+ assert box in self.temp_boxes
+ loc = self.make_sure_var_in_reg(box,
+ forbidden_vars=self.temp_boxes)
+ return loc
+
+ def get_scratch_reg(self):
+ box = TempFloat()
+ reg = self.force_allocate_reg(box, forbidden_vars=self.temp_boxes)
+ self.temp_boxes.append(box)
+ return reg
+
+
+class ZARCHRegisterManager(RegisterManager):
+ all_regs = r.MANAGED_REGS
+ box_types = None # or a list of acceptable types
+ no_lower_byte_regs = all_regs
+ save_around_call_regs = r.VOLATILES
+ frame_reg = r.SPP
+ assert set(save_around_call_regs).issubset(all_regs)
+
+ def __init__(self, longevity, frame_manager=None, assembler=None):
+ RegisterManager.__init__(self, longevity, frame_manager, assembler)
+
+ def call_result_location(self, v):
+ return r.r2
+
+ def convert_to_int(self, c):
+ if isinstance(c, ConstInt):
+ return rffi.cast(lltype.Signed, c.value)
+ else:
+ assert isinstance(c, ConstPtr)
+ return rffi.cast(lltype.Signed, c.value)
+
+ def convert_to_imm(self, c):
+ val = self.convert_to_int(c)
+ return locations.ImmLocation(val)
+
+ def ensure_reg(self, box):
+ if isinstance(box, Const):
+ loc = self.get_scratch_reg()
+ immvalue = self.convert_to_int(box)
+ self.assembler.mc.load_imm(loc, immvalue)
+ else:
+ assert box in self.temp_boxes
+ loc = self.make_sure_var_in_reg(box,
+ forbidden_vars=self.temp_boxes)
+ return loc
+
+ def get_scratch_reg(self):
+ box = TempVar()
+ reg = self.force_allocate_reg(box, forbidden_vars=self.temp_boxes)
+ self.temp_boxes.append(box)
+ return reg
+
+
+class ZARCHFrameManager(FrameManager):
+ def __init__(self, base_ofs):
+ FrameManager.__init__(self)
+ self.used = []
+ self.base_ofs = base_ofs
+
+ def frame_pos(self, loc, box_type):
+ #return locations.StackLocation(loc, get_fp_offset(self.base_ofs, loc), box_type)
+ return locations.StackLocation(loc, get_fp_offset(self.base_ofs, loc), box_type)
+
+ @staticmethod
+ def frame_size(type):
+ return 1
+
+ @staticmethod
+ def get_loc_index(loc):
+ assert isinstance(loc, locations.StackLocation)
+ return loc.position
+
+
+class Regalloc(BaseRegalloc):
+
+ def __init__(self, assembler=None):
+ self.cpu = assembler.cpu
+ self.assembler = assembler
+ self.jump_target_descr = None
+ self.final_jump_op = None
+
+ def _prepare(self, inputargs, operations, allgcrefs):
+ cpu = self.assembler.cpu
+ self.fm = ZARCHFrameManager(cpu.get_baseofs_of_frame_field())
+ operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations,
+ allgcrefs)
+ # compute longevity of variables
+ longevity, last_real_usage = compute_vars_longevity(
+ inputargs, operations)
+ self.longevity = longevity
+ self.last_real_usage = last_real_usage
+ self.rm = ZARCHRegisterManager(self.longevity,
+ frame_manager = self.fm,
+ assembler = self.assembler)
+ self.fprm = FPRegisterManager(self.longevity, frame_manager = self.fm,
+ assembler = self.assembler)
+ return operations
+
+ def prepare_loop(self, inputargs, operations, looptoken, allgcrefs):
+ operations = self._prepare(inputargs, operations, allgcrefs)
+ self._set_initial_bindings(inputargs, looptoken)
+ # note: we need to make a copy of inputargs because possibly_free_vars
+ # is also used on op args, which is a non-resizable list
+ self.possibly_free_vars(list(inputargs))
+ self.min_bytes_before_label = 4 # for redirect_call_assembler()
+ return operations
+
+ def prepare_bridge(self, inputargs, arglocs, operations, allgcrefs,
+ frame_info):
+ operations = self._prepare(inputargs, operations, allgcrefs)
+ self._update_bindings(arglocs, inputargs)
+ self.min_bytes_before_label = 0
+ return operations
+
+ def ensure_next_label_is_at_least_at_position(self, at_least_position):
+ self.min_bytes_before_label = max(self.min_bytes_before_label,
+ at_least_position)
+
+ def _update_bindings(self, locs, inputargs):
+ # XXX this should probably go to llsupport/regalloc.py
+ used = {}
+ i = 0
+ for loc in locs:
+ if loc is None: # xxx bit kludgy
+ loc = r.SPP
+ arg = inputargs[i]
+ i += 1
+ if loc.is_reg():
+ if loc is r.SPP:
+ self.rm.bindings_to_frame_reg[arg] = None
+ else:
+ self.rm.reg_bindings[arg] = loc
+ used[loc] = None
+ elif loc.is_fp_reg():
+ self.fprm.reg_bindings[arg] = loc
+ used[loc] = None
+ else:
+ assert loc.is_stack()
+ self.fm.bind(arg, loc)
+ self.rm.free_regs = []
+ for reg in self.rm.all_regs:
+ if reg not in used:
+ self.rm.free_regs.append(reg)
+ self.fprm.free_regs = []
+ for reg in self.fprm.all_regs:
+ if reg not in used:
+ self.fprm.free_regs.append(reg)
+ self.possibly_free_vars(list(inputargs))
+ self.fm.finish_binding()
+ self.rm._check_invariants()
+ self.fprm._check_invariants()
+
+ def get_final_frame_depth(self):
+ return self.fm.get_frame_depth()
+
+ def possibly_free_var(self, var):
+ if var is not None:
+ if var.type == FLOAT:
+ self.fprm.possibly_free_var(var)
+ else:
+ self.rm.possibly_free_var(var)
+
+ def possibly_free_vars(self, vars):
+ for var in vars:
+ self.possibly_free_var(var)
+
+ def possibly_free_vars_for_op(self, op):
+ for i in range(op.numargs()):
+ var = op.getarg(i)
+ self.possibly_free_var(var)
+
+ def force_allocate_reg(self, var):
+ if var.type == FLOAT:
+ forbidden_vars = self.fprm.temp_boxes
+ return self.fprm.force_allocate_reg(var, forbidden_vars)
+ else:
+ forbidden_vars = self.rm.temp_boxes
+ return self.rm.force_allocate_reg(var, forbidden_vars)
+
+ def force_allocate_reg_or_cc(self, var):
+ assert var.type == INT
+ if self.next_op_can_accept_cc(self.operations, self.rm.position):
+ # hack: return the SPP location to mean "lives in CC". This
+ # SPP will not actually be used, and the location will be freed
+ # after the next op as usual.
+ self.rm.force_allocate_frame_reg(var)
+ return r.SPP
+ else:
+ # else, return a regular register (not SPP).
+ return self.force_allocate_reg(var)
+
+ def walk_operations(self, inputargs, operations):
+ from rpython.jit.backend.zarch.assembler import (
+ asm_operations)
+ i = 0
+ self.limit_loop_break = (self.assembler.mc.get_relative_pos() +
+ LIMIT_LOOP_BREAK)
+ self.operations = operations
+ while i < len(operations):
+ op = operations[i]
+ self.assembler.mc.mark_op(op)
+ self.rm.position = i
+ self.fprm.position = i
+ if op.has_no_side_effect() and op not in self.longevity:
+ i += 1
+ self.possibly_free_vars_for_op(op)
+ continue
+ #
+ for j in range(op.numargs()):
+ box = op.getarg(j)
+ if box.type != FLOAT:
+ self.rm.temp_boxes.append(box)
+ else:
+ self.fprm.temp_boxes.append(box)
+ #
+ opnum = op.getopnum()
+ if not we_are_translated() and opnum == -127:
+ self._consider_force_spill(op)
+ else:
+ arglocs = prepare_oplist[opnum](self, op)
+ asm_operations[opnum](self.assembler, op, arglocs, self)
+ self.free_op_vars()
+ self.possibly_free_var(op)
+ self.rm._check_invariants()
+ self.fprm._check_invariants()
+ if self.assembler.mc.get_relative_pos() > self.limit_loop_break:
+ self.assembler.break_long_loop()
+ self.limit_loop_break = (self.assembler.mc.get_relative_pos() +
+ LIMIT_LOOP_BREAK)
+ i += 1
+ assert not self.rm.reg_bindings
+ assert not self.fprm.reg_bindings
+ self.flush_loop()
+ self.assembler.mc.mark_op(None) # end of the loop
+ self.operations = None
+ for arg in inputargs:
+ self.possibly_free_var(arg)
+
+ def flush_loop(self):
+ # Emit a nop in the rare case where we have a guard_not_invalidated
+ # immediately before a label
+ mc = self.assembler.mc
+ while self.min_bytes_before_label > mc.get_relative_pos():
+ mc.nop()
+
+ def get_gcmap(self, forbidden_regs=[], noregs=False):
+ frame_depth = self.fm.get_frame_depth()
+ gcmap = allocate_gcmap(self.assembler, frame_depth,
+ r.JITFRAME_FIXED_SIZE)
+ for box, loc in self.rm.reg_bindings.iteritems():
+ if loc in forbidden_regs:
+ continue
+ if box.type == REF and self.rm.is_still_alive(box):
+ assert not noregs
+ assert loc.is_reg()
+ val = self.assembler.cpu.all_reg_indexes[loc.value]
+ gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8))
+ for box, loc in self.fm.bindings.iteritems():
+ if box.type == REF and self.rm.is_still_alive(box):
+ assert isinstance(loc, locations.StackLocation)
+ val = loc.get_position() + r.JITFRAME_FIXED_SIZE
+ gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8))
+ return gcmap
+
+ def loc(self, var):
+ if var.type == FLOAT:
+ return self.fprm.loc(var)
+ else:
+ return self.rm.loc(var)
+
+ def next_instruction(self):
+ self.rm.next_instruction()
+ self.fprm.next_instruction()
+
+ def force_spill_var(self, var):
+ if var.type == FLOAT:
+ self.fprm.force_spill_var(var)
+ else:
+ self.rm.force_spill_var(var)
+
+ def _consider_force_spill(self, op):
+ # This operation is used only for testing
+ self.force_spill_var(op.getarg(0))
+
+ def before_call(self, force_store=[], save_all_regs=False):
+ self.rm.before_call(force_store, save_all_regs)
+ self.fprm.before_call(force_store, save_all_regs)
+
+ def after_call(self, v):
+ if v.type == FLOAT:
+ return self.fprm.after_call(v)
+ else:
+ return self.rm.after_call(v)
+
+ def call_result_location(self, v):
+ if v.type == FLOAT:
+ return self.fprm.call_result_location(v)
+ else:
+ return self.rm.call_result_location(v)
+
+ def ensure_reg(self, box):
+ if box.type == FLOAT:
+ return self.fprm.ensure_reg(box)
+ else:
+ return self.rm.ensure_reg(box)
+
+ def ensure_reg_or_16bit_imm(self, box):
+ if box.type == FLOAT:
+ return self.fprm.ensure_reg(box)
+ else:
+ if check_imm_box(box):
+ return imm(box.getint())
+ return self.rm.ensure_reg(box)
+
+ def ensure_reg_or_any_imm(self, box):
+ if box.type == FLOAT:
+ return self.fprm.ensure_reg(box)
+ else:
+ if isinstance(box, Const):
+ return imm(box.getint())
+ return self.rm.ensure_reg(box)
+
+ def get_scratch_reg(self, type):
+ if type == FLOAT:
+ return self.fprm.get_scratch_reg()
+ else:
+ return self.rm.get_scratch_reg()
+
+ def free_op_vars(self):
+ # free the boxes in the 'temp_boxes' lists, which contain both
+ # temporary boxes and all the current operation's arguments
+ self.rm.free_temp_vars()
+ self.fprm.free_temp_vars()
+
+ def compute_hint_frame_locations(self, operations):
+ # optimization only: fill in the 'hint_frame_locations' dictionary
+ # of rm and xrm based on the JUMP at the end of the loop, by looking
+ # at where we would like the boxes to be after the jump.
+ op = operations[-1]
+ if op.getopnum() != rop.JUMP:
+ return
+ self.final_jump_op = op
+ descr = op.getdescr()
+ assert isinstance(descr, TargetToken)
+ if descr._ll_loop_code != 0:
+ # if the target LABEL was already compiled, i.e. if it belongs
+ # to some already-compiled piece of code
+ self._compute_hint_frame_locations_from_descr(descr)
+ #else:
+ # The loop ends in a JUMP going back to a LABEL in the same loop.
+ # We cannot fill 'hint_frame_locations' immediately, but we can
+ # wait until the corresponding prepare_op_label() to know where the
+ # we would like the boxes to be after the jump.
+
+ def _compute_hint_frame_locations_from_descr(self, descr):
+ arglocs = self.assembler.target_arglocs(descr)
+ jump_op = self.final_jump_op
+ assert len(arglocs) == jump_op.numargs()
+ for i in range(jump_op.numargs()):
+ box = jump_op.getarg(i)
+ if not isinstance(box, Const):
+ loc = arglocs[i]
+ if loc is not None and loc.is_stack():
+ self.fm.hint_frame_pos[box] = self.fm.get_loc_index(loc)
+
+ # ******************************************************
+ # * P R E P A R E O P E R A T I O N S *
+ # ******************************************************
+
+def notimplemented(self, op):
+ msg = '[S390X/regalloc] %s not implemented\n' % op.getopname()
+ if we_are_translated():
+ llop.debug_print(lltype.Void, msg)
+ raise NotImplementedError(msg)
+
+prepare_oplist = [notimplemented] * (rop._LAST + 1)
+
+for key, value in rop.__dict__.items():
+ key = key.lower()
+ if key.startswith('_'):
+ continue
+ methname = 'prepare_%s' % key
+ if hasattr(Regalloc, methname):
+ func = getattr(Regalloc, methname).im_func
+ prepare_oplist[value] = func
diff --git a/rpython/jit/backend/zarch/test/test_runner.py b/rpython/jit/backend/zarch/test/test_runner.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/zarch/test/test_runner.py
@@ -0,0 +1,25 @@
+from rpython.jit.backend.test.runner_test import LLtypeBackendTest
+from rpython.jit.backend.zarch.runner import CPU_S390_64
+from rpython.jit.tool.oparser import parse
+from rpython.jit.metainterp.history import (AbstractFailDescr,
+ AbstractDescr,
+ BasicFailDescr, BasicFinalDescr,
+ JitCellToken, TargetToken,
+ ConstInt, ConstPtr,
+ Const, ConstFloat)
+from rpython.jit.metainterp.resoperation import InputArgInt, InputArgFloat
+from rpython.rtyper.lltypesystem import lltype
+from rpython.jit.metainterp.resoperation import ResOperation, rop
+import py
+
+class FakeStats(object):
+ pass
+
+class TestPPC(LLtypeBackendTest):
+ # for the individual tests see
+ # ====> ../../test/runner_test.py
+
+ def get_cpu(self):
+ cpu = CPU_S390_64(rtyper=None, stats=FakeStats())
+ cpu.setup_once()
+ return cpu
More information about the pypy-commit
mailing list