/rpython/jit/codewriter/test/test_jtransform.py
Python | 1410 lines | 1280 code | 95 blank | 35 comment | 71 complexity | 63551adc0e725aac181ad79b91ddf275 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
- import py
- import random
- from itertools import product
- from rpython.flowspace.model import FunctionGraph, Block, Link, c_last_exception
- from rpython.flowspace.model import SpaceOperation, Variable, Constant
- from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi
- from rpython.rtyper import rclass
- from rpython.rtyper.lltypesystem.module import ll_math
- from rpython.translator.unsimplify import varoftype
- from rpython.jit.codewriter import heaptracker, effectinfo
- from rpython.jit.codewriter.flatten import ListOfKind
- from rpython.jit.codewriter.jtransform import Transformer, UnsupportedMallocFlags
- from rpython.jit.metainterp.history import getkind
- def const(x):
- return Constant(x, lltype.typeOf(x))
- class FakeRTyper:
- instance_reprs = {}
- class FakeCPU:
- class tracker:
- pass
- rtyper = FakeRTyper()
- def calldescrof(self, FUNC, ARGS, RESULT):
- return ('calldescr', FUNC, ARGS, RESULT)
- def fielddescrof(self, STRUCT, name):
- return ('fielddescr', STRUCT, name)
- def interiorfielddescrof(self, ARRAY, name):
- return ('interiorfielddescr', ARRAY, name)
- def arraydescrof(self, ARRAY):
- return FakeDescr(('arraydescr', ARRAY))
- def sizeof(self, STRUCT, vtable=None):
- return FakeDescr(('sizedescr', STRUCT))
- class FakeDescr(tuple):
- pass
- class FakeLink:
- args = []
- def __init__(self, exitcase):
- self.exitcase = self.llexitcase = exitcase
- class FakeResidualCallControl:
- def guess_call_kind(self, op):
- return 'residual'
- def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
- extradescr=None):
- return 'calldescr'
- def calldescr_canraise(self, calldescr):
- return True
- class FakeRegularCallControl:
- def guess_call_kind(self, op):
- return 'regular'
- def graphs_from(self, op):
- return ['somegraph']
- def get_jitcode(self, graph, called_from=None):
- assert graph == 'somegraph'
- return 'somejitcode'
- class FakeResidualIndirectCallControl:
- def guess_call_kind(self, op):
- return 'residual'
- def getcalldescr(self, op, **kwds):
- return 'calldescr'
- def calldescr_canraise(self, calldescr):
- return True
- class FakeRegularIndirectCallControl:
- def guess_call_kind(self, op):
- return 'regular'
- def graphs_from(self, op):
- return ['somegraph1', 'somegraph2']
- def getcalldescr(self, op, **kwds):
- return 'calldescr'
- def get_jitcode(self, graph, called_from=None):
- assert graph in ('somegraph1', 'somegraph2')
- return 'somejitcode' + graph[-1]
- def calldescr_canraise(self, calldescr):
- return False
- class FakeCallInfoCollection:
- def __init__(self):
- self.seen = []
- def add(self, oopspecindex, calldescr, func):
- self.seen.append((oopspecindex, calldescr, func))
- def has_oopspec(self, oopspecindex):
- for i, c, f in self.seen:
- if i == oopspecindex:
- return True
- return False
- def callinfo_for_oopspec(self, oopspecindex):
- assert oopspecindex == effectinfo.EffectInfo.OS_STREQ_NONNULL
- class c:
- class adr:
- ptr = 1
- return ('calldescr', c)
- class FakeBuiltinCallControl:
- def __init__(self):
- self.callinfocollection = FakeCallInfoCollection()
- def guess_call_kind(self, op):
- return 'builtin'
- def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
- extradescr=None):
- assert oopspecindex is not None # in this test
- EI = effectinfo.EffectInfo
- if oopspecindex != EI.OS_ARRAYCOPY:
- PSTR = lltype.Ptr(rstr.STR)
- PUNICODE = lltype.Ptr(rstr.UNICODE)
- INT = lltype.Signed
- UNICHAR = lltype.UniChar
- FLOAT = lltype.Float
- ARRAYPTR = rffi.CArrayPtr(lltype.Char)
- argtypes = {
- EI.OS_MATH_SQRT: ([FLOAT], FLOAT),
- EI.OS_STR2UNICODE:([PSTR], PUNICODE),
- EI.OS_STR_CONCAT: ([PSTR, PSTR], PSTR),
- EI.OS_STR_SLICE: ([PSTR, INT, INT], PSTR),
- EI.OS_STREQ_NONNULL: ([PSTR, PSTR], INT),
- EI.OS_UNI_CONCAT: ([PUNICODE, PUNICODE], PUNICODE),
- EI.OS_UNI_SLICE: ([PUNICODE, INT, INT], PUNICODE),
- EI.OS_UNI_EQUAL: ([PUNICODE, PUNICODE], lltype.Bool),
- EI.OS_UNIEQ_SLICE_CHECKNULL:([PUNICODE, INT, INT, PUNICODE], INT),
- EI.OS_UNIEQ_SLICE_NONNULL: ([PUNICODE, INT, INT, PUNICODE], INT),
- EI.OS_UNIEQ_SLICE_CHAR: ([PUNICODE, INT, INT, UNICHAR], INT),
- EI.OS_UNIEQ_NONNULL: ([PUNICODE, PUNICODE], INT),
- EI.OS_UNIEQ_NONNULL_CHAR: ([PUNICODE, UNICHAR], INT),
- EI.OS_UNIEQ_CHECKNULL_CHAR: ([PUNICODE, UNICHAR], INT),
- EI.OS_UNIEQ_LENGTHOK: ([PUNICODE, PUNICODE], INT),
- EI.OS_RAW_MALLOC_VARSIZE_CHAR: ([INT], ARRAYPTR),
- EI.OS_RAW_FREE: ([ARRAYPTR], lltype.Void),
- EI.OS_THREADLOCALREF_GET: ([INT], INT), # for example
- EI.OS_INT_PY_DIV: ([INT, INT], INT),
- EI.OS_INT_UDIV: ([INT, INT], INT),
- EI.OS_INT_PY_MOD: ([INT, INT], INT),
- EI.OS_INT_UMOD: ([INT, INT], INT),
- }
- argtypes = argtypes[oopspecindex]
- assert argtypes[0] == [v.concretetype for v in op.args[1:]]
- assert argtypes[1] == op.result.concretetype
- if oopspecindex == EI.OS_STR2UNICODE:
- assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE
- elif oopspecindex == EI.OS_RAW_MALLOC_VARSIZE_CHAR:
- assert extraeffect == EI.EF_CAN_RAISE
- elif oopspecindex == EI.OS_RAW_FREE:
- assert extraeffect == EI.EF_CANNOT_RAISE
- elif oopspecindex == EI.OS_THREADLOCALREF_GET:
- assert extraeffect == self.expected_effect_of_threadlocalref_get
- elif oopspecindex in (EI.OS_STR_CONCAT, EI.OS_UNI_CONCAT,
- EI.OS_STR_SLICE, EI.OS_UNI_SLICE):
- assert extraeffect == EI.EF_ELIDABLE_OR_MEMORYERROR
- else:
- assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE
- return 'calldescr-%d' % oopspecindex
- def calldescr_canraise(self, calldescr):
- EI = effectinfo.EffectInfo
- if calldescr == 'calldescr-%d' % EI.OS_RAW_MALLOC_VARSIZE_CHAR:
- return True
- return False
- def test_optimize_goto_if_not():
- v1 = Variable()
- v2 = Variable()
- v3 = Variable(); v3.concretetype = lltype.Bool
- sp1 = SpaceOperation('foobar', [], None)
- sp2 = SpaceOperation('foobaz', [], None)
- block = Block([v1, v2])
- block.operations = [sp1, SpaceOperation('int_gt', [v1, v2], v3), sp2]
- block.exitswitch = v3
- block.exits = exits = [FakeLink(False), FakeLink(True)]
- res = Transformer().optimize_goto_if_not(block)
- assert res == True
- assert block.operations == [sp1, sp2]
- assert block.exitswitch == ('int_gt', v1, v2, '-live-before')
- assert block.exits == exits
- def test_optimize_goto_if_not__incoming():
- v1 = Variable(); v1.concretetype = lltype.Bool
- block = Block([v1])
- block.exitswitch = v1
- block.exits = [FakeLink(False), FakeLink(True)]
- assert not Transformer().optimize_goto_if_not(block)
- def test_optimize_goto_if_not__exit():
- # this case occurs in practice, e.g. with RPython code like:
- # return bool(p) and p.somefield > 0
- v1 = Variable()
- v2 = Variable()
- v3 = Variable(); v3.concretetype = lltype.Bool
- block = Block([v1, v2])
- block.operations = [SpaceOperation('int_gt', [v1, v2], v3)]
- block.exitswitch = v3
- block.exits = exits = [FakeLink(False), FakeLink(True)]
- block.exits[1].args = [v3]
- res = Transformer().optimize_goto_if_not(block)
- assert res == True
- assert block.operations == []
- assert block.exitswitch == ('int_gt', v1, v2, '-live-before')
- assert block.exits == exits
- assert exits[1].args == [const(True)]
- def test_optimize_goto_if_not__unknownop():
- v3 = Variable(); v3.concretetype = lltype.Bool
- block = Block([])
- block.operations = [SpaceOperation('foobar', [], v3)]
- block.exitswitch = v3
- block.exits = [FakeLink(False), FakeLink(True)]
- assert not Transformer().optimize_goto_if_not(block)
- def test_optimize_goto_if_not__ptr_eq():
- for opname in ['ptr_eq', 'ptr_ne']:
- v1 = Variable()
- v2 = Variable()
- v3 = Variable(); v3.concretetype = lltype.Bool
- block = Block([v1, v2])
- block.operations = [SpaceOperation(opname, [v1, v2], v3)]
- block.exitswitch = v3
- block.exits = exits = [FakeLink(False), FakeLink(True)]
- res = Transformer().optimize_goto_if_not(block)
- assert res == True
- assert block.operations == []
- assert block.exitswitch == (opname, v1, v2, '-live-before')
- assert block.exits == exits
- def test_optimize_goto_if_not__ptr_iszero():
- for opname in ['ptr_iszero', 'ptr_nonzero']:
- v1 = Variable()
- v3 = Variable(); v3.concretetype = lltype.Bool
- block = Block([v1])
- block.operations = [SpaceOperation(opname, [v1], v3)]
- block.exitswitch = v3
- block.exits = exits = [FakeLink(False), FakeLink(True)]
- res = Transformer().optimize_goto_if_not(block)
- assert res == True
- assert block.operations == []
- assert block.exitswitch == (opname, v1, '-live-before')
- assert block.exits == exits
- def test_symmetric():
- ops = {'int_add': 'int_add',
- 'int_or': 'int_or',
- 'int_gt': ('int_gt', 'int_lt'),
- 'uint_eq': 'int_eq',
- 'uint_le': ('uint_le', 'uint_ge'),
- 'char_ne': 'int_ne',
- 'char_lt': ('int_lt', 'int_gt'),
- 'uint_xor': 'int_xor',
- 'float_mul': 'float_mul',
- 'float_gt': ('float_gt', 'float_lt'),
- }
- v3 = varoftype(lltype.Signed)
- for v1 in [varoftype(lltype.Signed), const(42)]:
- for v2 in [varoftype(lltype.Signed), const(43)]:
- for name1, name2 in ops.items():
- op = SpaceOperation(name1, [v1, v2], v3)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- if isinstance(name2, str):
- name2 = name2, name2
- if isinstance(v1, Constant) and isinstance(v2, Variable):
- assert op1.args == [v2, v1]
- assert op1.result == v3
- assert op1.opname == name2[1]
- else:
- assert op1.args == [v1, v2]
- assert op1.result == v3
- assert op1.opname == name2[0]
- @py.test.mark.parametrize('opname', ['add_ovf', 'sub_ovf', 'mul_ovf'])
- def test_int_op_ovf(opname):
- v3 = varoftype(lltype.Signed)
- for v1 in [varoftype(lltype.Signed), const(42)]:
- for v2 in [varoftype(lltype.Signed), const(43)]:
- op = SpaceOperation('int_' + opname, [v1, v2], v3)
- oplist = Transformer(FakeCPU()).rewrite_operation(op)
- op1, op0 = oplist
- assert op0.opname == 'int_' + opname
- if (isinstance(v1, Constant) and isinstance(v2, Variable)
- and opname != 'sub_ovf'):
- assert op0.args == [v2, v1]
- assert op0.result == v3
- else:
- assert op0.args == [v1, v2]
- assert op0.result == v3
- assert op1.opname == '-live-'
- assert op1.args == []
- assert op1.result is None
- def test_neg_ovf():
- v3 = varoftype(lltype.Signed)
- for v1 in [varoftype(lltype.Signed), const(42)]:
- op = SpaceOperation('direct_call', [Constant('neg_ovf'), v1], v3)
- oplist = Transformer(FakeCPU())._handle_int_special(op, 'int.neg_ovf',
- [v1])
- op1, op0 = oplist
- assert op0.opname == 'int_sub_ovf'
- assert op0.args == [Constant(0), v1]
- assert op0.result == v3
- assert op1.opname == '-live-'
- assert op1.args == []
- assert op1.result is None
- @py.test.mark.parametrize('opname', ['py_div', 'udiv', 'py_mod', 'umod'])
- def test_int_op_residual(opname):
- v3 = varoftype(lltype.Signed)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- for v1 in [varoftype(lltype.Signed), const(42)]:
- for v2 in [varoftype(lltype.Signed), const(43)]:
- op = SpaceOperation('direct_call', [Constant(opname), v1, v2], v3)
- op0 = tr._handle_int_special(op, 'int.'+opname, [v1, v2])
- assert op0.opname == 'residual_call_ir_i'
- assert op0.args[0].value == opname # pseudo-function as str
- expected = ('int_' + opname).upper()
- assert (op0.args[-1] == 'calldescr-%d' %
- getattr(effectinfo.EffectInfo, 'OS_' + expected))
- def test_calls():
- for RESTYPE, with_void, with_i, with_r, with_f in product(
- [lltype.Signed, rclass.OBJECTPTR, lltype.Float, lltype.Void],
- [False, True],
- [False, True],
- [False, True],
- [False, True],
- ):
- ARGS = []
- if with_void:
- ARGS += [lltype.Void, lltype.Void]
- if with_i:
- ARGS += [lltype.Signed, lltype.Char]
- if with_r:
- ARGS += [rclass.OBJECTPTR, lltype.Ptr(rstr.STR)]
- if with_f:
- ARGS += [lltype.Float, lltype.Float]
- random.shuffle(ARGS)
- if RESTYPE == lltype.Float:
- with_f = True
- if with_f:
- expectedkind = 'irf' # all kinds
- elif with_i:
- expectedkind = 'ir' # integers and references
- else:
- expectedkind = 'r' # only references
- yield residual_call_test, ARGS, RESTYPE, expectedkind
- yield direct_call_test, ARGS, RESTYPE, expectedkind
- yield indirect_residual_call_test, ARGS, RESTYPE, expectedkind
- yield indirect_regular_call_test, ARGS, RESTYPE, expectedkind
- def get_direct_call_op(argtypes, restype):
- FUNC = lltype.FuncType(argtypes, restype)
- fnptr = lltype.functionptr(FUNC, "g") # no graph
- c_fnptr = const(fnptr)
- vars = [varoftype(TYPE) for TYPE in argtypes]
- v_result = varoftype(restype)
- op = SpaceOperation('direct_call', [c_fnptr] + vars, v_result)
- return op
- def residual_call_test(argtypes, restype, expectedkind):
- op = get_direct_call_op(argtypes, restype)
- tr = Transformer(FakeCPU(), FakeResidualCallControl())
- oplist = tr.rewrite_operation(op)
- op0, op1 = oplist
- reskind = getkind(restype)[0]
- assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind)
- assert op0.result == op.result
- assert op0.args[0] == op.args[0]
- assert op0.args[-1] == 'calldescr'
- assert len(op0.args) == 1 + len(expectedkind) + 1
- for sublist, kind1 in zip(op0.args[1:-1], expectedkind):
- assert sublist.kind.startswith(kind1)
- assert list(sublist) == [v for v in op.args[1:]
- if getkind(v.concretetype) == sublist.kind]
- for v in op.args[1:]:
- kind = getkind(v.concretetype)
- assert kind == 'void' or kind[0] in expectedkind
- assert op1.opname == '-live-'
- assert op1.args == []
- def direct_call_test(argtypes, restype, expectedkind):
- op = get_direct_call_op(argtypes, restype)
- tr = Transformer(FakeCPU(), FakeRegularCallControl())
- tr.graph = 'someinitialgraph'
- oplist = tr.rewrite_operation(op)
- op0, op1 = oplist
- reskind = getkind(restype)[0]
- assert op0.opname == 'inline_call_%s_%s' % (expectedkind, reskind)
- assert op0.result == op.result
- assert op0.args[0] == 'somejitcode'
- assert len(op0.args) == 1 + len(expectedkind)
- for sublist, kind1 in zip(op0.args[1:], expectedkind):
- assert sublist.kind.startswith(kind1)
- assert list(sublist) == [v for v in op.args[1:]
- if getkind(v.concretetype) == sublist.kind]
- for v in op.args[1:]:
- kind = getkind(v.concretetype)
- assert kind == 'void' or kind[0] in expectedkind
- assert op1.opname == '-live-'
- assert op1.args == []
- def indirect_residual_call_test(argtypes, restype, expectedkind):
- # an indirect call that is residual in all cases is very similar to
- # a residual direct call
- op = get_direct_call_op(argtypes, restype)
- op.opname = 'indirect_call'
- op.args[0] = varoftype(op.args[0].concretetype)
- op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void))
- tr = Transformer(FakeCPU(), FakeResidualIndirectCallControl())
- tr.graph = 'someinitialgraph'
- oplist = tr.rewrite_operation(op)
- op0, op1 = oplist
- reskind = getkind(restype)[0]
- assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind)
- assert op0.result == op.result
- assert op0.args[0] == op.args[0]
- assert op0.args[-1] == 'calldescr'
- assert len(op0.args) == 1 + len(expectedkind) + 1
- for sublist, kind1 in zip(op0.args[1:-1], expectedkind):
- assert sublist.kind.startswith(kind1)
- assert list(sublist) == [v for v in op.args[1:]
- if getkind(v.concretetype)==sublist.kind]
- for v in op.args[1:]:
- kind = getkind(v.concretetype)
- assert kind == 'void' or kind[0] in expectedkind
- assert op1.opname == '-live-'
- assert op1.args == []
- def indirect_regular_call_test(argtypes, restype, expectedkind):
- # a regular indirect call is preceded by a guard_value on the
- # function address, so that pyjitpl can know which jitcode to follow
- from rpython.jit.codewriter.flatten import IndirectCallTargets
- op = get_direct_call_op(argtypes, restype)
- op.opname = 'indirect_call'
- op.args[0] = varoftype(op.args[0].concretetype)
- op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void))
- tr = Transformer(FakeCPU(), FakeRegularIndirectCallControl())
- tr.graph = 'someinitialgraph'
- oplist = tr.rewrite_operation(op)
- op0gv, op1gv, op0, op1 = oplist
- assert op0gv.opname == '-live-'
- assert op0gv.args == []
- assert op1gv.opname == 'int_guard_value'
- assert op1gv.args == [op.args[0]]
- assert op1gv.result is None
- #
- reskind = getkind(restype)[0]
- assert op0.opname == 'residual_call_%s_%s' % (expectedkind, reskind)
- assert op0.result == op.result
- assert op0.args[0] == op.args[0]
- assert isinstance(op0.args[1], IndirectCallTargets)
- assert op0.args[1].lst == ['somejitcode1', 'somejitcode2']
- assert op0.args[-1] == 'calldescr'
- assert len(op0.args) == 2 + len(expectedkind) + 1
- for sublist, kind1 in zip(op0.args[2:-1], expectedkind):
- assert sublist.kind.startswith(kind1)
- assert list(sublist) == [v for v in op.args[1:]
- if getkind(v.concretetype)==sublist.kind]
- for v in op.args[1:]:
- kind = getkind(v.concretetype)
- assert kind == 'void' or kind[0] in expectedkind
- # Note: we still expect a -live- here, even though canraise() returns
- # False, because this 'residual_call' will likely call further jitcodes
- # which can do e.g. guard_class or other stuff requiring anyway a -live-.
- assert op1.opname == '-live-'
- assert op1.args == []
- def test_getfield():
- # XXX a more compact encoding would be possible, something along
- # the lines of getfield_gc_r %r0, $offset, %r1
- # which would not need a Descr at all.
- S1 = lltype.Struct('S1')
- S2 = lltype.GcStruct('S2')
- S = lltype.GcStruct('S', ('int', lltype.Signed),
- ('ps1', lltype.Ptr(S1)),
- ('ps2', lltype.Ptr(S2)),
- ('flt', lltype.Float),
- ('boo', lltype.Bool),
- ('chr', lltype.Char),
- ('unc', lltype.UniChar))
- for name, suffix in [('int', 'i'),
- ('ps1', 'i'),
- ('ps2', 'r'),
- ('flt', 'f'),
- ('boo', 'i'),
- ('chr', 'i'),
- ('unc', 'i')]:
- v_parent = varoftype(lltype.Ptr(S))
- c_name = Constant(name, lltype.Void)
- v_result = varoftype(getattr(S, name))
- op = SpaceOperation('getfield', [v_parent, c_name], v_result)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'getfield_gc_' + suffix
- fielddescr = ('fielddescr', S, name)
- assert op1.args == [v_parent, fielddescr]
- assert op1.result == v_result
- def test_getfield_typeptr():
- v_parent = varoftype(rclass.OBJECTPTR)
- c_name = Constant('typeptr', lltype.Void)
- v_result = varoftype(rclass.OBJECT.typeptr)
- op = SpaceOperation('getfield', [v_parent, c_name], v_result)
- oplist = Transformer(FakeCPU()).rewrite_operation(op)
- op0, op1 = oplist
- assert op0.opname == '-live-'
- assert op0.args == []
- assert op1.opname == 'guard_class'
- assert op1.args == [v_parent]
- assert op1.result == v_result
- def test_setfield():
- # XXX a more compact encoding would be possible; see test_getfield()
- S1 = lltype.Struct('S1')
- S2 = lltype.GcStruct('S2')
- S = lltype.GcStruct('S', ('int', lltype.Signed),
- ('ps1', lltype.Ptr(S1)),
- ('ps2', lltype.Ptr(S2)),
- ('flt', lltype.Float),
- ('boo', lltype.Bool),
- ('chr', lltype.Char),
- ('unc', lltype.UniChar))
- for name, suffix in [('int', 'i'),
- ('ps1', 'i'),
- ('ps2', 'r'),
- ('flt', 'f'),
- ('boo', 'i'),
- ('chr', 'i'),
- ('unc', 'i')]:
- v_parent = varoftype(lltype.Ptr(S))
- c_name = Constant(name, lltype.Void)
- v_newvalue = varoftype(getattr(S, name))
- op = SpaceOperation('setfield', [v_parent, c_name, v_newvalue],
- varoftype(lltype.Void))
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'setfield_gc_' + suffix
- fielddescr = ('fielddescr', S, name)
- assert op1.args == [v_parent, v_newvalue, fielddescr]
- assert op1.result is None
- def test_malloc_new():
- S = lltype.GcStruct('S')
- v = varoftype(lltype.Ptr(S))
- op = SpaceOperation('malloc', [Constant(S, lltype.Void),
- Constant({'flavor': 'gc'}, lltype.Void)], v)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'new'
- assert op1.args == [('sizedescr', S)]
- def test_malloc_new_zero_2():
- S = lltype.GcStruct('S', ('x', lltype.Signed))
- v = varoftype(lltype.Ptr(S))
- op = SpaceOperation('malloc', [Constant(S, lltype.Void),
- Constant({'flavor': 'gc',
- 'zero': True}, lltype.Void)], v)
- op1, op2 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'new'
- assert op1.args == [('sizedescr', S)]
- assert op2.opname == 'setfield_gc_i'
- assert op2.args[0] == v
- def test_malloc_new_zero_nested():
- S0 = lltype.GcStruct('S0')
- S = lltype.Struct('S', ('x', lltype.Ptr(S0)))
- S2 = lltype.GcStruct('S2', ('parent', S),
- ('xx', lltype.Ptr(S0)))
- v = varoftype(lltype.Ptr(S2))
- op = SpaceOperation('malloc', [Constant(S2, lltype.Void),
- Constant({'flavor': 'gc',
- 'zero': True}, lltype.Void)], v)
- op1, op2, op3 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'new'
- assert op1.args == [('sizedescr', S2)]
- assert op2.opname == 'setfield_gc_r'
- assert op2.args[0] == v
- assert op3.opname == 'setfield_gc_r'
- assert op3.args[0] == v
- def test_malloc_new_with_vtable():
- vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- S = lltype.GcStruct('S', ('parent', rclass.OBJECT))
- heaptracker.set_testing_vtable_for_gcstruct(S, vtable, 'S')
- v = varoftype(lltype.Ptr(S))
- op = SpaceOperation('malloc', [Constant(S, lltype.Void),
- Constant({'flavor': 'gc'}, lltype.Void)], v)
- cpu = FakeCPU()
- op1 = Transformer(cpu).rewrite_operation(op)
- assert op1.opname == 'new_with_vtable'
- assert op1.args == [('sizedescr', S)]
- def test_malloc_new_with_destructor():
- vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- S = lltype.GcStruct('S', ('parent', rclass.OBJECT), rtti=True)
- DESTRUCTOR = lltype.FuncType([lltype.Ptr(S)], lltype.Void)
- destructor = lltype.functionptr(DESTRUCTOR, 'destructor')
- lltype.attachRuntimeTypeInfo(S, destrptr=destructor)
- heaptracker.set_testing_vtable_for_gcstruct(S, vtable, 'S')
- v = varoftype(lltype.Ptr(S))
- op = SpaceOperation('malloc', [Constant(S, lltype.Void),
- Constant({'flavor': 'gc'}, lltype.Void)], v)
- tr = Transformer(FakeCPU(), FakeResidualCallControl())
- oplist = tr.rewrite_operation(op)
- op0, op1 = oplist
- assert op0.opname == 'residual_call_r_r'
- assert op0.args[0].value == 'alloc_with_del' # pseudo-function as a str
- assert list(op0.args[1]) == []
- assert op1.opname == '-live-'
- assert op1.args == []
- def test_raw_malloc():
- S = rffi.CArray(lltype.Char)
- v1 = varoftype(lltype.Signed)
- v = varoftype(lltype.Ptr(S))
- flags = Constant({'flavor': 'raw'}, lltype.Void)
- op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
- v1], v)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op0, op1 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_ir_i'
- assert op0.args[0].value == 'raw_malloc_varsize' # pseudo-function as a str
- assert (op0.args[-1] == 'calldescr-%d' %
- effectinfo.EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR)
- assert op1.opname == '-live-'
- assert op1.args == []
- def test_raw_malloc_zero():
- S = rffi.CArray(lltype.Signed)
- v1 = varoftype(lltype.Signed)
- v = varoftype(lltype.Ptr(S))
- flags = Constant({'flavor': 'raw', 'zero': True}, lltype.Void)
- op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
- v1], v)
- tr = Transformer(FakeCPU(), FakeResidualCallControl())
- op0, op1 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_ir_i'
- assert op0.args[0].value == 'raw_malloc_varsize_zero' # pseudo-fn as a str
- assert op1.opname == '-live-'
- assert op1.args == []
- def test_raw_malloc_unsupported_flag():
- S = rffi.CArray(lltype.Signed)
- v1 = varoftype(lltype.Signed)
- v = varoftype(lltype.Ptr(S))
- flags = Constant({'flavor': 'raw', 'unsupported_flag': True}, lltype.Void)
- op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
- v1], v)
- tr = Transformer(FakeCPU(), FakeResidualCallControl())
- py.test.raises(UnsupportedMallocFlags, tr.rewrite_operation, op)
- def test_raw_malloc_fixedsize():
- S = lltype.Struct('dummy', ('x', lltype.Signed))
- v = varoftype(lltype.Ptr(S))
- flags = Constant({'flavor': 'raw', 'zero': True}, lltype.Void)
- op = SpaceOperation('malloc', [Constant(S, lltype.Void), flags], v)
- tr = Transformer(FakeCPU(), FakeResidualCallControl())
- op0, op1 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_r_i'
- assert op0.args[0].value == 'raw_malloc_fixedsize_zero' #pseudo-fn as a str
- assert op1.opname == '-live-'
- assert op1.args == []
- def test_raw_free():
- S = rffi.CArray(lltype.Char)
- flags = Constant({'flavor': 'raw', 'track_allocation': True},
- lltype.Void)
- op = SpaceOperation('free', [varoftype(lltype.Ptr(S)), flags],
- varoftype(lltype.Void))
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op0 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_ir_v'
- assert op0.args[0].value == 'raw_free'
- assert op0.args[-1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_RAW_FREE
- def test_raw_free_no_track_allocation():
- S = rffi.CArray(lltype.Signed)
- flags = Constant({'flavor': 'raw', 'track_allocation': False},
- lltype.Void)
- op = SpaceOperation('free', [varoftype(lltype.Ptr(S)), flags],
- varoftype(lltype.Void))
- tr = Transformer(FakeCPU(), FakeResidualCallControl())
- op0, op1 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_ir_v'
- assert op0.args[0].value == 'raw_free_no_track_allocation'
- assert op1.opname == '-live-'
- def test_rename_on_links():
- v1 = Variable()
- v2 = Variable(); v2.concretetype = llmemory.Address
- v3 = Variable()
- block = Block([v1])
- block.operations = [SpaceOperation('cast_pointer', [v1], v2)]
- block2 = Block([v3])
- block.closeblock(Link([v2], block2))
- Transformer().optimize_block(block)
- assert block.inputargs == [v1]
- assert block.operations == []
- assert block.exits[0].target is block2
- assert block.exits[0].args == [v1]
- def test_cast_ptr_to_adr():
- t = Transformer(FakeCPU(), None)
- v = varoftype(lltype.Ptr(lltype.Array()))
- v2 = varoftype(llmemory.Address)
- op1 = t.rewrite_operation(SpaceOperation('cast_ptr_to_adr', [v], v2))
- assert op1 is None
- def test_int_eq():
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(lltype.Signed)
- v3 = varoftype(lltype.Bool)
- c0 = const(0)
- #
- for opname, reducedname in [('int_eq', 'int_is_zero'),
- ('int_ne', 'int_is_true')]:
- op = SpaceOperation(opname, [v1, v2], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == opname
- assert op1.args == [v1, v2]
- #
- op = SpaceOperation(opname, [v1, c0], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v1]
- #
- op = SpaceOperation(opname, [c0, v2], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v2]
- def test_ptr_eq():
- v1 = varoftype(lltype.Ptr(rstr.STR))
- v2 = varoftype(lltype.Ptr(rstr.STR))
- v3 = varoftype(lltype.Bool)
- c0 = const(lltype.nullptr(rstr.STR))
- #
- for opname, reducedname in [('ptr_eq', 'ptr_iszero'),
- ('ptr_ne', 'ptr_nonzero')]:
- op = SpaceOperation(opname, [v1, v2], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == opname
- assert op1.args == [v1, v2]
- #
- op = SpaceOperation(opname, [v1, c0], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v1]
- #
- op = SpaceOperation(opname, [c0, v2], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v2]
- def test_instance_ptr_eq():
- v1 = varoftype(rclass.OBJECTPTR)
- v2 = varoftype(rclass.OBJECTPTR)
- v3 = varoftype(lltype.Bool)
- c0 = const(lltype.nullptr(rclass.OBJECT))
- for opname, newopname, reducedname in [
- ('ptr_eq', 'instance_ptr_eq', 'ptr_iszero'),
- ('ptr_ne', 'instance_ptr_ne', 'ptr_nonzero')
- ]:
- op = SpaceOperation(opname, [v1, v2], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == newopname
- assert op1.args == [v1, v2]
- op = SpaceOperation(opname, [v1, c0], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v1]
- op = SpaceOperation(opname, [c0, v1], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v1]
- def test_nongc_ptr_eq():
- v1 = varoftype(rclass.NONGCOBJECTPTR)
- v2 = varoftype(rclass.NONGCOBJECTPTR)
- v3 = varoftype(lltype.Bool)
- c0 = const(lltype.nullptr(rclass.NONGCOBJECT))
- #
- for opname, reducedname in [('ptr_eq', 'int_is_zero'),
- ('ptr_ne', 'int_is_true')]:
- op = SpaceOperation(opname, [v1, v2], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == opname.replace('ptr_', 'int_')
- assert op1.args == [v1, v2]
- #
- op = SpaceOperation(opname, [v1, c0], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v1]
- #
- op = SpaceOperation(opname, [c0, v2], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == reducedname
- assert op1.args == [v2]
- #
- op = SpaceOperation('ptr_iszero', [v1], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'int_is_zero'
- assert op1.args == [v1]
- #
- op = SpaceOperation('ptr_nonzero', [v1], v3)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'int_is_true'
- assert op1.args == [v1]
- def test_str_getinteriorarraysize():
- v = varoftype(lltype.Ptr(rstr.STR))
- v_result = varoftype(lltype.Signed)
- op = SpaceOperation('getinteriorarraysize',
- [v, Constant('chars', lltype.Void)],
- v_result)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'strlen'
- assert op1.args == [v]
- assert op1.result == v_result
- def test_unicode_getinteriorarraysize():
- v = varoftype(lltype.Ptr(rstr.UNICODE))
- v_result = varoftype(lltype.Signed)
- op = SpaceOperation('getinteriorarraysize',
- [v, Constant('chars', lltype.Void)],
- v_result)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'unicodelen'
- assert op1.args == [v]
- assert op1.result == v_result
- def test_str_getinteriorfield():
- v = varoftype(lltype.Ptr(rstr.STR))
- v_index = varoftype(lltype.Signed)
- v_result = varoftype(lltype.Char)
- op = SpaceOperation('getinteriorfield',
- [v, Constant('chars', lltype.Void), v_index],
- v_result)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'strgetitem'
- assert op1.args == [v, v_index]
- assert op1.result == v_result
- def test_unicode_getinteriorfield():
- v = varoftype(lltype.Ptr(rstr.UNICODE))
- v_index = varoftype(lltype.Signed)
- v_result = varoftype(lltype.UniChar)
- op = SpaceOperation('getinteriorfield',
- [v, Constant('chars', lltype.Void), v_index],
- v_result)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'unicodegetitem'
- assert op1.args == [v, v_index]
- assert op1.result == v_result
- def test_dict_getinteriorfield():
- DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
- ('k', lltype.Signed)))
- v = varoftype(lltype.Ptr(DICT))
- i = varoftype(lltype.Signed)
- v_result = varoftype(lltype.Signed)
- op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
- v_result)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'getinteriorfield_gc_i'
- assert op1.args == [v, i, ('interiorfielddescr', DICT, 'v')]
- op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
- Constant(None, lltype.Void))
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1 is None
- def test_str_setinteriorfield():
- v = varoftype(lltype.Ptr(rstr.STR))
- v_index = varoftype(lltype.Signed)
- v_newchr = varoftype(lltype.Char)
- v_void = varoftype(lltype.Void)
- op = SpaceOperation('setinteriorfield',
- [v, Constant('chars', lltype.Void), v_index, v_newchr],
- v_void)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'strsetitem'
- assert op1.args == [v, v_index, v_newchr]
- assert op1.result == v_void
- def test_unicode_setinteriorfield():
- v = varoftype(lltype.Ptr(rstr.UNICODE))
- v_index = varoftype(lltype.Signed)
- v_newchr = varoftype(lltype.UniChar)
- v_void = varoftype(lltype.Void)
- op = SpaceOperation('setinteriorfield',
- [v, Constant('chars', lltype.Void), v_index, v_newchr],
- v_void)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'unicodesetitem'
- assert op1.args == [v, v_index, v_newchr]
- assert op1.result == v_void
- def test_dict_setinteriorfield():
- DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
- ('k', lltype.Signed)))
- v = varoftype(lltype.Ptr(DICT))
- i = varoftype(lltype.Signed)
- v_void = varoftype(lltype.Void)
- op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
- i],
- v_void)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'setinteriorfield_gc_i'
- assert op1.args == [v, i, i, ('interiorfielddescr', DICT, 'v')]
- op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
- v_void], v_void)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert not op1
- def test_raw_store():
- v_storage = varoftype(llmemory.Address)
- v_index = varoftype(lltype.Signed)
- v_item = varoftype(lltype.Signed) # for example
- op = SpaceOperation('raw_store', [v_storage, v_index, v_item], None)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'raw_store_i'
- assert op1.args[0] == v_storage
- assert op1.args[1] == v_index
- assert op1.args[2] == v_item
- assert op1.args[3] == ('arraydescr', rffi.CArray(lltype.Signed))
- def test_raw_load():
- v_storage = varoftype(llmemory.Address)
- v_index = varoftype(lltype.Signed)
- v_res = varoftype(lltype.Signed) # for example
- op = SpaceOperation('raw_load', [v_storage, v_index], v_res)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'raw_load_i'
- assert op1.args[0] == v_storage
- assert op1.args[1] == v_index
- assert op1.args[2] == ('arraydescr', rffi.CArray(lltype.Signed))
- assert op1.result == v_res
- def test_promote_1():
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(lltype.Signed)
- op = SpaceOperation('hint',
- [v1, Constant({'promote': True}, lltype.Void)],
- v2)
- oplist = Transformer().rewrite_operation(op)
- op0, op1, op2 = oplist
- assert op0.opname == '-live-'
- assert op0.args == []
- assert op1.opname == 'int_guard_value'
- assert op1.args == [v1]
- assert op1.result is None
- assert op2 is None
- def test_promote_2():
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(lltype.Signed)
- op = SpaceOperation('hint',
- [v1, Constant({'promote': True}, lltype.Void)],
- v2)
- returnblock = Block([varoftype(lltype.Signed)])
- returnblock.operations = ()
- block = Block([v1])
- block.operations = [op]
- block.closeblock(Link([v2], returnblock))
- Transformer().optimize_block(block)
- assert len(block.operations) == 2
- assert block.operations[0].opname == '-live-'
- assert block.operations[0].args == []
- assert block.operations[1].opname == 'int_guard_value'
- assert block.operations[1].args == [v1]
- assert block.operations[1].result is None
- assert block.exits[0].args == [v1]
- def test_jit_merge_point_1():
- class FakeJitDriverSD:
- index = 42
- class jitdriver:
- active = True
- greens = ['green1', 'green2', 'voidgreen3']
- reds = ['red1', 'red2', 'voidred3']
- numreds = 3
- jd = FakeJitDriverSD()
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(lltype.Signed)
- vvoid1 = varoftype(lltype.Void)
- v3 = varoftype(lltype.Signed)
- v4 = varoftype(lltype.Signed)
- vvoid2 = varoftype(lltype.Void)
- v5 = varoftype(lltype.Void)
- op = SpaceOperation('jit_marker',
- [Constant('jit_merge_point', lltype.Void),
- Constant(jd.jitdriver, lltype.Void),
- v1, v2, vvoid1, v3, v4, vvoid2], v5)
- tr = Transformer()
- tr.portal_jd = jd
- oplist = tr.rewrite_operation(op)
- assert len(oplist) == 7
- assert oplist[0].opname == '-live-'
- assert oplist[1].opname == 'int_guard_value'
- assert oplist[1].args == [v1]
- assert oplist[2].opname == '-live-'
- assert oplist[3].opname == 'int_guard_value'
- assert oplist[3].args == [v2]
- assert oplist[4].opname == '-live-'
- assert oplist[5].opname == 'jit_merge_point'
- assert oplist[5].args[0].value == 42
- assert list(oplist[5].args[1]) == [v1, v2]
- assert list(oplist[5].args[4]) == [v3, v4]
- assert oplist[6].opname == '-live-'
- def test_getfield_gc():
- S = lltype.GcStruct('S', ('x', lltype.Char))
- v1 = varoftype(lltype.Ptr(S))
- v2 = varoftype(lltype.Char)
- op = SpaceOperation('getfield', [v1, Constant('x', lltype.Void)], v2)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'getfield_gc_i'
- assert op1.args == [v1, ('fielddescr', S, 'x')]
- assert op1.result == v2
- def test_getfield_gc_pure():
- S = lltype.GcStruct('S', ('x', lltype.Char),
- hints={'immutable': True})
- v1 = varoftype(lltype.Ptr(S))
- v2 = varoftype(lltype.Char)
- op = SpaceOperation('getfield', [v1, Constant('x', lltype.Void)], v2)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'getfield_gc_i_pure'
- assert op1.args == [v1, ('fielddescr', S, 'x')]
- assert op1.result == v2
- def test_getfield_gc_greenfield():
- class FakeCC:
- def get_vinfo(self, v):
- return None
- def could_be_green_field(self, S1, name1):
- assert S1 == S
- assert name1 == 'x'
- return True
- S = lltype.GcStruct('S', ('x', lltype.Char),
- hints={'immutable': True})
- v1 = varoftype(lltype.Ptr(S))
- v2 = varoftype(lltype.Char)
- op = SpaceOperation('getfield', [v1, Constant('x', lltype.Void)], v2)
- op0, op1 = Transformer(FakeCPU(), FakeCC()).rewrite_operation(op)
- assert op0.opname == '-live-'
- assert op1.opname == 'getfield_gc_i_greenfield'
- assert op1.args == [v1, ('fielddescr', S, 'x')]
- assert op1.result == v2
- def test_int_abs():
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(lltype.Signed)
- op = SpaceOperation('int_abs', [v1], v2)
- tr = Transformer(FakeCPU(), FakeRegularCallControl())
- tr.graph = "somemaingraph"
- oplist = tr.rewrite_operation(op)
- assert oplist[0].opname == 'inline_call_ir_i'
- assert oplist[0].args[0] == 'somejitcode'
- def test_str_newstr():
- c_STR = Constant(rstr.STR, lltype.Void)
- c_flavor = Constant({'flavor': 'gc'}, lltype.Void)
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(lltype.Ptr(rstr.STR))
- op = SpaceOperation('malloc_varsize', [c_STR, c_flavor, v1], v2)
- op1 = Transformer().rewrite_operation(op)
- assert op1.opname == 'newstr'
- assert op1.args == [v1]
- assert op1.result == v2
- def test_malloc_varsize_zero():
- c_A = Constant(lltype.GcArray(lltype.Signed), lltype.Void)
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(c_A.value)
- c_flags = Constant({"flavor": "gc", "zero": True}, lltype.Void)
- op = SpaceOperation('malloc_varsize', [c_A, c_flags, v1], v2)
- op1 = Transformer(FakeCPU()).rewrite_operation(op)
- assert op1.opname == 'new_array_clear'
- def test_str_concat():
- # test that the oopspec is present and correctly transformed
- PSTR = lltype.Ptr(rstr.STR)
- FUNC = lltype.FuncType([PSTR, PSTR], PSTR)
- func = lltype.functionptr(FUNC, 'll_strconcat',
- _callable=rstr.LLHelpers.ll_strconcat)
- v1 = varoftype(PSTR)
- v2 = varoftype(PSTR)
- v3 = varoftype(PSTR)
- op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_r_r'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind('ref', [v1, v2])
- assert op1.args[2] == 'calldescr-%d' % effectinfo.EffectInfo.OS_STR_CONCAT
- assert op1.result == v3
- def test_str_promote():
- PSTR = lltype.Ptr(rstr.STR)
- v1 = varoftype(PSTR)
- v2 = varoftype(PSTR)
- op = SpaceOperation('hint',
- [v1, Constant({'promote_string': True}, lltype.Void)],
- v2)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op0, op1, _ = tr.rewrite_operation(op)
- assert op1.opname == 'str_guard_value'
- assert op1.args[0] == v1
- assert op1.args[2] == 'calldescr'
- assert op1.result == v2
- assert op0.opname == '-live-'
- def test_double_promote_str():
- PSTR = lltype.Ptr(rstr.STR)
- v1 = varoftype(PSTR)
- v2 = varoftype(PSTR)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = SpaceOperation('hint',
- [v1, Constant({'promote_string': True}, lltype.Void)],
- v2)
- op2 = SpaceOperation('hint',
- [v1, Constant({'promote_string': True,
- 'promote': True}, lltype.Void)],
- v2)
- lst1 = tr.rewrite_operation(op1)
- lst2 = tr.rewrite_operation(op2)
- assert lst1 == lst2
- def test_double_promote_nonstr():
- v1 = varoftype(lltype.Signed)
- v2 = varoftype(lltype.Signed)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = SpaceOperation('hint',
- [v1, Constant({'promote': True}, lltype.Void)],
- v2)
- op2 = SpaceOperation('hint',
- [v1, Constant({'promote_string': True,
- 'promote': True}, lltype.Void)],
- v2)
- lst1 = tr.rewrite_operation(op1)
- lst2 = tr.rewrite_operation(op2)
- assert lst1 == lst2
- def test_unicode_concat():
- # test that the oopspec is present and correctly transformed
- PSTR = lltype.Ptr(rstr.UNICODE)
- FUNC = lltype.FuncType([PSTR, PSTR], PSTR)
- func = lltype.functionptr(FUNC, 'll_strconcat',
- _callable=rstr.LLHelpers.ll_strconcat)
- v1 = varoftype(PSTR)
- v2 = varoftype(PSTR)
- v3 = varoftype(PSTR)
- op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
- cc = FakeBuiltinCallControl()
- tr = Transformer(FakeCPU(), cc)
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_r_r'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind('ref', [v1, v2])
- assert op1.args[2] == 'calldescr-%d' % effectinfo.EffectInfo.OS_UNI_CONCAT
- assert op1.result == v3
- #
- # check the callinfo_for_oopspec
- got = cc.callinfocollection.seen[0]
- assert got[0] == effectinfo.EffectInfo.OS_UNI_CONCAT
- assert got[1] == op1.args[2] # the calldescr
- assert heaptracker.int2adr(got[2]) == llmemory.cast_ptr_to_adr(func)
- def test_str_slice():
- # test that the oopspec is present and correctly transformed
- PSTR = lltype.Ptr(rstr.STR)
- INT = lltype.Signed
- FUNC = lltype.FuncType([PSTR, INT, INT], PSTR)
- func = lltype.functionptr(FUNC, '_ll_stringslice',
- _callable=rstr.LLHelpers._ll_stringslice)
- v1 = varoftype(PSTR)
- v2 = varoftype(INT)
- v3 = varoftype(INT)
- v4 = varoftype(PSTR)
- op = SpaceOperation('direct_call', [const(func), v1, v2, v3], v4)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_ir_r'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind('int', [v2, v3])
- assert op1.args[2] == ListOfKind('ref', [v1])
- assert op1.args[3] == 'calldescr-%d' % effectinfo.EffectInfo.OS_STR_SLICE
- assert op1.result == v4
- def test_unicode_slice():
- # test that the oopspec is present and correctly transformed
- PUNICODE = lltype.Ptr(rstr.UNICODE)
- INT = lltype.Signed
- FUNC = lltype.FuncType([PUNICODE, INT, INT], PUNICODE)
- func = lltype.functionptr(FUNC, '_ll_stringslice',
- _callable=rstr.LLHelpers._ll_stringslice)
- v1 = varoftype(PUNICODE)
- v2 = varoftype(INT)
- v3 = varoftype(INT)
- v4 = varoftype(PUNICODE)
- op = SpaceOperation('direct_call', [const(func), v1, v2, v3], v4)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_ir_r'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind('int', [v2, v3])
- assert op1.args[2] == ListOfKind('ref', [v1])
- assert op1.args[3] == 'calldescr-%d' % effectinfo.EffectInfo.OS_UNI_SLICE
- assert op1.result == v4
- def test_str2unicode():
- # test that the oopspec is present and correctly transformed
- PSTR = lltype.Ptr(rstr.STR)
- PUNICODE = lltype.Ptr(rstr.UNICODE)
- FUNC = lltype.FuncType([PSTR], PUNICODE)
- func = lltype.functionptr(FUNC, 'll_str2unicode',
- _callable=rstr.LLHelpers.ll_str2unicode)
- v1 = varoftype(PSTR)
- v2 = varoftype(PUNICODE)
- op = SpaceOperation('direct_call', [const(func), v1], v2)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_r_r'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind('ref', [v1])
- assert op1.args[2] == 'calldescr-%d' % effectinfo.EffectInfo.OS_STR2UNICODE
- assert op1.result == v2
- def test_unicode_eq_checknull_char():
- # test that the oopspec is present and correctly transformed
- PUNICODE = lltype.Ptr(rstr.UNICODE)
- FUNC = lltype.FuncType([PUNICODE, PUNICODE], lltype.Bool)
- func = lltype.functionptr(FUNC, 'll_streq',
- _callable=rstr.LLHelpers.ll_streq)
- v1 = varoftype(PUNICODE)
- v2 = varoftype(PUNICODE)
- v3 = varoftype(lltype.Bool)
- op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
- cc = FakeBuiltinCallControl()
- tr = Transformer(FakeCPU(), cc)
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_r_i'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind('ref', [v1, v2])
- assert op1.args[2] == 'calldescr-%d' % effectinfo.EffectInfo.OS_UNI_EQUAL
- assert op1.result == v3
- # test that the OS_UNIEQ_* functions are registered
- cic = cc.callinfocollection
- assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL)
- assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR)
- def test_list_ll_arraycopy():
- from rpython.rlib.rgc import ll_arraycopy
- LIST = lltype.GcArray(lltype.Signed)
- PLIST = lltype.Ptr(LIST)
- INT = lltype.Signed
- FUNC = lltype.FuncType([PLIST]*2+[INT]*3, lltype.Void)
- func = lltype.functionptr(FUNC, 'll_arraycopy', _callable=ll_arraycopy)
- v1 = varoftype(PLIST)
- v2 = varoftype(PLIST)
- v3 = varoftype(INT)
- v4 = varoftype(INT)
- v5 = varoftype(INT)
- v6 = varoftype(lltype.Void)
- op = SpaceOperation('direct_call', [const(func), v1, v2, v3, v4, v5], v6)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_ir_v'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind('int', [v3, v4, v5])
- assert op1.args[2] == ListOfKind('ref', [v1, v2])
- assert op1.args[3] == 'calldescr-%d' % effectinfo.EffectInfo.OS_ARRAYCOPY
- def test_math_sqrt():
- # test that the oopspec is present and correctly transformed
- FLOAT = lltype.Float
- FUNC = lltype.FuncType([FLOAT], FLOAT)
- func = lltype.functionptr(FUNC, 'll_math',
- _callable=ll_math.sqrt_nonneg)
- v1 = varoftype(FLOAT)
- v2 = varoftype(FLOAT)
- op = SpaceOperation('direct_call', [const(func), v1], v2)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
- op1 = tr.rewrite_operation(op)
- assert op1.opname == 'residual_call_irf_f'
- assert op1.args[0].value == func
- assert op1.args[1] == ListOfKind("int", [])
- assert op1.args[2] == ListOfKind("ref", [])
- assert op1.args[3] == ListOfKind('float', [v1])
- assert op1.args[4] == 'calldescr-%d' % effectinfo.EffectInfo.OS_MATH_SQRT
- assert op1.result == v2
- def test_quasi_immutable():
- from rpython.rtyper.rclass import FieldListAccessor, IR_QUASIIMMUTABLE
- accessor = FieldListAccessor()
- accessor.initialize(None, {'inst_x': IR_QUASIIMMUTABLE})
- v2 = varoftype(lltype.Signed)
- STRUCT = lltype.GcStruct('struct', ('inst_x', lltype.Signed),
- ('mutate_x', rclass.OBJECTPTR),
- hints={'immutable_fields': accessor})
- for v_x in [const(lltype.malloc(STRUCT)), varoftype(lltype.Ptr(STRUCT))]:
- op = SpaceOperation('getfield', [v_x, Constant('inst_x', lltype.Void)],
- v2)
- tr = Transformer(FakeCPU())
- [_, op1, op2] = tr.rewrite_operation(op)
- assert op1.opname == 'record_quasiimmut_field'
- assert len(op1.args) == 3
- assert op1.args[0] == v_x
- assert op1.args[1] == ('fielddescr', STRUCT, 'inst_x')
- assert op1.args[2] == ('fielddescr', STRUCT, 'mutate_x')
- assert op1.result is None
- assert op2.opname == 'getfield_gc_i_pure'
- assert len(op2.args) == 2
- assert op2.args[0] == v_x
- assert op2.args[1] == ('fielddescr', STRUCT, 'inst_x')
- assert op2.result is op.result
- def test_quasi_immutable_setfield():
- from rpython.rtyper.rclass import FieldListAccessor, IR_QUASIIMMUTABLE
- accessor = FieldListAccessor()
- accessor.initialize(None, {'inst_x': IR_QUASIIMMUTABLE})
- v1 = varoftype(lltype.Signed)
- STRUCT = lltype.GcStruct('struct', ('inst_x', lltype.Signed),
- ('mutate_x', rclass.OBJECTPTR),
- hints={'immutable_fields': accessor})
- for v_x in [const(lltype.malloc(STRUCT)), varoftype(lltype.Ptr(STRUCT))]:
- op = SpaceOperation('jit_force_quasi_immutable',
- [v_x, Constant('mutate_x', lltype.Void)],
- varoftype(lltype.Void))
- tr = Transformer(FakeCPU(), FakeRegularCallControl())
- tr.graph = 'currentgraph'
- op0, op1 = tr.rewrite_operation(op)
- assert op0.opname == '-live-'
- assert op1.opname == 'jit_force_quasi_immutable'
- assert op1.args[0] == v_x
- assert op1.args[1] == ('fielddescr', STRUCT, 'mutate_x')
- def test_no_gcstruct_nesting_outside_of_OBJECT():
- PARENT = lltype.GcStruct('parent')
- STRUCT = lltype.GcStruct('struct', ('parent', PARENT),
- ('x', lltype.Signed))
- v_x = varoftype(lltype.Ptr(STRUCT))
- op = SpaceOperation('getfield', [v_x, Constant('x', lltype.Void)],
- varoftype(lltype.Signed))
- tr = Transformer(None, None)
- py.test.raises(NotImplementedError, tr.rewrite_operation, op)
- def test_no_fixedsizearray():
- A = lltype.FixedSizeArray(lltype.Signed, 5)
- v_x = varoftype(lltype.Ptr(A))
- op = SpaceOperation('getarrayitem', [v_x, Constant(0, lltype.Signed)],
- varoftype(lltype.Signed))
- tr = Transformer(None, None)
- tr.graph = 'demo'
- py.test.raises(NotImplementedError, tr.rewrite_operation, op)
- op = SpaceOperation('setarrayitem', [v_x, Constant(0, lltype.Signed),
- Constant(42, lltype.Signed)],
- varoftype(lltype.Void))
- e = py.test.raises(NotImplementedError, tr.rewrite_operation, op)
- assert str(e.value) == (
- "'demo' uses %r, which is not supported by the JIT codewriter" % (A,))
- def _test_threadlocalref_get(loop_inv):
- from rpython.rlib.rthread import ThreadLocalField
- tlfield = ThreadLocalField(lltype.Signed, 'foobar_test_',
- loop_invariant=loop_inv)
- OS_THREADLOCALREF_GET = effectinfo.EffectInfo.OS_THREADLOCALREF_GET
- c = const(tlfield.getoffset())
- v = varoftype(lltype.Signed)
- op = SpaceOperation('threadlocalref_get', [c], v)
- cc = FakeBuiltinCallControl()
- cc.expected_effect_of_threadlocalref_get = (
- effectinfo.EffectInfo.EF_LOOPINVARIANT if loop_inv
- else effectinfo.EffectInfo.EF_CANNOT_RAISE)
- tr = Transformer(FakeCPU(), cc)
- op0 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_ir_i'
- assert op0.args[0].value == 'threadlocalref_get' # pseudo-function as str
- assert op0.args[1] == ListOfKind("int", [c])
- assert op0.args[2] == ListOfKind("ref", [])
- assert op0.args[3] == 'calldescr-%d' % OS_THREADLOCALREF_GET
- assert op0.result == v
- def test_threadlocalref_get_no_loop_inv():
- _test_threadlocalref_get(loop_inv=False)
- def test_threadlocalref_get_with_loop_inv():
- _test_threadlocalref_get(loop_inv=True)
- def test_unknown_operation():
- op = SpaceOperation('foobar', [], varoftype(lltype.Void))
- tr = Transformer()
- try:
- tr.rewrite_operation(op)
- except Exception as e:
- assert 'foobar' in str(e)
- def test_likely_unlikely():
- v1 = varoftype(lltype.Bool)
- v2 = varoftype(lltype.Bool)
- op = SpaceOperation('likely', [v1], v2)
- tr = Transformer()
- assert tr.rewrite_operation(op) is None
- op = SpaceOperation('unlikely', [v1], v2)
- assert tr.rewrite_operation(op) is None