Author: Armin Rigo <[email protected]>
Branch: conditional_call_value_2
Changeset: r86996:87c41fa2e0f5
Date: 2016-09-11 12:23 +0200
http://bitbucket.org/pypy/pypy/changeset/87c41fa2e0f5/
Log: Add support for COND_CALL_X in the x86 backend
diff --git a/rpython/jit/backend/llsupport/regalloc.py
b/rpython/jit/backend/llsupport/regalloc.py
--- a/rpython/jit/backend/llsupport/regalloc.py
+++ b/rpython/jit/backend/llsupport/regalloc.py
@@ -757,17 +757,17 @@
next_op = operations[i + 1]
opnum = next_op.getopnum()
if (opnum != rop.GUARD_TRUE and opnum != rop.GUARD_FALSE
- and opnum != rop.COND_CALL):
+ and opnum != rop.COND_CALL_N):
return False
if next_op.getarg(0) is not op:
return False
if self.longevity[op][1] > i + 1:
return False
- if opnum != rop.COND_CALL:
+ if opnum != rop.COND_CALL_N:
if op in operations[i + 1].getfailargs():
return False
else:
- if op in operations[i + 1].getarglist()[1:]:
+ if op in operations[i + 1].getarglist()[3:]:
return False
return True
diff --git a/rpython/jit/backend/llsupport/rewrite.py
b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -392,7 +392,7 @@
opnum = next_op.getopnum()
if not (opnum == rop.GUARD_TRUE or
opnum == rop.GUARD_FALSE or
- opnum == rop.COND_CALL):
+ opnum == rop.COND_CALL_N):
return False
if next_op.getarg(0) is not op:
return False
diff --git a/rpython/jit/backend/test/runner_test.py
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -2215,51 +2215,6 @@
excvalue = self.cpu.grab_exc_value(deadframe)
assert not excvalue
- def test_cond_call_value(self):
- def func_int(*args):
- called.append(args)
- return len(args) * 100 + 1000
-
- for i in range(5):
- called = []
-
- FUNC = self.FuncType([lltype.Signed] * i, lltype.Signed)
- func_ptr = llhelper(lltype.Ptr(FUNC), func_int)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
-
- ops = '''
- [i0, i1, i2, i3, i4, i5, i6, f0, f1]
- i15 = cond_call_i(i1, 20, ConstClass(func_ptr), %s)
- guard_false(i0, descr=faildescr) [i1,i2,i3,i4,i5,i6,i15, f0,f1]
- finish(i15)
- ''' % ', '.join(['i%d' % (j + 2) for j in range(i)] +
- ["descr=calldescr"])
- loop = parse(ops, namespace={'faildescr': BasicFailDescr(),
- 'func_ptr': func_ptr,
- 'calldescr': calldescr})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- f1 = longlong.getfloatstorage(1.2)
- f2 = longlong.getfloatstorage(3.4)
- frame = self.cpu.execute_token(looptoken, 1, 50, 1, 2, 3, 4, 5,
- f1, f2)
- assert not called
- assert [self.cpu.get_int_value(frame, j) for j in range(7)] == [
- 50, 1, 2, 3, 4, 5, 50]
- assert longlong.getrealfloat(
- self.cpu.get_float_value(frame, 7)) == 1.2
- assert longlong.getrealfloat(
- self.cpu.get_float_value(frame, 8)) == 3.4
- #
- frame = self.cpu.execute_token(looptoken, 1, 20, 1, 2, 3, 4, 5,
- f1, f2)
- assert called == [(1, 2, 3, 4)[:i]]
- assert [self.cpu.get_int_value(frame, j) for j in range(7)] == [
- 20, 1, 2, 3, 4, 5, i * 100 + 1000]
- assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7))
== 1.2
- assert longlong.getrealfloat(self.cpu.get_float_value(frame, 8))
== 3.4
-
def test_cond_call_gc_wb(self):
def func_void(a):
record.append(rffi.cast(lltype.Signed, a))
@@ -2422,7 +2377,7 @@
ops = '''
[i0, i1, i2, i3, i4, i5, i6, f0, f1]
- cond_call(i1, ConstClass(func_ptr), %s)
+ cond_call_n(i1, 1, ConstClass(func_ptr), %s)
guard_false(i0, descr=faildescr) [i1, i2, i3, i4, i5, i6, f0, f1]
''' % ', '.join(['i%d' % (j + 2) for j in range(i)] +
["descr=calldescr"])
loop = parse(ops, namespace={'faildescr': BasicFailDescr(),
@@ -2434,7 +2389,7 @@
f2 = longlong.getfloatstorage(3.4)
frame = self.cpu.execute_token(looptoken, 1, 0, 1, 2, 3, 4, 5, f1,
f2)
assert not called
- for j in range(5):
+ for j in range(6):
assert self.cpu.get_int_value(frame, j) == j
assert longlong.getrealfloat(self.cpu.get_float_value(frame, 6))
== 1.2
assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7))
== 3.4
@@ -2472,7 +2427,7 @@
ops = '''
[%s, %s, i3, i4]
i2 = %s(%s)
- cond_call(i2, ConstClass(func_ptr), i3, i4, descr=calldescr)
+ cond_call_n(i2, 1, ConstClass(func_ptr), i3, i4, descr=calldescr)
guard_no_exception(descr=faildescr) []
finish()
''' % ("i0" if operation.startswith('int') else "f0",
@@ -2492,6 +2447,51 @@
67, 89)
assert called == [(67, 89)]
+ def test_cond_call_value(self):
+ def func_int(*args):
+ called.append(args)
+ return len(args) * 100 + 1000
+
+ for i in range(5):
+ called = []
+
+ FUNC = self.FuncType([lltype.Signed] * i, lltype.Signed)
+ func_ptr = llhelper(lltype.Ptr(FUNC), func_int)
+ calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+ EffectInfo.MOST_GENERAL)
+
+ ops = '''
+ [i0, i1, i2, i3, i4, i5, i6, f0, f1]
+ i15 = cond_call_i(i1, 20, ConstClass(func_ptr), %s)
+ guard_false(i0, descr=faildescr) [i1,i2,i3,i4,i5,i6,i15, f0,f1]
+ finish(i15)
+ ''' % ', '.join(['i%d' % (j + 2) for j in range(i)] +
+ ["descr=calldescr"])
+ loop = parse(ops, namespace={'faildescr': BasicFailDescr(),
+ 'func_ptr': func_ptr,
+ 'calldescr': calldescr})
+ looptoken = JitCellToken()
+ self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+ f1 = longlong.getfloatstorage(1.2)
+ f2 = longlong.getfloatstorage(3.4)
+ frame = self.cpu.execute_token(looptoken, 1, 50, 1, 2, 3, 4, 5,
+ f1, f2)
+ assert not called
+ assert [self.cpu.get_int_value(frame, j) for j in range(7)] == [
+ 50, 1, 2, 3, 4, 5, 50]
+ assert longlong.getrealfloat(
+ self.cpu.get_float_value(frame, 7)) == 1.2
+ assert longlong.getrealfloat(
+ self.cpu.get_float_value(frame, 8)) == 3.4
+ #
+ frame = self.cpu.execute_token(looptoken, 1, 20, 1, 2, 3, 4, 5,
+ f1, f2)
+ assert called == [(1, 2, 3, 4)[:i]]
+ assert [self.cpu.get_int_value(frame, j) for j in range(7)] == [
+ 20, 1, 2, 3, 4, 5, i * 100 + 1000]
+ assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7))
== 1.2
+ assert longlong.getrealfloat(self.cpu.get_float_value(frame, 8))
== 3.4
+
def test_force_operations_returning_void(self):
values = []
def maybe_force(token, flag):
diff --git a/rpython/jit/backend/x86/assembler.py
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -174,8 +174,8 @@
# copy registers to the frame, with the exception of the
# 'cond_call_register_arguments' and eax, because these have already
# been saved by the caller. Note that this is not symmetrical:
- # these 5 registers are saved by the caller but restored here at
- # the end of this function.
+ # these 5 registers are saved by the caller but 4 of them are
+ # restored here at the end of this function.
self._push_all_regs_to_frame(mc, cond_call_register_arguments + [eax],
supports_floats, callee_only)
# the caller already did push_gcmap(store=True)
@@ -198,7 +198,7 @@
mc.ADD(esp, imm(WORD * 7))
self.set_extra_stack_depth(mc, 0)
self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller
- self._pop_all_regs_from_frame(mc, [], supports_floats, callee_only)
+ self._pop_all_regs_from_frame(mc, [eax], supports_floats, callee_only)
mc.RET()
return mc.materialize(self.cpu, [])
@@ -1703,7 +1703,8 @@
self.implement_guard(guard_token)
# If the previous operation was a COND_CALL, overwrite its conditional
# jump to jump over this GUARD_NO_EXCEPTION as well, if we can
- if self._find_nearby_operation(-1).getopnum() == rop.COND_CALL:
+ if self._find_nearby_operation(-1).getopnum() in (
+ rop.COND_CALL_N, rop.COND_CALL_I, rop.COND_CALL_R):
jmp_adr = self.previous_cond_call_jcond
offset = self.mc.get_relative_pos() - jmp_adr
if offset <= 127:
@@ -2381,7 +2382,7 @@
def label(self):
self._check_frame_depth_debug(self.mc)
- def cond_call(self, op, gcmap, imm_func, arglocs):
+ def cond_call(self, op, gcmap, imm_func, arglocs, resloc=None):
assert self.guard_success_cc >= 0
self.mc.J_il8(rx86.invert_condition(self.guard_success_cc), 0)
# patched later
@@ -2394,11 +2395,14 @@
# plus the register 'eax'
base_ofs = self.cpu.get_baseofs_of_frame_field()
should_be_saved = self._regalloc.rm.reg_bindings.values()
+ pop_eax = False
for gpr in cond_call_register_arguments + [eax]:
- if gpr not in should_be_saved:
+ if gpr not in should_be_saved or gpr is resloc:
continue
v = gpr_reg_mgr_cls.all_reg_indexes[gpr.value]
self.mc.MOV_br(v * WORD + base_ofs, gpr.value)
+ if gpr is eax:
+ pop_eax = True
#
# load the 0-to-4 arguments into these registers
from rpython.jit.backend.x86.jump import remap_frame_layout
@@ -2422,8 +2426,15 @@
floats = True
cond_call_adr = self.cond_call_slowpath[floats * 2 + callee_only]
self.mc.CALL(imm(follow_jump(cond_call_adr)))
+ # if this is not a COND_CALL_N, we need to move the result in place
+ if resloc is not None and resloc is not eax:
+ self.mc.MOV(resloc, eax)
# restoring the registers saved above, and doing pop_gcmap(), is left
- # to the cond_call_slowpath helper. We never have any result value.
+ # to the cond_call_slowpath helper. We must only pop eax, if needed.
+ if pop_eax:
+ v = gpr_reg_mgr_cls.all_reg_indexes[eax.value]
+ self.mc.MOV_rb(eax.value, v * WORD + base_ofs)
+ #
offset = self.mc.get_relative_pos() - jmp_adr
assert 0 < offset <= 127
self.mc.overwrite(jmp_adr-1, chr(offset))
diff --git a/rpython/jit/backend/x86/regalloc.py
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -928,7 +928,7 @@
consider_cond_call_gc_wb_array = consider_cond_call_gc_wb
- def XXXconsider_cond_call(self, op):
+ def consider_cond_call_n(self, op):
# A 32-bit-only, asmgcc-only issue: 'cond_call_register_arguments'
# contains edi and esi, which are also in asmgcroot.py:ASM_FRAMEDATA.
# We must make sure that edi and esi do not contain GC pointers.
@@ -938,16 +938,27 @@
self.rm.force_spill_var(box)
assert box not in self.rm.reg_bindings
#
- assert op.type == 'v'
+ #assert op.type == 'v'
args = op.getarglist()
- assert 2 <= len(args) <= 4 + 2 # maximum 4 arguments
- v = args[1]
- assert isinstance(v, Const)
- imm_func = self.rm.convert_to_imm(v)
- arglocs = [self.loc(args[i]) for i in range(2, len(args))]
+ assert 3 <= len(args) <= 4 + 3 # maximum 4 arguments
+ v_func = args[2]
+ assert isinstance(v_func, Const)
+ imm_func = self.rm.convert_to_imm(v_func)
+ arglocs = [self.loc(args[i]) for i in range(3, len(args))]
gcmap = self.get_gcmap()
- self.load_condition_into_cc(op.getarg(0))
- self.assembler.cond_call(op, gcmap, imm_func, arglocs)
+ if op.type == 'v': # COND_CALL_N
+ self.load_condition_into_cc(op.getarg(0))
+ resloc = None
+ else:
+ condvalue_loc = self.loc(args[0])
+ assert not isinstance(condvalue_loc, ImmedLoc)
+ self.assembler.mc.CMP(condvalue_loc, self.loc(args[1]))
+ self.assembler.guard_success_cc = rx86.Conditions['E']
+ resloc = self.rm.force_result_in_reg(op, args[0])
+ self.assembler.cond_call(op, gcmap, imm_func, arglocs, resloc)
+
+ consider_cond_call_i = consider_cond_call_n
+ consider_cond_call_r = consider_cond_call_n
def consider_call_malloc_nursery(self, op):
size_box = op.getarg(0)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit