Author: David Schneider <[email protected]>
Branch: arm-backed-float
Changeset: r44645:d3279ad17fe6
Date: 2011-06-01 17:46 +0200
http://bitbucket.org/pypy/pypy/changeset/d3279ad17fe6/
Log: (arigo, bivab) add a resoperation for testing called force_spill,
that forces a variable to be spilled. It is used to the generate
different call patterns with variables that are currently spilled as
arguments
diff --git a/pypy/jit/backend/llsupport/regalloc.py
b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -226,6 +226,18 @@
else:
raise ValueError
+ def force_spill_var(self, var):
+ self._sync_var(var)
+ try:
+ loc = self.reg_bindings[var]
+ del self.reg_bindings[var]
+ self.free_regs.append(loc)
+ except KeyError:
+ if not we_are_translated():
+ import pdb; pdb.set_trace()
+ else:
+ raise ValueError
+
def loc(self, box):
""" Return the location of 'box'.
"""
diff --git a/pypy/jit/backend/test/calling_convention_test.py
b/pypy/jit/backend/test/calling_convention_test.py
--- a/pypy/jit/backend/test/calling_convention_test.py
+++ b/pypy/jit/backend/test/calling_convention_test.py
@@ -1,4 +1,3 @@
-import py, sys, random, os, struct, operator, itertools
from pypy.jit.metainterp.history import (AbstractFailDescr,
AbstractDescr,
BasicFailDescr,
@@ -24,6 +23,7 @@
def constfloat(x):
return ConstFloat(longlong.getfloatstorage(x))
+
class FakeStats(object):
pass
class TestCallingConv(Runner):
@@ -35,11 +35,127 @@
self.cpu = getcpuclass()(rtyper=None, stats=FakeStats())
self.cpu.setup_once()
+ def _prepare_args(self, args, floats, ints):
+ local_floats = list(floats)
+ local_ints = list(ints)
+ expected_result = 0.0
+ for i in range(len(args)):
+ x = args[i]
+ if x[0] == 'f':
+ x = local_floats.pop()
+ t = longlong.getfloatstorage(x)
+ self.cpu.set_future_value_float(i, t)
+ else:
+ x = local_ints.pop()
+ self.cpu.set_future_value_int(i, x)
+ expected_result += x
+ return expected_result
+
@classmethod
def get_funcbox(cls, cpu, func_ptr):
addr = llmemory.cast_ptr_to_adr(func_ptr)
return ConstInt(heaptracker.adr2int(addr))
+ def test_call_aligned_with_spilled_values(self):
+ from pypy.rlib.libffi import types
+ cpu = self.cpu
+ if not cpu.supports_floats:
+ py.test.skip('requires floats')
+
+
+ def func(*args):
+ return float(sum(args))
+
+ F = lltype.Float
+ I = lltype.Signed
+ floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
+ ints = [7, 11, 23, 13, -42, 1111, 95, 1]
+ for case in range(256):
+ local_floats = list(floats)
+ local_ints = list(ints)
+ args = []
+ spills = []
+ funcargs = []
+ float_count = 0
+ int_count = 0
+ for i in range(8):
+ if case & (1<<i):
+ args.append('f%d' % float_count)
+ spills.append('force_spill(f%d)' % float_count)
+ float_count += 1
+ funcargs.append(F)
+ else:
+ args.append('i%d' % int_count)
+ spills.append('force_spill(i%d)' % int_count)
+ int_count += 1
+ funcargs.append(I)
+
+ arguments = ', '.join(args)
+ spill_ops = '\n'.join(spills)
+
+ FUNC = self.FuncType(funcargs, F)
+ FPTR = self.Ptr(FUNC)
+ func_ptr = llhelper(FPTR, func)
+ calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+ funcbox = self.get_funcbox(cpu, func_ptr)
+
+ ops = '[%s]\n' % arguments
+ ops += '%s\n' % spill_ops
+ ops += 'f99 = call(ConstClass(func_ptr), %s,
descr=calldescr)\n' % arguments
+ ops += 'finish(f99, %s)\n' % arguments
+
+ loop = parse(ops, namespace=locals())
+ looptoken = LoopToken()
+ done_number =
self.cpu.get_fail_descr_number(loop.operations[-1].getdescr())
+ self.cpu.compile_loop(loop.inputargs, loop.operations,
looptoken)
+ expected_result = self._prepare_args(args, floats, ints)
+
+ res = self.cpu.execute_token(looptoken)
+ x = longlong.getrealfloat(cpu.get_latest_value_float(0))
+ assert abs(x - expected_result) < 0.0001
+
+ def test_call_aligned_with_imm_values(self):
+ from pypy.rlib.libffi import types
+ cpu = self.cpu
+ if not cpu.supports_floats:
+ py.test.skip('requires floats')
+
+
+ def func(*args):
+ return float(sum(args))
+
+ F = lltype.Float
+ I = lltype.Signed
+ floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
+ ints = [7, 11, 23, 13, -42, 1111, 95, 1]
+ for case in range(256):
+ result = 0.0
+ args = []
+ argslist = []
+ local_floats = list(floats)
+ local_ints = list(ints)
+ for i in range(8):
+ if case & (1<<i):
+ args.append(F)
+ arg = local_floats.pop()
+ result += arg
+ argslist.append(constfloat(arg))
+ else:
+ args.append(I)
+ arg = local_ints.pop()
+ result += arg
+ argslist.append(ConstInt(arg))
+ FUNC = self.FuncType(args, F)
+ FPTR = self.Ptr(FUNC)
+ func_ptr = llhelper(FPTR, func)
+ calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+ funcbox = self.get_funcbox(cpu, func_ptr)
+
+ res = self.execute_operation(rop.CALL,
+ [funcbox] + argslist,
+ 'float', descr=calldescr)
+ assert abs(res.getfloat() - result) < 0.0001
+
def test_call_aligned_with_args_on_the_stack(self):
from pypy.rlib.libffi import types
cpu = self.cpu
@@ -48,79 +164,46 @@
def func(*args):
- return sum(args)
+ return float(sum(args))
F = lltype.Float
I = lltype.Signed
- base_args = [F, F]
- floats = [0.7, 5.8, 0.1, 0.3, 0.9]
- ints = [7, 11, 23]
- result = sum(floats + ints)
- for p in itertools.permutations([I, I, I, F, F, F]):
- args = base_args + list(p)
+ floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
+ ints = [7, 11, 23, 13, -42, 1111, 95, 1]
+ for case in range(256):
+ result = 0.0
+ args = []
+ argslist = []
local_floats = list(floats)
local_ints = list(ints)
+ for i in range(8):
+ if case & (1<<i):
+ args.append(F)
+ arg = local_floats.pop()
+ result += arg
+ argslist.append(boxfloat(arg))
+ else:
+ args.append(I)
+ arg = local_ints.pop()
+ result += arg
+ argslist.append(BoxInt(arg))
FUNC = self.FuncType(args, F)
FPTR = self.Ptr(FUNC)
func_ptr = llhelper(FPTR, func)
calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
funcbox = self.get_funcbox(cpu, func_ptr)
- argslist = []
- for x in args:
- if x is F:
- argslist.append(boxfloat(local_floats.pop()))
- else:
- argslist.append(BoxInt(local_ints.pop()))
res = self.execute_operation(rop.CALL,
[funcbox] + argslist,
'float', descr=calldescr)
assert abs(res.getfloat() - result) < 0.0001
- def test_call_alignment_register_args(self):
- from pypy.rlib.libffi import types
- cpu = self.cpu
- if not cpu.supports_floats:
- py.test.skip('requires floats')
-
-
- def func(*args):
- return sum(args)
-
- F = lltype.Float
- I = lltype.Signed
- floats = [0.7, 5.8]
- ints = [7, 11]
- result = sum(floats + ints)
- for args in itertools.permutations([I, I, F, F]):
- local_floats = list(floats)
- local_ints = list(ints)
- FUNC = self.FuncType(args, F)
- FPTR = self.Ptr(FUNC)
- func_ptr = llhelper(FPTR, func)
- calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
- funcbox = self.get_funcbox(cpu, func_ptr)
- argslist = []
- for x in args:
- if x is F:
- argslist.append(boxfloat(local_floats.pop()))
- else:
- argslist.append(BoxInt(local_ints.pop()))
-
- res = self.execute_operation(rop.CALL,
- [funcbox] + argslist,
- 'float', descr=calldescr)
- assert abs(res.getfloat() - result) < 0.0001
-
-
def test_call_alignment_call_assembler(self):
from pypy.rlib.libffi import types
cpu = self.cpu
if not cpu.supports_floats:
py.test.skip('requires floats')
- fdescr1 = BasicFailDescr(1)
- fdescr2 = BasicFailDescr(2)
fdescr3 = BasicFailDescr(3)
fdescr4 = BasicFailDescr(4)
@@ -136,35 +219,34 @@
assembler_helper_adr = llmemory.cast_ptr_to_adr(
_assembler_helper_ptr)
- arglist = ['f0', 'f1', 'f2', 'i0', 'f3']
- floats = [0.7, 5.8, 0.1, 0.3]
- ints = [7, 11, 23, 42]
- def _prepare_args(args):
- local_floats = list(floats)
- local_ints = list(ints)
- for i in range(len(args)):
- x = args[i]
- if x[0] == 'f':
- t = longlong.getfloatstorage(local_floats.pop())
- cpu.set_future_value_float(i, t)
+ floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
+ ints = [7, 11, 23, 42, -42, 1111, 95, 1]
+
+ for case in range(256):
+ float_count = 0
+ int_count = 0
+ args = []
+ called_ops = ''
+ total_index = -1
+ for i in range(8):
+ if case & (1<<i):
+ args.append('f%d' % float_count)
else:
- cpu.set_future_value_int(i, (local_ints.pop()))
-
- for args in itertools.permutations(arglist):
- args += ('i1', 'i2', 'i3')
+ args.append('i%d' % int_count)
+ called_ops += 'f%d = cast_int_to_float(i%d)\n' % (
+ float_count, int_count)
+ int_count += 1
+ if total_index == -1:
+ total_index = float_count
+ float_count += 1
+ else:
+ called_ops += 'f%d = float_add(f%d, f%d)\n' % (
+ float_count + 1, total_index, float_count)
+ total_index = float_count + 1
+ float_count += 2
arguments = ', '.join(args)
- called_ops = '''
- [%s]
- i4 = int_add(i0, i1)
- i5 = int_add(i4, i2)
- i6 = int_add(i5, i3)
- guard_value(i6, 83, descr=fdescr1) [i4, i5, i6]
- f4 = float_add(f0, f1)
- f5 = float_add(f4, f2)
- f6 = float_add(f5, f3)
- i7 = float_lt(f6, 6.99)
- guard_true(i7, descr=fdescr2) [f4, f5, f6]
- finish(i6, f6, descr=fdescr3)''' % arguments
+ called_ops = '[%s]\n' % arguments + called_ops
+ called_ops += 'finish(f%d, descr=fdescr3)\n' % total_index
# compile called loop
called_loop = parse(called_ops, namespace=locals())
called_looptoken = LoopToken()
@@ -172,15 +254,14 @@
done_number =
self.cpu.get_fail_descr_number(called_loop.operations[-1].getdescr())
self.cpu.compile_loop(called_loop.inputargs,
called_loop.operations, called_looptoken)
- _prepare_args(args)
+ expected_result = self._prepare_args(args, floats, ints)
res = cpu.execute_token(called_looptoken)
assert res.identifier == 3
- assert cpu.get_latest_value_int(0) == 83
- t = longlong.getrealfloat(cpu.get_latest_value_float(1))
- assert abs(t - 6.9) < 0.0001
+ t = longlong.getrealfloat(cpu.get_latest_value_float(0))
+ assert abs(t - expected_result) < 0.0001
ARGS = []
- RES = lltype.Signed
+ RES = lltype.Float
for x in args:
if x[0] == 'f':
ARGS.append(lltype.Float)
@@ -190,22 +271,23 @@
lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES)
ops = '''
[%s]
- i10 = call_assembler(%s, descr=called_looptoken)
+ f99 = call_assembler(%s, descr=called_looptoken)
guard_not_forced()[]
- finish(i10, descr=fdescr4)
+ finish(f99, descr=fdescr4)
''' % (arguments, arguments)
loop = parse(ops, namespace=locals())
# we want to take the fast path
- self.cpu.done_with_this_frame_int_v = done_number
+ self.cpu.done_with_this_frame_float_v = done_number
try:
othertoken = LoopToken()
self.cpu.compile_loop(loop.inputargs, loop.operations,
othertoken)
# prepare call to called_loop
- _prepare_args(args)
+ self._prepare_args(args, floats, ints)
res = cpu.execute_token(othertoken)
- x = cpu.get_latest_value_int(0)
+ x = longlong.getrealfloat(cpu.get_latest_value_float(0))
assert res.identifier == 4
- assert x == 83
+ assert abs(x - expected_result) < 0.0001
finally:
- del self.cpu.done_with_this_frame_int_v
+ del self.cpu.done_with_this_frame_float_v
+
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -266,6 +266,12 @@
return self.rm.force_allocate_reg(var, forbidden_vars,
selected_reg, need_lower_byte)
+ def force_spill_var(self, var):
+ if var.type == FLOAT:
+ return self.xrm.force_spill_var(var)
+ else:
+ return self.rm.force_spill_var(var)
+
def load_xmm_aligned_16_bytes(self, var, forbidden_vars=[]):
# Load 'var' in a register; but if it is a constant, we can return
# a 16-bytes-aligned ConstFloatLoc.
@@ -400,6 +406,8 @@
if self.can_merge_with_next_guard(op, i, operations):
oplist_with_guard[op.getopnum()](self, op, operations[i + 1])
i += 1
+ elif not we_are_translated() and op.getopnum() == -124:
+ self._consider_force_spill(op)
else:
oplist[op.getopnum()](self, op)
if op.result is not None:
@@ -1228,6 +1236,10 @@
def consider_jit_debug(self, op):
pass
+ def _consider_force_spill(self, op):
+ # This operation is used only for testing
+ self.force_spill_var(op.getarg(0))
+
def get_mark_gc_roots(self, gcrootmap, use_copy_area=False):
shape = gcrootmap.get_basic_shape(IS_X86_64)
for v, val in self.fm.frame_bindings.items():
diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py
--- a/pypy/jit/tool/oparser.py
+++ b/pypy/jit/tool/oparser.py
@@ -6,7 +6,9 @@
from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\
ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\
LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode
-from pypy.jit.metainterp.resoperation import rop, ResOperation,
ResOpWithDescr, N_aryOp
+from pypy.jit.metainterp.resoperation import rop, ResOperation, \
+ ResOpWithDescr, N_aryOp, \
+ UnaryOp, PlainResOp
from pypy.jit.metainterp.typesystem import llhelper
from pypy.jit.codewriter.heaptracker import adr2int
from pypy.jit.codewriter import longlong
@@ -35,6 +37,23 @@
def clone(self):
return ESCAPE_OP(self.OPNUM, self.getarglist()[:], self.result,
self.getdescr())
+class FORCE_SPILL(UnaryOp, PlainResOp):
+
+ OPNUM = -124
+
+ def __init__(self, opnum, args, result=None, descr=None):
+ assert result is None
+ assert descr is None
+ assert opnum == self.OPNUM
+ self.result = result
+ self.initarglist(args)
+
+ def getopnum(self):
+ return self.OPNUM
+
+ def clone(self):
+ return FORCE_SPILL(self.OPNUM, self.getarglist()[:])
+
class ExtendedTreeLoop(TreeLoop):
def getboxes(self):
@@ -220,6 +239,8 @@
except AttributeError:
if opname == 'escape':
opnum = ESCAPE_OP.OPNUM
+ elif opname == 'force_spill':
+ opnum = FORCE_SPILL.OPNUM
else:
raise ParseError("unknown op: %s" % opname)
endnum = line.rfind(')')
@@ -261,6 +282,8 @@
def create_op(self, opnum, args, result, descr):
if opnum == ESCAPE_OP.OPNUM:
return ESCAPE_OP(opnum, args, result, descr)
+ if opnum == FORCE_SPILL.OPNUM:
+ return FORCE_SPILL(opnum, args, result, descr)
else:
return ResOperation(opnum, args, result, descr)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit