PageRenderTime 63ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/jit/backend/test/test_random.py

https://bitbucket.org/pypy/pypy/
Python | 995 lines | 925 code | 42 blank | 28 comment | 141 complexity | 749636901ed3d8f95f4d44988720beba MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. import pytest
  3. from rpython.rlib.rarithmetic import intmask, LONG_BIT
  4. from rpython.jit.metainterp.history import BasicFailDescr, TreeLoop, BasicFinalDescr
  5. from rpython.jit.metainterp.history import INT, ConstInt, JitCellToken
  6. from rpython.jit.metainterp.history import REF, ConstPtr, TargetToken
  7. from rpython.jit.metainterp.history import FLOAT, ConstFloat, Const, VOID
  8. from rpython.jit.metainterp.resoperation import ResOperation, rop
  9. from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef
  10. from rpython.jit.metainterp.resoperation import InputArgFloat
  11. from rpython.jit.metainterp.executor import _execute_arglist, wrap_constant
  12. from rpython.jit.metainterp.resoperation import opname
  13. from rpython.jit.codewriter import longlong
  14. from rpython.rtyper.lltypesystem import lltype, llmemory, rstr
  15. from rpython.rtyper import rclass
  16. class DummyLoop(object):
  17. def __init__(self, subops):
  18. self.operations = subops
  19. class FakeMetaInterp(object):
  20. ovf_flag = False
  21. def execute_raised(self, exc, constant=False):
  22. self._got_exc = exc
  23. def getint(v):
  24. if isinstance(v, (ConstInt, InputArgInt)):
  25. return v.getint()
  26. else:
  27. return v._example_int
  28. def getfloatstorage(v):
  29. if isinstance(v, (ConstFloat, InputArgFloat)):
  30. return v.getfloatstorage()
  31. else:
  32. return v._example_float
  33. def getfloat(v):
  34. return longlong.getrealfloat(getfloatstorage(v))
  35. def getref_base(v):
  36. if isinstance(v, (ConstPtr, InputArgRef)):
  37. return v.getref_base()
  38. else:
  39. return v._example_ref
  40. def getref(PTR, v):
  41. return lltype.cast_opaque_ptr(PTR, getref_base(v))
  42. def constbox(v):
  43. if v.type == INT:
  44. return ConstInt(getint(v))
  45. if v.type == FLOAT:
  46. return ConstFloat(getfloatstorage(v))
  47. if v.type == REF:
  48. return ConstPtr(getref_base(v))
  49. assert 0, v.type
  50. class OperationBuilder(object):
  51. def __init__(self, cpu, loop, vars):
  52. self.cpu = cpu
  53. if not hasattr(cpu, '_faildescr_keepalive'):
  54. cpu._faildescr_keepalive = []
  55. self.fakemetainterp = FakeMetaInterp()
  56. self.loop = loop
  57. self.intvars = [box for box in vars if box.type == INT]
  58. self.boolvars = [] # subset of self.intvars
  59. self.ptrvars = []
  60. self.prebuilt_ptr_consts = []
  61. floatvars = [box for box in vars if box.type == FLOAT]
  62. if cpu.supports_floats:
  63. self.floatvars = floatvars
  64. else:
  65. assert floatvars == []
  66. self.should_fail_by = None
  67. self.counter = 0
  68. assert len(self.intvars) == len(dict.fromkeys(self.intvars))
  69. self.descr_counters = {}
  70. def fork(self, cpu, loop, vars):
  71. fork = self.__class__(cpu, loop, vars)
  72. fork.prebuilt_ptr_consts = self.prebuilt_ptr_consts
  73. fork.descr_counters = self.descr_counters
  74. return fork
  75. def do(self, opnum, argboxes, descr=None):
  76. self.fakemetainterp._got_exc = None
  77. op = ResOperation(opnum, argboxes, descr)
  78. argboxes = map(constbox, argboxes)
  79. result = _execute_arglist(self.cpu, self.fakemetainterp,
  80. opnum, argboxes, descr)
  81. if result is not None:
  82. if lltype.typeOf(result) == lltype.Signed:
  83. op._example_int = result
  84. elif isinstance(result, bool):
  85. op._example_int = int(result)
  86. elif lltype.typeOf(result) == longlong.FLOATSTORAGE:
  87. op._example_float = result
  88. elif isinstance(result, float):
  89. op._example_float = longlong.getfloatstorage(result)
  90. else:
  91. assert lltype.typeOf(result) == llmemory.GCREF
  92. op._example_ref = result
  93. self.loop.operations.append(op)
  94. return op
  95. def get_bool_var(self, r):
  96. if self.boolvars and r.random() < 0.8:
  97. return r.choice(self.boolvars)
  98. elif self.ptrvars and r.random() < 0.4:
  99. v, S = r.choice(self.ptrvars + self.prebuilt_ptr_consts)[:2]
  100. v2, S2 = r.choice(self.ptrvars + self.prebuilt_ptr_consts)[:2]
  101. if S == S2 and not (isinstance(v, ConstPtr) and
  102. isinstance(v2, ConstPtr)):
  103. if r.random() < 0.5:
  104. return self.do(rop.PTR_EQ, [v, v2])
  105. else:
  106. return self.do(rop.PTR_NE, [v, v2])
  107. v = r.choice(self.intvars)
  108. if r.random() < 0.7:
  109. return self.do(rop.INT_IS_TRUE, [v])
  110. else:
  111. return self.do(rop.INT_IS_ZERO, [v])
  112. def subset_of_intvars(self, r):
  113. subset = []
  114. k = r.random()
  115. num = int(k * len(self.intvars))
  116. seen = {}
  117. for i in range(num):
  118. v = r.choice(self.intvars)
  119. if v not in seen:
  120. subset.append(v)
  121. seen[v] = True
  122. return subset
  123. def process_operation(self, s, op, names):
  124. args = []
  125. for v in op.getarglist():
  126. if v in names:
  127. args.append(names[v])
  128. elif isinstance(v, ConstPtr):
  129. assert not getref_base(v) # otherwise should be in the names
  130. args.append('ConstPtr(lltype.nullptr(llmemory.GCREF.TO))')
  131. elif isinstance(v, ConstFloat):
  132. args.append('ConstFloat(longlong.getfloatstorage(%r))'
  133. % v.getfloat())
  134. elif isinstance(v, ConstInt):
  135. args.append('ConstInt(%s)' % v.getint())
  136. else:
  137. raise NotImplementedError(v)
  138. if op.getdescr() is None:
  139. descrstr = ''
  140. else:
  141. try:
  142. descrstr = ', ' + getattr(op.getdescr(), '_random_info')
  143. except AttributeError:
  144. if op.opnum == rop.LABEL:
  145. descrstr = ', TargetToken()'
  146. else:
  147. descrstr = ', descr=' + self.descr_counters.get(op.getdescr(), '...')
  148. print >>s, ' %s = ResOperation(rop.%s, [%s]%s),' % (
  149. names[op], opname[op.getopnum()], ', '.join(args), descrstr)
  150. def print_loop(self, output, fail_descr=None, fail_args=None):
  151. def update_names(ops):
  152. for op in ops:
  153. v = op
  154. if v not in names:
  155. writevar(v, 'tmp')
  156. if op.is_guard() or op.opnum == rop.FINISH:
  157. descr = op.getdescr()
  158. no = len(self.descr_counters)
  159. if op.is_guard():
  160. name = 'faildescr%d' % no
  161. clsname = 'BasicFailDescr'
  162. else:
  163. name = 'finishdescr%d' % no
  164. clsname = 'BasicFinalDescr'
  165. self.descr_counters[descr] = name
  166. print >>s, " %s = %s()" % (name, clsname)
  167. def print_loop_prebuilt(ops):
  168. for op in ops:
  169. for arg in op.getarglist():
  170. if isinstance(arg, ConstPtr):
  171. if arg not in names:
  172. writevar(arg, 'const_ptr')
  173. def type_descr(TP):
  174. if TP in TYPE_NAMES:
  175. return TYPE_NAMES[TP]
  176. elif isinstance(TP, lltype.Primitive):
  177. return _type_descr(TP) # don't cache
  178. else:
  179. descr = _type_descr(TP)
  180. no = len(TYPE_NAMES)
  181. tp_name = 'S' + str(no)
  182. TYPE_NAMES[TP] = tp_name
  183. print >>s, ' %s = %s' % (tp_name, descr)
  184. return tp_name
  185. def _type_descr(TP):
  186. if isinstance(TP, lltype.Ptr):
  187. return "lltype.Ptr(%s)" % type_descr(TP.TO)
  188. if isinstance(TP, lltype.Struct):
  189. if TP._gckind == 'gc':
  190. pref = 'Gc'
  191. else:
  192. pref = ''
  193. fields = []
  194. for k in TP._names:
  195. v = getattr(TP, k)
  196. fields.append('("%s", %s)' % (k, type_descr(v)))
  197. return "lltype.%sStruct('Sx', %s)" % (pref,
  198. ", ".join(fields))
  199. elif isinstance(TP, lltype.GcArray):
  200. return "lltype.GcArray(%s)" % (type_descr(TP.OF),)
  201. if TP._name.upper() == TP._name:
  202. return 'rffi.%s' % TP._name
  203. return 'lltype.%s' % TP._name
  204. s = output
  205. names = {None: 'None'}
  206. TYPE_NAMES = {
  207. rstr.STR: 'rstr.STR',
  208. rstr.UNICODE: 'rstr.UNICODE',
  209. rclass.OBJECT: 'rclass.OBJECT',
  210. rclass.OBJECT_VTABLE: 'rclass.OBJECT_VTABLE',
  211. }
  212. for op in self.loop.operations:
  213. descr = op.getdescr()
  214. if hasattr(descr, '_random_info'):
  215. tp_name = type_descr(descr._random_type)
  216. descr._random_info = descr._random_info.replace('...', tp_name)
  217. #
  218. def writevar(v, nameprefix, init=''):
  219. if nameprefix == 'const_ptr':
  220. if not getref_base(v):
  221. return 'lltype.nullptr(llmemory.GCREF.TO)'
  222. TYPE = getref_base(v)._obj.ORIGTYPE
  223. cont = lltype.cast_opaque_ptr(TYPE, getref_base(v))
  224. if TYPE.TO._is_varsize():
  225. if isinstance(TYPE.TO, lltype.GcStruct):
  226. lgt = len(cont.chars)
  227. else:
  228. lgt = len(cont)
  229. init = 'lltype.malloc(%s, %d)' % (TYPE_NAMES[TYPE.TO],
  230. lgt)
  231. else:
  232. init = 'lltype.malloc(%s)' % TYPE_NAMES[TYPE.TO]
  233. init = 'lltype.cast_opaque_ptr(llmemory.GCREF, %s)' % init
  234. names[v] = '%s%d' % (nameprefix, len(names))
  235. print >>s, ' %s = %s(%s)' % (names[v], v.__class__.__name__,
  236. init)
  237. #
  238. for v in self.intvars:
  239. writevar(v, 'v')
  240. for v in self.floatvars:
  241. writevar(v, 'f')
  242. for v, S in self.ptrvars:
  243. writevar(v, 'p')
  244. update_names(self.loop.operations)
  245. print_loop_prebuilt(self.loop.operations)
  246. #
  247. if fail_descr is None:
  248. print >>s, ' cpu = CPU(None, None)'
  249. print >>s, ' cpu.setup_once()'
  250. if hasattr(self.loop, 'inputargs'):
  251. print >>s, ' inputargs = [%s]' % (
  252. ', '.join([names[v] for v in self.loop.inputargs]))
  253. else:
  254. print >>s, ' inputargs = [%s]' % (
  255. ', '.join([names[v] for v in fail_args]))
  256. print >>s, ' operations = ['
  257. for op in self.loop.operations:
  258. self.process_operation(s, op, names)
  259. print >>s, ' ]'
  260. for i, op in enumerate(self.loop.operations):
  261. if op.is_guard():
  262. fa = ", ".join([names[v] for v in op.getfailargs()])
  263. print >>s, ' operations[%d].setfailargs([%s])' % (i, fa)
  264. if fail_descr is None:
  265. print >>s, ' looptoken = JitCellToken()'
  266. print >>s, ' cpu.compile_loop(inputargs, operations, looptoken)'
  267. else:
  268. print >>s, ' cpu.compile_bridge(%s, inputargs, operations, looptoken)' % self.descr_counters[fail_descr]
  269. if hasattr(self.loop, 'inputargs'):
  270. vals = []
  271. for i, v in enumerate(self.loop.inputargs):
  272. assert not isinstance(v, Const)
  273. if v.type == FLOAT:
  274. vals.append("longlong.getfloatstorage(%r)" % getfloat(v))
  275. else:
  276. vals.append("%r" % getint(v))
  277. print >>s, ' loop_args = [%s]' % ", ".join(vals)
  278. print >>s, ' frame = cpu.execute_token(looptoken, *loop_args)'
  279. if self.should_fail_by is None:
  280. fail_args = self.loop.operations[-1].getarglist()
  281. else:
  282. fail_args = self.should_fail_by.getfailargs()
  283. for i, v in enumerate(fail_args):
  284. if v.type == FLOAT:
  285. print >>s, (' assert longlong.getrealfloat('
  286. 'cpu.get_float_value(frame, %d)) == %r' % (i, getfloatstorage(v)))
  287. else:
  288. print >>s, (' assert cpu.get_int_value(frame, %d) == %d'
  289. % (i, getint(v)))
  290. self.names = names
  291. s.flush()
  292. def getfaildescr(self, is_finish=False):
  293. if is_finish:
  294. descr = BasicFinalDescr()
  295. else:
  296. descr = BasicFailDescr()
  297. self.cpu._faildescr_keepalive.append(descr)
  298. return descr
  299. class CannotProduceOperation(Exception):
  300. pass
  301. class AbstractOperation(object):
  302. def __init__(self, opnum, boolres=False):
  303. self.opnum = opnum
  304. self.boolres = boolres
  305. def filter(self, builder):
  306. pass
  307. def put(self, builder, args, descr=None):
  308. v_result = builder.do(self.opnum, args, descr=descr)
  309. if v_result is not None:
  310. if v_result.type == INT:
  311. builder.intvars.append(v_result)
  312. boolres = self.boolres
  313. if boolres == 'sometimes':
  314. boolres = getint(v_result) in [0, 1]
  315. if boolres:
  316. builder.boolvars.append(v_result)
  317. elif v_result.type == FLOAT:
  318. builder.floatvars.append(v_result)
  319. assert self.boolres != True
  320. elif v_result.type == VOID:
  321. assert self.boolres != True
  322. else:
  323. raise NotImplementedError(v_result)
  324. class UnaryOperation(AbstractOperation):
  325. def produce_into(self, builder, r):
  326. self.put(builder, [r.choice(builder.intvars)])
  327. class BooleanUnaryOperation(UnaryOperation):
  328. def produce_into(self, builder, r):
  329. v = builder.get_bool_var(r)
  330. self.put(builder, [v])
  331. class ConstUnaryOperation(UnaryOperation):
  332. def produce_into(self, builder, r):
  333. if r.random() < 0.4:
  334. UnaryOperation.produce_into(self, builder, r)
  335. else:
  336. self.put(builder, [ConstInt(r.random_integer())])
  337. class SignExtOperation(AbstractOperation):
  338. def produce_into(self, builder, r):
  339. sizes = [1, 2]
  340. if sys.maxint > (1 << 32):
  341. sizes.append(4)
  342. self.put(builder, [r.choice(builder.intvars),
  343. ConstInt(r.choice(sizes))])
  344. class BinaryOperation(AbstractOperation):
  345. def __init__(self, opnum, and_mask=-1, or_mask=0, boolres=False):
  346. AbstractOperation.__init__(self, opnum, boolres=boolres)
  347. self.and_mask = and_mask
  348. self.or_mask = or_mask
  349. def produce_into(self, builder, r):
  350. k = r.random()
  351. if k < 0.2:
  352. v_first = ConstInt(r.random_integer())
  353. else:
  354. v_first = r.choice(builder.intvars)
  355. if k > 0.75:
  356. value = r.random_integer()
  357. v_second = ConstInt((value & self.and_mask) | self.or_mask)
  358. else:
  359. v = r.choice(builder.intvars)
  360. v_value = getint(v)
  361. if (v_value & self.and_mask) != v_value:
  362. v = builder.do(rop.INT_AND, [v, ConstInt(self.and_mask)])
  363. v_value = getint(v)
  364. if (v_value | self.or_mask) != v_value:
  365. v = builder.do(rop.INT_OR, [v, ConstInt(self.or_mask)])
  366. v_second = v
  367. self.put(builder, [v_first, v_second])
  368. class AbstractOvfOperation(AbstractOperation):
  369. def produce_into(self, builder, r):
  370. fail_subset = builder.subset_of_intvars(r)
  371. original_intvars = builder.intvars[:]
  372. builder.fakemetainterp.ovf_flag = False
  373. super(AbstractOvfOperation, self).produce_into(builder, r)
  374. if builder.fakemetainterp.ovf_flag: # overflow detected
  375. op = ResOperation(rop.GUARD_OVERFLOW, [])
  376. # the overflowed result should not be used any more, but can
  377. # be used on the failure path: recompute fail_subset including
  378. # the result, and then remove it from builder.intvars.
  379. fail_subset = builder.subset_of_intvars(r)
  380. builder.intvars[:] = original_intvars
  381. else:
  382. op = ResOperation(rop.GUARD_NO_OVERFLOW, [])
  383. op.setdescr(builder.getfaildescr())
  384. op.setfailargs(fail_subset)
  385. builder.loop.operations.append(op)
  386. class BinaryOvfOperation(AbstractOvfOperation, BinaryOperation):
  387. pass
  388. class AbstractFloatOperation(AbstractOperation):
  389. def filter(self, builder):
  390. if not builder.cpu.supports_floats:
  391. raise CannotProduceOperation
  392. class BinaryFloatOperation(AbstractFloatOperation):
  393. def produce_into(self, builder, r):
  394. if not builder.floatvars:
  395. raise CannotProduceOperation
  396. k = r.random()
  397. if k < 0.18:
  398. v_first = ConstFloat(r.random_float_storage())
  399. else:
  400. v_first = r.choice(builder.floatvars)
  401. if k > 0.82:
  402. v_second = ConstFloat(r.random_float_storage())
  403. else:
  404. v_second = r.choice(builder.floatvars)
  405. if abs(getfloat(v_first)) > 1E100 or abs(getfloat(v_second)) > 1E100:
  406. raise CannotProduceOperation # avoid infinities
  407. if abs(getfloat(v_second)) < 1E-100:
  408. raise CannotProduceOperation # e.g. division by zero error
  409. self.put(builder, [v_first, v_second])
  410. class UnaryFloatOperation(AbstractFloatOperation):
  411. def produce_into(self, builder, r):
  412. if not builder.floatvars:
  413. raise CannotProduceOperation
  414. self.put(builder, [r.choice(builder.floatvars)])
  415. class ConstUnaryFloatOperation(UnaryFloatOperation):
  416. def produce_into(self, builder, r):
  417. if r.random() < 0.4:
  418. UnaryFloatOperation.produce_into(self, builder, r)
  419. else:
  420. self.put(builder, [ConstFloat(r.random_float_storage())])
  421. class CastIntToFloatOperation(AbstractFloatOperation):
  422. def produce_into(self, builder, r):
  423. self.put(builder, [r.choice(builder.intvars)])
  424. class CastLongLongToFloatOperation(AbstractFloatOperation):
  425. def produce_into(self, builder, r):
  426. if longlong.is_64_bit:
  427. self.put(builder, [r.choice(builder.intvars)])
  428. else:
  429. if not builder.floatvars:
  430. raise CannotProduceOperation
  431. self.put(builder, [r.choice(builder.floatvars)])
  432. class CastFloatToIntOperation(AbstractFloatOperation):
  433. def produce_into(self, builder, r):
  434. if not builder.floatvars:
  435. raise CannotProduceOperation
  436. box = r.choice(builder.floatvars)
  437. if not (-sys.maxint-1 <= getfloat(box) <= sys.maxint):
  438. raise CannotProduceOperation # would give an overflow
  439. self.put(builder, [box])
  440. class GuardOperation(AbstractOperation):
  441. def gen_guard(self, builder, r):
  442. v = builder.get_bool_var(r)
  443. op = ResOperation(self.opnum, [v])
  444. passing = ((self.opnum == rop.GUARD_TRUE and getint(v)) or
  445. (self.opnum == rop.GUARD_FALSE and not getint(v)))
  446. return op, passing
  447. def produce_into(self, builder, r):
  448. op, passing = self.gen_guard(builder, r)
  449. builder.loop.operations.append(op)
  450. op.setdescr(builder.getfaildescr())
  451. op.setfailargs(builder.subset_of_intvars(r))
  452. if not passing:
  453. builder.should_fail_by = op
  454. builder.guard_op = op
  455. class GuardPtrOperation(GuardOperation):
  456. def gen_guard(self, builder, r):
  457. if not builder.ptrvars:
  458. raise CannotProduceOperation
  459. box = r.choice(builder.ptrvars)[0]
  460. op = ResOperation(self.opnum, [box])
  461. passing = ((self.opnum == rop.GUARD_NONNULL and getref_base(box)) or
  462. (self.opnum == rop.GUARD_ISNULL and not getref_base(box)))
  463. return op, passing
  464. class GuardValueOperation(GuardOperation):
  465. def gen_guard(self, builder, r):
  466. v = r.choice(builder.intvars)
  467. if r.random() > 0.8:
  468. other = r.choice(builder.intvars)
  469. else:
  470. if r.random() < 0.75:
  471. value = getint(v)
  472. elif r.random() < 0.5:
  473. value = getint(v) ^ 1
  474. else:
  475. value = r.random_integer()
  476. other = ConstInt(value)
  477. op = ResOperation(self.opnum, [v, other])
  478. return op, (getint(v) == getint(other))
  479. # ____________________________________________________________
  480. OPERATIONS = []
  481. for _op in [rop.INT_ADD,
  482. rop.INT_SUB,
  483. rop.INT_MUL,
  484. rop.INT_AND,
  485. rop.INT_OR,
  486. rop.INT_XOR,
  487. rop.UINT_MUL_HIGH,
  488. ]:
  489. OPERATIONS.append(BinaryOperation(_op))
  490. for _op in [rop.INT_LT,
  491. rop.INT_LE,
  492. rop.INT_EQ,
  493. rop.INT_NE,
  494. rop.INT_GT,
  495. rop.INT_GE,
  496. rop.UINT_LT,
  497. rop.UINT_LE,
  498. rop.UINT_GT,
  499. rop.UINT_GE,
  500. ]:
  501. OPERATIONS.append(BinaryOperation(_op, boolres=True))
  502. #OPERATIONS.append(BinaryOperation(rop.INT_FLOORDIV, ~3, 2))
  503. #OPERATIONS.append(BinaryOperation(rop.INT_MOD, ~3, 2))
  504. OPERATIONS.append(BinaryOperation(rop.INT_RSHIFT, LONG_BIT-1))
  505. OPERATIONS.append(BinaryOperation(rop.INT_LSHIFT, LONG_BIT-1))
  506. OPERATIONS.append(BinaryOperation(rop.UINT_RSHIFT, LONG_BIT-1))
  507. OPERATIONS.append(GuardOperation(rop.GUARD_TRUE))
  508. OPERATIONS.append(GuardOperation(rop.GUARD_TRUE))
  509. OPERATIONS.append(GuardOperation(rop.GUARD_FALSE))
  510. OPERATIONS.append(GuardOperation(rop.GUARD_FALSE))
  511. OPERATIONS.append(GuardPtrOperation(rop.GUARD_NONNULL))
  512. OPERATIONS.append(GuardPtrOperation(rop.GUARD_ISNULL))
  513. OPERATIONS.append(GuardValueOperation(rop.GUARD_VALUE))
  514. for _op in [rop.INT_NEG,
  515. rop.INT_INVERT,
  516. ]:
  517. OPERATIONS.append(UnaryOperation(_op))
  518. OPERATIONS.append(UnaryOperation(rop.INT_IS_TRUE, boolres=True))
  519. OPERATIONS.append(UnaryOperation(rop.INT_IS_ZERO, boolres=True))
  520. OPERATIONS.append(ConstUnaryOperation(rop.SAME_AS_I, boolres='sometimes'))
  521. OPERATIONS.append(ConstUnaryFloatOperation(rop.SAME_AS_F))
  522. OPERATIONS.append(SignExtOperation(rop.INT_SIGNEXT))
  523. for _op in [rop.INT_ADD_OVF,
  524. rop.INT_SUB_OVF,
  525. rop.INT_MUL_OVF,
  526. ]:
  527. OPERATIONS.append(BinaryOvfOperation(_op))
  528. for _op in [rop.FLOAT_ADD,
  529. rop.FLOAT_SUB,
  530. rop.FLOAT_MUL,
  531. rop.FLOAT_TRUEDIV,
  532. ]:
  533. OPERATIONS.append(BinaryFloatOperation(_op))
  534. for _op in [rop.FLOAT_NEG,
  535. rop.FLOAT_ABS,
  536. ]:
  537. OPERATIONS.append(UnaryFloatOperation(_op))
  538. OPERATIONS.append(CastFloatToIntOperation(rop.CAST_FLOAT_TO_INT))
  539. OPERATIONS.append(CastIntToFloatOperation(rop.CAST_INT_TO_FLOAT))
  540. OPERATIONS.append(CastFloatToIntOperation(rop.CONVERT_FLOAT_BYTES_TO_LONGLONG))
  541. OPERATIONS.append(CastLongLongToFloatOperation(rop.CONVERT_LONGLONG_BYTES_TO_FLOAT))
  542. OperationBuilder.OPERATIONS = OPERATIONS
  543. # ____________________________________________________________
  544. def do_assert(condition, error_message):
  545. if condition:
  546. return
  547. seed = pytest.config.option.randomseed
  548. message = "%s\nPython: %s\nRandom seed: %r" % (
  549. error_message,
  550. sys.executable,
  551. seed)
  552. raise AssertionError(message)
  553. def Random():
  554. import random
  555. seed = pytest.config.option.randomseed
  556. print
  557. print 'Random seed value is %d.' % (seed,)
  558. print
  559. r = random.Random(seed)
  560. def get_random_integer():
  561. while True:
  562. result = int(r.expovariate(0.05))
  563. if result <= sys.maxint:
  564. break
  565. if r.randrange(0, 5) <= 1:
  566. result = -result
  567. if result not in (0, -1) and r.random() < 0.1:
  568. # occasionally produce a very large integer. The algo is such
  569. # that it's likely we get a special value, e.g. sys.maxint or
  570. # -sys.maxint-1.
  571. while intmask(result << 2) == (result << 2):
  572. result = (result << 2) | (result & 0x3)
  573. return result
  574. def get_random_char():
  575. return chr(get_random_integer() % 256)
  576. def get_random_float():
  577. x = float(get_random_integer())
  578. k = r.random() * 1.2
  579. if k < 1.0:
  580. x += k
  581. return x
  582. def get_random_float_storage():
  583. x = get_random_float()
  584. return longlong.getfloatstorage(x)
  585. r.random_integer = get_random_integer
  586. r.random_char = get_random_char
  587. r.random_float = get_random_float
  588. r.random_float_storage = get_random_float_storage
  589. return r
  590. def get_cpu():
  591. if pytest.config.option.backend == 'llgraph':
  592. from rpython.jit.backend.llgraph.runner import LLGraphCPU
  593. return LLGraphCPU(None)
  594. elif pytest.config.option.backend == 'cpu':
  595. from rpython.jit.backend.detect_cpu import getcpuclass
  596. return getcpuclass()(None, None)
  597. else:
  598. assert 0, "unknown backend %r" % pytest.config.option.backend
  599. # ____________________________________________________________
  600. class RandomLoop(object):
  601. dont_generate_more = False
  602. def __init__(self, cpu, builder_factory, r, startvars=None, output=None):
  603. self.cpu = cpu
  604. self.output = output
  605. if startvars is None:
  606. startvars = []
  607. if cpu.supports_floats:
  608. # pick up a single threshold for the whole 'inputargs', so
  609. # that some loops have no or mostly no FLOATs while others
  610. # have a lot of them
  611. k = r.random()
  612. # but make sure there is at least one INT
  613. at_least_once = r.randrange(0, pytest.config.option.n_vars)
  614. else:
  615. k = -1
  616. at_least_once = 0
  617. for i in range(pytest.config.option.n_vars):
  618. if r.random() < k and i != at_least_once:
  619. startvars.append(InputArgFloat(r.random_float_storage()))
  620. else:
  621. startvars.append(InputArgInt(r.random_integer()))
  622. allow_delay = True
  623. else:
  624. allow_delay = False
  625. assert len(dict.fromkeys(startvars)) == len(startvars)
  626. self.startvars = startvars
  627. self.prebuilt_ptr_consts = []
  628. self.r = r
  629. self.subloops = []
  630. self.build_random_loop(cpu, builder_factory, r, startvars, allow_delay)
  631. def build_random_loop(self, cpu, builder_factory, r, startvars,
  632. allow_delay):
  633. loop = TreeLoop('test_random_function')
  634. loop.inputargs = startvars[:]
  635. loop.operations = []
  636. loop._jitcelltoken = JitCellToken()
  637. builder = builder_factory(cpu, loop, startvars[:])
  638. if allow_delay:
  639. needs_a_label = True
  640. else:
  641. self.insert_label(loop, 0, r)
  642. needs_a_label = False
  643. self.generate_ops(builder, r, loop, startvars, needs_a_label=needs_a_label)
  644. self.builder = builder
  645. self.loop = loop
  646. dump(loop)
  647. cpu.compile_loop(loop.inputargs, loop.operations, loop._jitcelltoken)
  648. if self.output:
  649. builder.print_loop(self.output)
  650. def insert_label(self, loop, position, r):
  651. assert not hasattr(loop, '_targettoken')
  652. for i in range(position):
  653. op = loop.operations[i]
  654. if (not rop.has_no_side_effect(op.opnum)
  655. or op.type not in (INT, FLOAT)):
  656. position = i
  657. break # cannot move the LABEL later
  658. randompos = r.randrange(0, len(self.startvars)+1)
  659. self.startvars.insert(randompos, op)
  660. loop._targettoken = TargetToken()
  661. loop.operations.insert(position, ResOperation(rop.LABEL, self.startvars,
  662. loop._targettoken))
  663. def generate_ops(self, builder, r, loop, startvars, needs_a_label=False):
  664. block_length = pytest.config.option.block_length
  665. istart = 0
  666. for i in range(block_length):
  667. istart = len(loop.operations)
  668. try:
  669. op = r.choice(builder.OPERATIONS)
  670. op.filter(builder)
  671. op.produce_into(builder, r)
  672. except CannotProduceOperation:
  673. pass
  674. if builder.should_fail_by is not None:
  675. break
  676. if needs_a_label and r.random() < 0.2:
  677. self.insert_label(loop, istart, r)
  678. needs_a_label = False
  679. if needs_a_label:
  680. self.insert_label(loop, istart, r)
  681. endvars = []
  682. used_later = {}
  683. for op in loop.operations:
  684. for v in op.getarglist():
  685. used_later[v] = True
  686. for v in startvars:
  687. if v not in used_later:
  688. endvars.append(v)
  689. r.shuffle(endvars)
  690. endvars = endvars[:1]
  691. loop.operations.append(ResOperation(rop.FINISH, endvars,
  692. descr=builder.getfaildescr(is_finish=True)))
  693. if builder.should_fail_by:
  694. self.should_fail_by = builder.should_fail_by
  695. self.guard_op = builder.guard_op
  696. else:
  697. self.should_fail_by = loop.operations[-1]
  698. self.guard_op = None
  699. self.prebuilt_ptr_consts.extend(builder.prebuilt_ptr_consts)
  700. endvars = self.get_fail_args()
  701. self.expected = {}
  702. for v in endvars:
  703. if v.type == INT:
  704. self.expected[v] = getint(v)
  705. elif v.type == FLOAT:
  706. self.expected[v] = getfloatstorage(v)
  707. else:
  708. assert 0, v.type
  709. def runjitcelltoken(self):
  710. if self.startvars == self.loop.inputargs:
  711. return self.loop._jitcelltoken
  712. if not hasattr(self, '_initialjumploop_celltoken'):
  713. self._initialjumploop_celltoken = JitCellToken()
  714. args = []
  715. for box in self.startvars:
  716. if box not in self.loop.inputargs:
  717. box = constbox(box)
  718. args.append(box)
  719. self.cpu.compile_loop(self.loop.inputargs,
  720. [ResOperation(rop.JUMP, args,
  721. descr=self.loop._targettoken)],
  722. self._initialjumploop_celltoken)
  723. return self._initialjumploop_celltoken
  724. def get_fail_args(self):
  725. if self.should_fail_by.is_guard():
  726. assert self.should_fail_by.getfailargs() is not None
  727. return self.should_fail_by.getfailargs()
  728. else:
  729. assert self.should_fail_by.getopnum() == rop.FINISH
  730. return self.should_fail_by.getarglist()
  731. def clear_state(self):
  732. for v, S, fields in self.prebuilt_ptr_consts:
  733. container = getref_base(v)._obj.container
  734. for name, value in fields.items():
  735. if isinstance(name, str):
  736. setattr(container, name, value)
  737. elif isinstance(value, dict):
  738. item = container.getitem(name)
  739. for key1, value1 in value.items():
  740. setattr(item, key1, value1)
  741. else:
  742. container.setitem(name, value)
  743. def run_loop(self):
  744. cpu = self.builder.cpu
  745. self.clear_state()
  746. # disable check for now
  747. # exc = cpu.grab_exc_value()
  748. # assert not exc
  749. arguments = []
  750. for box in self.loop.inputargs:
  751. if box.type == INT:
  752. arguments.append(getint(box))
  753. elif box.type == FLOAT:
  754. arguments.append(getfloatstorage(box))
  755. else:
  756. assert 0, box.type
  757. deadframe = cpu.execute_token(self.runjitcelltoken(), *arguments)
  758. fail = cpu.get_latest_descr(deadframe)
  759. do_assert(fail is self.should_fail_by.getdescr(),
  760. "Got %r, expected %r" % (fail,
  761. self.should_fail_by.getdescr()))
  762. for i, v in enumerate(self.get_fail_args()):
  763. if v not in self.expected:
  764. assert v.getopnum() == rop.SAME_AS_I # special case
  765. assert isinstance(v.getarg(0), ConstInt)
  766. self.expected[v] = getint(v.getarg(0))
  767. if v.type == FLOAT:
  768. value = cpu.get_float_value(deadframe, i)
  769. else:
  770. value = cpu.get_int_value(deadframe, i)
  771. do_assert(value == self.expected[v],
  772. "Got %r, expected %r for value #%d" % (value,
  773. self.expected[v],
  774. i)
  775. )
  776. exc = cpu.grab_exc_value(deadframe)
  777. if (self.guard_op is not None and
  778. rop.is_guard_exception(self.guard_op.getopnum())):
  779. if self.guard_op.getopnum() == rop.GUARD_NO_EXCEPTION:
  780. do_assert(exc,
  781. "grab_exc_value() should not be %r" % (exc,))
  782. else:
  783. do_assert(not exc,
  784. "unexpected grab_exc_value(): %r" % (exc,))
  785. def build_bridge(self):
  786. def exc_handling(guard_op):
  787. # operations need to start with correct GUARD_EXCEPTION
  788. if guard_op._exc_box is None:
  789. op = ResOperation(rop.GUARD_NO_EXCEPTION, [])
  790. else:
  791. op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box])
  792. op.setdescr(self.builder.getfaildescr())
  793. op.setfailargs([])
  794. return op
  795. if self.dont_generate_more:
  796. return False
  797. r = self.r
  798. guard_op = self.guard_op
  799. fail_args = guard_op.getfailargs()
  800. fail_descr = guard_op.getdescr()
  801. op = self.should_fail_by
  802. if not op.getfailargs():
  803. return False
  804. for _fail_box in fail_args:
  805. _fail_box.set_forwarded(None)
  806. # generate the branch: a sequence of operations that ends in a FINISH
  807. subloop = DummyLoop([])
  808. self.subloops.append(subloop) # keep around for debugging
  809. if rop.is_guard_exception(guard_op.getopnum()):
  810. subloop.operations.append(exc_handling(guard_op))
  811. bridge_builder = self.builder.fork(self.builder.cpu, subloop,
  812. op.getfailargs()[:])
  813. self.generate_ops(bridge_builder, r, subloop, op.getfailargs()[:])
  814. # note that 'self.guard_op' now points to the guard that will fail in
  815. # this new bridge, while 'guard_op' still points to the guard that
  816. # has just failed.
  817. if r.random() < 0.1 and self.guard_op is None:
  818. # Occasionally, instead of ending in a FINISH, we end in a jump
  819. # to another loop. We don't do it, however, if the new bridge's
  820. # execution will hit 'self.guard_op', but only if it executes
  821. # to the FINISH normally. (There is no point to the extra
  822. # complexity, as we might get the same effect by two calls
  823. # to build_bridge().)
  824. # First make up the other loop...
  825. #
  826. # New restriction: must have the same argument count and types
  827. # as the original loop
  828. subset = []
  829. for box in self.loop.inputargs:
  830. srcbox = r.choice(fail_args)
  831. if srcbox.type != box.type:
  832. if box.type == INT:
  833. srcbox = ConstInt(r.random_integer())
  834. elif box.type == FLOAT:
  835. srcbox = ConstFloat(r.random_float_storage())
  836. else:
  837. raise AssertionError(box.type)
  838. subset.append(srcbox)
  839. #
  840. args = []
  841. for x in subset:
  842. if x.type == INT:
  843. args.append(InputArgInt(getint(x)))
  844. elif x.type == FLOAT:
  845. args.append(InputArgFloat(getfloatstorage(x)))
  846. else:
  847. assert 0, x.type
  848. rl = RandomLoop(self.builder.cpu, self.builder.fork,
  849. r, args)
  850. # done
  851. self.should_fail_by = rl.should_fail_by
  852. self.expected = rl.expected
  853. assert len(rl.loop.inputargs) == len(args)
  854. # The new bridge's execution will end normally at its FINISH.
  855. # Just replace the FINISH with the JUMP to the new loop.
  856. jump_op = ResOperation(rop.JUMP, subset,
  857. descr=rl.loop._targettoken)
  858. subloop.operations[-1] = jump_op
  859. self.guard_op = rl.guard_op
  860. self.prebuilt_ptr_consts += rl.prebuilt_ptr_consts
  861. self.loop._jitcelltoken.record_jump_to(rl.loop._jitcelltoken)
  862. self.dont_generate_more = True
  863. if r.random() < .05:
  864. return False
  865. dump(subloop)
  866. self.builder.cpu.compile_bridge(fail_descr, fail_args,
  867. subloop.operations,
  868. self.loop._jitcelltoken)
  869. if self.output:
  870. bridge_builder.print_loop(self.output, fail_descr, fail_args)
  871. return True
  872. def dump(loop):
  873. print >> sys.stderr, loop
  874. if hasattr(loop, 'inputargs'):
  875. print >> sys.stderr, '\t', loop.inputargs
  876. for op in loop.operations:
  877. if op.is_guard():
  878. print >> sys.stderr, '\t', op, op.getfailargs()
  879. else:
  880. print >> sys.stderr, '\t', op
  881. def check_random_function(cpu, BuilderClass, r, num=None, max=None):
  882. if pytest.config.option.output:
  883. output = open(pytest.config.option.output, "w")
  884. else:
  885. output = None
  886. loop = RandomLoop(cpu, BuilderClass, r, output=output)
  887. while True:
  888. loop.run_loop()
  889. if loop.guard_op is not None:
  890. if not loop.build_bridge():
  891. break
  892. else:
  893. break
  894. if num is not None:
  895. print ' # passed (%d/%d).' % (num + 1, max)
  896. else:
  897. print ' # passed.'
  898. if pytest.config.option.output:
  899. output.close()
  900. print
  901. def test_random_function(BuilderClass=OperationBuilder):
  902. r = Random()
  903. cpu = get_cpu()
  904. cpu.setup_once()
  905. if pytest.config.option.repeat == -1:
  906. while 1:
  907. check_random_function(cpu, BuilderClass, r)
  908. else:
  909. for i in range(pytest.config.option.repeat):
  910. check_random_function(cpu, BuilderClass, r, i,
  911. pytest.config.option.repeat)