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

/rpython/translator/c/funcgen.py

https://bitbucket.org/pypy/pypy/
Python | 945 lines | 870 code | 43 blank | 32 comment | 63 complexity | ec2775704f6ce6ae14f7fad9f06fea56 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. from rpython.translator.c.support import cdecl
  3. from rpython.translator.c.support import llvalue_from_constant, gen_assignments
  4. from rpython.translator.c.support import c_string_constant, barebonearray
  5. from rpython.flowspace.model import Variable, Constant, mkentrymap
  6. from rpython.rtyper.lltypesystem.lltype import (Ptr, Void, Bool, Signed, Unsigned,
  7. SignedLongLong, Float, UnsignedLongLong, Char, UniChar, ContainerType,
  8. Array, FixedSizeArray, ForwardReference, FuncType)
  9. from rpython.rtyper.lltypesystem.rffi import INT
  10. from rpython.rtyper.lltypesystem.llmemory import Address
  11. from rpython.translator.backendopt.ssa import SSI_to_SSA
  12. from rpython.translator.backendopt.innerloop import find_inner_loops
  13. from rpython.tool.identity_dict import identity_dict
  14. from rpython.rlib.objectmodel import CDefinedIntSymbolic
  15. LOCALVAR = 'l_%s'
  16. KEEP_INLINED_GRAPHS = False
  17. def make_funcgen(graph, db, exception_policy, functionname):
  18. graph._seen_by_the_backend = True
  19. # apply the exception transformation
  20. if db.exctransformer:
  21. db.exctransformer.create_exception_handling(graph)
  22. # apply the gc transformation
  23. if db.gctransformer:
  24. db.gctransformer.transform_graph(graph)
  25. return FunctionCodeGenerator(graph, db, exception_policy, functionname)
  26. class FunctionCodeGenerator(object):
  27. """
  28. Collects information about a function which we have to generate
  29. from a flow graph.
  30. """
  31. def __init__(self, graph, db, exception_policy, functionname):
  32. self.graph = graph
  33. self.db = db
  34. self.gcpolicy = db.gcpolicy
  35. self.exception_policy = exception_policy
  36. self.functionname = functionname
  37. self.collect_var_and_types()
  38. for v in self.vars:
  39. T = v.concretetype
  40. # obscure: skip forward references and hope for the best
  41. # (needed for delayed function pointers)
  42. if isinstance(T, Ptr) and T.TO.__class__ == ForwardReference:
  43. continue
  44. db.gettype(T) # force the type to be considered by the database
  45. self.illtypes = None
  46. def collect_var_and_types(self):
  47. #
  48. # collect all variables and constants used in the body,
  49. # and get their types now
  50. #
  51. # NOTE: cannot use dictionaries with Constants as keys, because
  52. # Constants may hash and compare equal but have different lltypes
  53. self.all_cached_consts = None # will be filled after implementation_end
  54. mix = [self.graph.getreturnvar()]
  55. self.more_ll_values = []
  56. for block in self.graph.iterblocks():
  57. mix.extend(block.inputargs)
  58. for op in block.operations:
  59. mix.extend(op.args)
  60. mix.append(op.result)
  61. for link in block.exits:
  62. mix.extend(link.getextravars())
  63. mix.extend(link.args)
  64. if hasattr(link, 'llexitcase'):
  65. self.more_ll_values.append(link.llexitcase)
  66. elif link.exitcase is not None:
  67. mix.append(Constant(link.exitcase))
  68. uniquemix = []
  69. seen = identity_dict()
  70. for v in mix:
  71. if v not in seen:
  72. uniquemix.append(v)
  73. seen[v] = True
  74. self.vars = uniquemix
  75. def implementation_begin(self):
  76. SSI_to_SSA(self.graph)
  77. self.collect_var_and_types()
  78. self.blocknum = {}
  79. for block in self.graph.iterblocks():
  80. self.blocknum[block] = len(self.blocknum)
  81. db = self.db
  82. lltypes = identity_dict()
  83. for v in self.vars:
  84. T = v.concretetype
  85. typename = db.gettype(T)
  86. lltypes[v] = T, typename
  87. self.illtypes = lltypes
  88. self.innerloops = {} # maps the loop's header block to a Loop()
  89. for loop in find_inner_loops(self.graph, Bool):
  90. self.innerloops[loop.headblock] = loop
  91. def graphs_to_patch(self):
  92. yield self.graph
  93. def implementation_end(self):
  94. self.all_cached_consts = list(self.allconstantvalues())
  95. self.illtypes = None
  96. self.vars = None
  97. self.blocknum = None
  98. self.innerloops = None
  99. def argnames(self):
  100. return [LOCALVAR % v.name for v in self.graph.getargs()]
  101. def allvariables(self):
  102. return [v for v in self.vars if isinstance(v, Variable)]
  103. def allconstants(self):
  104. return [c for c in self.vars if isinstance(c, Constant)]
  105. def allconstantvalues(self):
  106. for c in self.vars:
  107. if isinstance(c, Constant):
  108. yield llvalue_from_constant(c)
  109. for llvalue in self.more_ll_values:
  110. yield llvalue
  111. def lltypemap(self, v):
  112. T, typename = self.illtypes[v]
  113. return T
  114. def lltypename(self, v):
  115. T, typename = self.illtypes[v]
  116. return typename
  117. def expr(self, v, special_case_void=True):
  118. if isinstance(v, Variable):
  119. if self.lltypemap(v) is Void and special_case_void:
  120. return '/* nothing */'
  121. else:
  122. return LOCALVAR % v.name
  123. elif isinstance(v, Constant):
  124. value = llvalue_from_constant(v)
  125. if value is None and not special_case_void:
  126. return 'nothing'
  127. else:
  128. return self.db.get(value)
  129. else:
  130. raise TypeError("expr(%r)" % (v,))
  131. # ____________________________________________________________
  132. def cfunction_declarations(self):
  133. # declare the local variables, excluding the function arguments
  134. seen = set()
  135. for a in self.graph.getargs():
  136. seen.add(a.name)
  137. result_by_name = []
  138. for v in self.allvariables():
  139. name = v.name
  140. if name not in seen:
  141. seen.add(name)
  142. result = cdecl(self.lltypename(v), LOCALVAR % name) + ';'
  143. if self.lltypemap(v) is Void:
  144. continue #result = '/*%s*/' % result
  145. result_by_name.append((v._name, result))
  146. result_by_name.sort()
  147. return [result for name, result in result_by_name]
  148. # ____________________________________________________________
  149. def cfunction_body(self):
  150. graph = self.graph
  151. # Locate blocks with a single predecessor, which can be written
  152. # inline in place of a "goto":
  153. entrymap = mkentrymap(graph)
  154. self.inlinable_blocks = {
  155. block for block in entrymap if len(entrymap[block]) == 1}
  156. yield ''
  157. for line in self.gen_goto(graph.startblock):
  158. yield line
  159. # Only blocks left are those that have more than one predecessor.
  160. for block in graph.iterblocks():
  161. if block in self.inlinable_blocks:
  162. continue
  163. for line in self.gen_block(block):
  164. yield line
  165. def gen_block(self, block):
  166. if 1: # (preserve indentation)
  167. myblocknum = self.blocknum[block]
  168. if block in self.inlinable_blocks:
  169. # debug comment
  170. yield '/* block%d: (inlined) */' % myblocknum
  171. else:
  172. yield 'block%d:' % myblocknum
  173. if block in self.innerloops:
  174. for line in self.gen_while_loop_hack(block):
  175. yield line
  176. return
  177. for i, op in enumerate(block.operations):
  178. for line in self.gen_op(op):
  179. yield line
  180. if len(block.exits) == 0:
  181. assert len(block.inputargs) == 1
  182. # regular return block
  183. retval = self.expr(block.inputargs[0])
  184. if self.exception_policy != "exc_helper":
  185. yield 'RPY_DEBUG_RETURN();'
  186. yield 'return %s;' % retval
  187. return
  188. elif block.exitswitch is None:
  189. # single-exit block
  190. assert len(block.exits) == 1
  191. for op in self.gen_link(block.exits[0]):
  192. yield op
  193. else:
  194. assert not block.canraise
  195. # block ending in a switch on a value
  196. TYPE = self.lltypemap(block.exitswitch)
  197. if TYPE == Bool:
  198. expr = self.expr(block.exitswitch)
  199. for link in block.exits[:0:-1]:
  200. assert link.exitcase in (False, True)
  201. if not link.exitcase:
  202. expr = '!' + expr
  203. yield 'if (%s) {' % expr
  204. for op in self.gen_link(link):
  205. yield '\t' + op
  206. yield '}'
  207. link = block.exits[0]
  208. assert link.exitcase in (False, True)
  209. for op in self.gen_link(link):
  210. yield op
  211. elif TYPE in (Signed, Unsigned, SignedLongLong,
  212. UnsignedLongLong, Char, UniChar):
  213. defaultlink = None
  214. expr = self.expr(block.exitswitch)
  215. yield 'switch (%s) {' % self.expr(block.exitswitch)
  216. for link in block.exits:
  217. if link.exitcase == 'default':
  218. defaultlink = link
  219. continue
  220. yield 'case %s:' % self.db.get(link.llexitcase)
  221. for op in self.gen_link(link):
  222. yield '\t' + op
  223. # 'break;' not needed, as gen_link ends in a 'goto'
  224. # Emit default case
  225. yield 'default:'
  226. if defaultlink is None:
  227. yield '\tassert(!"bad switch!!"); abort();'
  228. else:
  229. for op in self.gen_link(defaultlink):
  230. yield '\t' + op
  231. yield '}'
  232. else:
  233. raise TypeError("exitswitch type not supported"
  234. " Got %r" % (TYPE,))
  235. def gen_link(self, link):
  236. "Generate the code to jump across the given Link."
  237. assignments = []
  238. for a1, a2 in zip(link.args, link.target.inputargs):
  239. a2type, a2typename = self.illtypes[a2]
  240. if a2type is Void:
  241. continue
  242. src = self.expr(a1)
  243. dest = LOCALVAR % a2.name
  244. assignments.append((a2typename, dest, src))
  245. for line in gen_assignments(assignments):
  246. yield line
  247. for line in self.gen_goto(link.target, link):
  248. yield line
  249. def gen_goto(self, target, link=None):
  250. """Recursively expand block with inlining or goto.
  251. Blocks that have only one predecessor are inlined directly, all others
  252. are reached via goto.
  253. """
  254. label = 'block%d' % self.blocknum[target]
  255. if target in self.innerloops:
  256. loop = self.innerloops[target]
  257. if link is loop.links[-1]: # link that ends a loop
  258. label += '_back'
  259. if target in self.inlinable_blocks:
  260. for line in self.gen_block(target):
  261. yield line
  262. else:
  263. yield 'goto %s;' % label
  264. def gen_op(self, op):
  265. macro = 'OP_%s' % op.opname.upper()
  266. line = None
  267. if op.opname.startswith('gc_') and op.opname != 'gc_load_indexed':
  268. meth = getattr(self.gcpolicy, macro, None)
  269. if meth:
  270. line = meth(self, op)
  271. else:
  272. meth = getattr(self, macro, None)
  273. if meth:
  274. line = meth(op)
  275. if line is None:
  276. lst = [self.expr(v) for v in op.args]
  277. lst.append(self.expr(op.result))
  278. line = '%s(%s);' % (macro, ', '.join(lst))
  279. if "\n" not in line:
  280. yield line
  281. else:
  282. for line in line.splitlines():
  283. yield line
  284. def gen_while_loop_hack(self, headblock):
  285. # a GCC optimization hack: generate 'while' statement in the
  286. # source to convince the C compiler that it is really dealing
  287. # with loops. For the head of a loop (i.e. the block where the
  288. # decision is) we produce code like this:
  289. #
  290. # headblock:
  291. # while (1) {
  292. # ...headblock operations...
  293. # if (!cond) break;
  294. # goto firstbodyblock;
  295. # headblock_back: ;
  296. # }
  297. #
  298. # The real body of the loop is not syntactically within the
  299. # scope of { }, but apparently this doesn't matter to GCC as
  300. # long as it is within the { } via the chain of goto's starting
  301. # at firstbodyblock: and ending at headblock_back:. We need to
  302. # duplicate the operations of headblock, though, because the
  303. # chain of gotos entering the loop must arrive outside the
  304. # while() at the headblock: label and the chain of goto's that
  305. # close the loop must arrive inside the while() at the
  306. # headblock_back: label.
  307. looplinks = self.innerloops[headblock].links
  308. enterlink = looplinks[0]
  309. assert len(headblock.exits) == 2
  310. assert isinstance(headblock.exits[0].exitcase, bool)
  311. assert isinstance(headblock.exits[1].exitcase, bool)
  312. i = list(headblock.exits).index(enterlink)
  313. exitlink = headblock.exits[1 - i]
  314. yield 'while (1) {'
  315. for i, op in enumerate(headblock.operations):
  316. for line in self.gen_op(op):
  317. yield '\t' + line
  318. expr = self.expr(headblock.exitswitch)
  319. if enterlink.exitcase == True:
  320. expr = '!' + expr
  321. yield '\tif (%s) break;' % expr
  322. for op in self.gen_link(enterlink):
  323. yield '\t' + op
  324. yield ' block%d_back: ;' % self.blocknum[headblock]
  325. yield '}'
  326. for op in self.gen_link(exitlink):
  327. yield op
  328. # ____________________________________________________________
  329. # the C preprocessor cannot handle operations taking a variable number
  330. # of arguments, so here are Python methods that do it
  331. def OP_NEWLIST(self, op):
  332. args = [self.expr(v) for v in op.args]
  333. r = self.expr(op.result)
  334. if len(args) == 0:
  335. return 'OP_NEWLIST0(%s);' % (r, )
  336. else:
  337. args.insert(0, '%d' % len(args))
  338. return 'OP_NEWLIST((%s), %s);' % (', '.join(args), r)
  339. def OP_NEWDICT(self, op):
  340. args = [self.expr(v) for v in op.args]
  341. r = self.expr(op.result)
  342. if len(args) == 0:
  343. return 'OP_NEWDICT0(%s);' % (r, )
  344. else:
  345. assert len(args) % 2 == 0
  346. args.insert(0, '%d' % (len(args)//2))
  347. return 'OP_NEWDICT((%s), %s);' % (', '.join(args), r)
  348. def OP_NEWTUPLE(self, op):
  349. args = [self.expr(v) for v in op.args]
  350. r = self.expr(op.result)
  351. args.insert(0, '%d' % len(args))
  352. return 'OP_NEWTUPLE((%s), %s);' % (', '.join(args), r)
  353. def OP_SIMPLE_CALL(self, op):
  354. args = [self.expr(v) for v in op.args]
  355. r = self.expr(op.result)
  356. args.append('NULL')
  357. return 'OP_SIMPLE_CALL((%s), %s);' % (', '.join(args), r)
  358. def OP_CALL_ARGS(self, op):
  359. args = [self.expr(v) for v in op.args]
  360. r = self.expr(op.result)
  361. return 'OP_CALL_ARGS((%s), %s);' % (', '.join(args), r)
  362. def generic_call(self, FUNC, fnexpr, args_v, v_result, targets=None):
  363. args = []
  364. assert len(args_v) == len(FUNC.TO.ARGS)
  365. for v, ARGTYPE in zip(args_v, FUNC.TO.ARGS):
  366. if ARGTYPE is Void:
  367. continue # skip 'void' argument
  368. args.append(self.expr(v))
  369. # special case for rctypes: by-value container args:
  370. # XXX is this still needed now that rctypes is gone
  371. if isinstance(ARGTYPE, ContainerType):
  372. args[-1] = '*%s' % (args[-1],)
  373. line = '%s(%s);' % (fnexpr, ', '.join(args))
  374. if self.lltypemap(v_result) is not Void:
  375. # skip assignment of 'void' return value
  376. r = self.expr(v_result)
  377. line = '%s = %s' % (r, line)
  378. if targets:
  379. for graph in targets:
  380. if getattr(graph, 'inhibit_tail_call', False):
  381. line += '\nPYPY_INHIBIT_TAIL_CALL();'
  382. break
  383. return line
  384. def OP_DIRECT_CALL(self, op):
  385. fn = op.args[0]
  386. try:
  387. targets = [fn.value._obj.graph]
  388. except AttributeError:
  389. targets = None
  390. return self.generic_call(fn.concretetype, self.expr(fn),
  391. op.args[1:], op.result, targets)
  392. def OP_INDIRECT_CALL(self, op):
  393. fn = op.args[0]
  394. return self.generic_call(fn.concretetype, self.expr(fn),
  395. op.args[1:-1], op.result, op.args[-1].value)
  396. def OP_ADR_CALL(self, op):
  397. ARGTYPES = [v.concretetype for v in op.args[1:]]
  398. RESTYPE = op.result.concretetype
  399. FUNC = Ptr(FuncType(ARGTYPES, RESTYPE))
  400. typename = self.db.gettype(FUNC)
  401. fnaddr = op.args[0]
  402. fnexpr = '((%s)%s)' % (cdecl(typename, ''), self.expr(fnaddr))
  403. return self.generic_call(FUNC, fnexpr, op.args[1:], op.result)
  404. def OP_JIT_CONDITIONAL_CALL(self, op):
  405. return 'abort(); /* jit_conditional_call */'
  406. # low-level operations
  407. def generic_get(self, op, sourceexpr):
  408. T = self.lltypemap(op.result)
  409. newvalue = self.expr(op.result, special_case_void=False)
  410. result = '%s = %s;' % (newvalue, sourceexpr)
  411. if T is Void:
  412. result = '/* %s */' % result
  413. return result
  414. def generic_set(self, op, targetexpr):
  415. newvalue = self.expr(op.args[-1], special_case_void=False)
  416. result = '%s = %s;' % (targetexpr, newvalue)
  417. T = self.lltypemap(op.args[-1])
  418. if T is Void:
  419. result = '/* %s */' % result
  420. return result
  421. def OP_GETFIELD(self, op, ampersand=''):
  422. assert isinstance(op.args[1], Constant)
  423. STRUCT = self.lltypemap(op.args[0]).TO
  424. structdef = self.db.gettypedefnode(STRUCT)
  425. baseexpr_is_const = isinstance(op.args[0], Constant)
  426. expr = ampersand + structdef.ptr_access_expr(self.expr(op.args[0]),
  427. op.args[1].value,
  428. baseexpr_is_const)
  429. return self.generic_get(op, expr)
  430. def OP_BARE_SETFIELD(self, op):
  431. assert isinstance(op.args[1], Constant)
  432. STRUCT = self.lltypemap(op.args[0]).TO
  433. structdef = self.db.gettypedefnode(STRUCT)
  434. baseexpr_is_const = isinstance(op.args[0], Constant)
  435. expr = structdef.ptr_access_expr(self.expr(op.args[0]),
  436. op.args[1].value,
  437. baseexpr_is_const)
  438. return self.generic_set(op, expr)
  439. def OP_GETSUBSTRUCT(self, op):
  440. RESULT = self.lltypemap(op.result).TO
  441. if (isinstance(RESULT, FixedSizeArray) or
  442. (isinstance(RESULT, Array) and barebonearray(RESULT))):
  443. return self.OP_GETFIELD(op, ampersand='')
  444. else:
  445. return self.OP_GETFIELD(op, ampersand='&')
  446. def OP_GETARRAYSIZE(self, op):
  447. ARRAY = self.lltypemap(op.args[0]).TO
  448. if isinstance(ARRAY, FixedSizeArray):
  449. return '%s = %d;' % (self.expr(op.result),
  450. ARRAY.length)
  451. else:
  452. return '%s = %s->length;' % (self.expr(op.result),
  453. self.expr(op.args[0]))
  454. def OP_GETARRAYITEM(self, op):
  455. ARRAY = self.lltypemap(op.args[0]).TO
  456. ptr = self.expr(op.args[0])
  457. index = self.expr(op.args[1])
  458. arraydef = self.db.gettypedefnode(ARRAY)
  459. return self.generic_get(op, arraydef.itemindex_access_expr(ptr, index))
  460. def OP_SETARRAYITEM(self, op):
  461. ARRAY = self.lltypemap(op.args[0]).TO
  462. ptr = self.expr(op.args[0])
  463. index = self.expr(op.args[1])
  464. arraydef = self.db.gettypedefnode(ARRAY)
  465. return self.generic_set(op, arraydef.itemindex_access_expr(ptr, index))
  466. OP_BARE_SETARRAYITEM = OP_SETARRAYITEM
  467. def OP_GETARRAYSUBSTRUCT(self, op):
  468. ARRAY = self.lltypemap(op.args[0]).TO
  469. ptr = self.expr(op.args[0])
  470. index = self.expr(op.args[1])
  471. arraydef = self.db.gettypedefnode(ARRAY)
  472. return '%s = &%s;' % (self.expr(op.result),
  473. arraydef.itemindex_access_expr(ptr, index))
  474. def interior_expr(self, args, rettype=False):
  475. TYPE = args[0].concretetype.TO
  476. expr = self.expr(args[0])
  477. for i, arg in enumerate(args[1:]):
  478. defnode = self.db.gettypedefnode(TYPE)
  479. if arg.concretetype is Void:
  480. fieldname = arg.value
  481. if i == 0:
  482. expr = defnode.ptr_access_expr(expr, fieldname)
  483. else:
  484. expr = defnode.access_expr(expr, fieldname)
  485. if isinstance(TYPE, FixedSizeArray):
  486. TYPE = TYPE.OF
  487. else:
  488. TYPE = getattr(TYPE, fieldname)
  489. else:
  490. indexexpr = self.expr(arg)
  491. if i == 0:
  492. expr = defnode.itemindex_access_expr(expr, indexexpr)
  493. else:
  494. expr = defnode.access_expr_varindex(expr, indexexpr)
  495. TYPE = TYPE.OF
  496. if rettype:
  497. return expr, TYPE
  498. else:
  499. return expr
  500. def OP_GETINTERIORFIELD(self, op):
  501. return self.generic_get(op, self.interior_expr(op.args))
  502. def OP_BARE_SETINTERIORFIELD(self, op):
  503. return self.generic_set(op, self.interior_expr(op.args[:-1]))
  504. def OP_GETINTERIORARRAYSIZE(self, op):
  505. expr, ARRAY = self.interior_expr(op.args, True)
  506. if isinstance(ARRAY, FixedSizeArray):
  507. return '%s = %d;'%(self.expr(op.result), ARRAY.length)
  508. else:
  509. assert isinstance(ARRAY, Array)
  510. return '%s = %s.length;'%(self.expr(op.result), expr)
  511. def OP_PTR_NONZERO(self, op):
  512. return '%s = (%s != NULL);' % (self.expr(op.result),
  513. self.expr(op.args[0]))
  514. def OP_PTR_ISZERO(self, op):
  515. return '%s = (%s == NULL);' % (self.expr(op.result),
  516. self.expr(op.args[0]))
  517. def OP_PTR_EQ(self, op):
  518. return '%s = (%s == %s);' % (self.expr(op.result),
  519. self.expr(op.args[0]),
  520. self.expr(op.args[1]))
  521. def OP_PTR_NE(self, op):
  522. return '%s = (%s != %s);' % (self.expr(op.result),
  523. self.expr(op.args[0]),
  524. self.expr(op.args[1]))
  525. def OP_BOEHM_MALLOC(self, op):
  526. return 'OP_BOEHM_ZERO_MALLOC(%s, %s, void*, 0, 0);' % (self.expr(op.args[0]),
  527. self.expr(op.result))
  528. def OP_BOEHM_MALLOC_ATOMIC(self, op):
  529. return 'OP_BOEHM_ZERO_MALLOC(%s, %s, void*, 1, 0);' % (self.expr(op.args[0]),
  530. self.expr(op.result))
  531. def OP_BOEHM_REGISTER_FINALIZER(self, op):
  532. return 'GC_REGISTER_FINALIZER(%s, (GC_finalization_proc)%s, NULL, NULL, NULL);' \
  533. % (self.expr(op.args[0]), self.expr(op.args[1]))
  534. def OP_RAW_MALLOC(self, op):
  535. eresult = self.expr(op.result)
  536. esize = self.expr(op.args[0])
  537. return "OP_RAW_MALLOC(%s, %s, void *);" % (esize, eresult)
  538. def OP_STACK_MALLOC(self, op):
  539. eresult = self.expr(op.result)
  540. esize = self.expr(op.args[0])
  541. return "OP_STACK_MALLOC(%s, %s, void *);" % (esize, eresult)
  542. def OP_DIRECT_FIELDPTR(self, op):
  543. return self.OP_GETFIELD(op, ampersand='&')
  544. def OP_DIRECT_ARRAYITEMS(self, op):
  545. ARRAY = self.lltypemap(op.args[0]).TO
  546. items = self.expr(op.args[0])
  547. if not isinstance(ARRAY, FixedSizeArray) and not barebonearray(ARRAY):
  548. items += '->items'
  549. return '%s = %s;' % (self.expr(op.result), items)
  550. def OP_DIRECT_PTRADD(self, op):
  551. ARRAY = self.lltypemap(op.args[0]).TO
  552. if ARRAY._hints.get("render_as_void"):
  553. return '%s = (char *)%s + %s;' % (
  554. self.expr(op.result),
  555. self.expr(op.args[0]),
  556. self.expr(op.args[1]))
  557. else:
  558. return '%s = %s + %s;' % (
  559. self.expr(op.result),
  560. self.expr(op.args[0]),
  561. self.expr(op.args[1]))
  562. def OP_CAST_POINTER(self, op):
  563. TYPE = self.lltypemap(op.result)
  564. typename = self.db.gettype(TYPE)
  565. result = []
  566. result.append('%s = (%s)%s;' % (self.expr(op.result),
  567. cdecl(typename, ''),
  568. self.expr(op.args[0])))
  569. return '\t'.join(result)
  570. OP_CAST_PTR_TO_ADR = OP_CAST_POINTER
  571. OP_CAST_ADR_TO_PTR = OP_CAST_POINTER
  572. OP_CAST_OPAQUE_PTR = OP_CAST_POINTER
  573. def OP_LENGTH_OF_SIMPLE_GCARRAY_FROM_OPAQUE(self, op):
  574. return ('%s = *(long *)(((char *)%s) + sizeof(struct pypy_header0));'
  575. ' /* length_of_simple_gcarray_from_opaque */'
  576. % (self.expr(op.result), self.expr(op.args[0])))
  577. def OP_CAST_INT_TO_PTR(self, op):
  578. TYPE = self.lltypemap(op.result)
  579. typename = self.db.gettype(TYPE)
  580. return "%s = (%s)%s;" % (self.expr(op.result), cdecl(typename, ""),
  581. self.expr(op.args[0]))
  582. def OP_SAME_AS(self, op):
  583. result = []
  584. TYPE = self.lltypemap(op.result)
  585. assert self.lltypemap(op.args[0]) == TYPE
  586. if TYPE is not Void:
  587. result.append('%s = %s;' % (self.expr(op.result),
  588. self.expr(op.args[0])))
  589. return '\t'.join(result)
  590. def OP_HINT(self, op):
  591. hints = op.args[1].value
  592. return '%s\t/* hint: %r */' % (self.OP_SAME_AS(op), hints)
  593. def OP_KEEPALIVE(self, op): # xxx what should be the sematics consequences of this
  594. v = op.args[0]
  595. TYPE = self.lltypemap(v)
  596. if TYPE is Void:
  597. return "/* kept alive: void */"
  598. if isinstance(TYPE, Ptr) and TYPE.TO._gckind == 'gc':
  599. meth = getattr(self.gcpolicy, 'GC_KEEPALIVE', None)
  600. if meth:
  601. return meth(self, v)
  602. return "/* kept alive: %s */" % self.expr(v)
  603. #address operations
  604. def OP_RAW_STORE(self, op):
  605. addr = self.expr(op.args[0])
  606. offset = self.expr(op.args[1])
  607. value = self.expr(op.args[2])
  608. TYPE = op.args[2].concretetype
  609. typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '')
  610. return (
  611. '((%(typename)s) (((char *)%(addr)s) + %(offset)s))[0] = %(value)s;'
  612. % locals())
  613. OP_BARE_RAW_STORE = OP_RAW_STORE
  614. def OP_RAW_LOAD(self, op):
  615. addr = self.expr(op.args[0])
  616. offset = self.expr(op.args[1])
  617. result = self.expr(op.result)
  618. TYPE = op.result.concretetype
  619. typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '')
  620. return (
  621. "%(result)s = ((%(typename)s) (((char *)%(addr)s) + %(offset)s))[0];"
  622. % locals())
  623. def OP_GC_LOAD_INDEXED(self, op):
  624. addr = self.expr(op.args[0])
  625. index = self.expr(op.args[1])
  626. scale = self.expr(op.args[2])
  627. base_ofs = self.expr(op.args[3])
  628. result = self.expr(op.result)
  629. TYPE = op.result.concretetype
  630. typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '')
  631. return (
  632. "%(result)s = ((%(typename)s) (((char *)%(addr)s) + "
  633. "%(base_ofs)s + %(scale)s * %(index)s))[0];"
  634. % locals())
  635. def OP_CAST_PRIMITIVE(self, op):
  636. TYPE = self.lltypemap(op.result)
  637. val = self.expr(op.args[0])
  638. result = self.expr(op.result)
  639. if TYPE == Bool:
  640. return "%(result)s = !!%(val)s;" % locals()
  641. ORIG = self.lltypemap(op.args[0])
  642. if ORIG is Char:
  643. val = "(unsigned char)%s" % val
  644. elif ORIG is UniChar:
  645. val = "(unsigned long)%s" % val
  646. typename = cdecl(self.db.gettype(TYPE), '')
  647. return "%(result)s = (%(typename)s)(%(val)s);" % locals()
  648. OP_FORCE_CAST = OP_CAST_PRIMITIVE # xxx the same logic works
  649. def OP_RESUME_POINT(self, op):
  650. return '/* resume point %s */'%(op.args[0],)
  651. def OP_DEBUG_PRINT(self, op):
  652. # XXX
  653. from rpython.rtyper.lltypesystem.rstr import STR
  654. format = []
  655. argv = []
  656. free_line = ""
  657. for arg in op.args:
  658. T = arg.concretetype
  659. if T == Ptr(STR):
  660. if isinstance(arg, Constant):
  661. format.append(''.join(arg.value.chars).replace('%', '%%'))
  662. else:
  663. format.append('%s')
  664. argv.append('RPyString_AsCharP(%s)' % self.expr(arg))
  665. free_line = "RPyString_FreeCache();"
  666. continue
  667. elif T == Signed:
  668. format.append('%ld')
  669. elif T == INT:
  670. format.append('%d')
  671. elif T == Unsigned:
  672. format.append('%lu')
  673. elif T == Float:
  674. format.append('%f')
  675. elif isinstance(T, Ptr) or T == Address:
  676. format.append('%p')
  677. elif T == Char:
  678. if isinstance(arg, Constant):
  679. format.append(arg.value.replace('%', '%%'))
  680. continue
  681. format.append('%c')
  682. elif T == Bool:
  683. format.append('%s')
  684. argv.append('(%s) ? "True" : "False"' % self.expr(arg))
  685. continue
  686. elif T == SignedLongLong:
  687. if sys.platform == 'win32':
  688. format.append('%I64d')
  689. else:
  690. format.append('%lld')
  691. elif T == UnsignedLongLong:
  692. if sys.platform == 'win32':
  693. format.append('%I64u')
  694. else:
  695. format.append('%llu')
  696. else:
  697. raise Exception("don't know how to debug_print %r" % (T,))
  698. argv.append(self.expr(arg))
  699. argv.insert(0, c_string_constant(' '.join(format) + '\n'))
  700. return (
  701. "if (PYPY_HAVE_DEBUG_PRINTS) { fprintf(PYPY_DEBUG_FILE, %s); %s}"
  702. % (', '.join(argv), free_line))
  703. def _op_debug(self, opname, arg):
  704. if isinstance(arg, Constant):
  705. string_literal = c_string_constant(''.join(arg.value.chars))
  706. return "%s(%s);" % (opname, string_literal)
  707. else:
  708. x = "%s(RPyString_AsCharP(%s));\n" % (opname, self.expr(arg))
  709. x += "RPyString_FreeCache();"
  710. return x
  711. def OP_DEBUG_START(self, op):
  712. return self._op_debug('PYPY_DEBUG_START', op.args[0])
  713. def OP_DEBUG_STOP(self, op):
  714. return self._op_debug('PYPY_DEBUG_STOP', op.args[0])
  715. def OP_HAVE_DEBUG_PRINTS_FOR(self, op):
  716. arg = op.args[0]
  717. assert isinstance(arg, Constant) and isinstance(arg.value, str)
  718. string_literal = c_string_constant(arg.value)
  719. return '%s = pypy_have_debug_prints_for(%s);' % (
  720. self.expr(op.result), string_literal)
  721. def OP_DEBUG_ASSERT(self, op):
  722. return 'RPyAssert(%s, %s);' % (self.expr(op.args[0]),
  723. c_string_constant(op.args[1].value))
  724. def OP_DEBUG_FATALERROR(self, op):
  725. # XXX
  726. from rpython.rtyper.lltypesystem.rstr import STR
  727. msg = op.args[0]
  728. assert msg.concretetype == Ptr(STR)
  729. if isinstance(msg, Constant):
  730. msg = c_string_constant(''.join(msg.value.chars))
  731. else:
  732. msg = 'RPyString_AsCharP(%s)' % self.expr(msg)
  733. return 'fprintf(stderr, "%%s\\n", %s); abort();' % msg
  734. def OP_DEBUG_LLINTERPCALL(self, op):
  735. result = 'abort(); /* debug_llinterpcall should be unreachable */'
  736. TYPE = self.lltypemap(op.result)
  737. if TYPE is not Void:
  738. typename = self.db.gettype(TYPE)
  739. result += '\n%s = (%s)0;' % (self.expr(op.result),
  740. cdecl(typename, ''))
  741. return result
  742. def OP_DEBUG_NONNULL_POINTER(self, op):
  743. expr = self.expr(op.args[0])
  744. return 'if ((-8192 <= (long)%s) && (((long)%s) < 8192)) abort();' % (
  745. expr, expr)
  746. def OP_INSTRUMENT_COUNT(self, op):
  747. counter_label = op.args[1].value
  748. self.db.instrument_ncounter = max(self.db.instrument_ncounter,
  749. counter_label+1)
  750. counter_label = self.expr(op.args[1])
  751. return 'PYPY_INSTRUMENT_COUNT(%s);' % counter_label
  752. def OP_IS_EARLY_CONSTANT(self, op):
  753. return '%s = 0; /* IS_EARLY_CONSTANT */' % (self.expr(op.result),)
  754. def OP_JIT_MARKER(self, op):
  755. return '/* JIT_MARKER %s */' % op
  756. def OP_JIT_FORCE_VIRTUALIZABLE(self, op):
  757. return '/* JIT_FORCE_VIRTUALIZABLE %s */' % op
  758. def OP_JIT_FORCE_VIRTUAL(self, op):
  759. return '%s = %s; /* JIT_FORCE_VIRTUAL */' % (self.expr(op.result),
  760. self.expr(op.args[0]))
  761. def OP_JIT_IS_VIRTUAL(self, op):
  762. return '%s = 0; /* JIT_IS_VIRTUAL */' % (self.expr(op.result),)
  763. def OP_JIT_FORCE_QUASI_IMMUTABLE(self, op):
  764. return '/* JIT_FORCE_QUASI_IMMUTABLE %s */' % op
  765. def OP_JIT_FFI_SAVE_RESULT(self, op):
  766. return '/* JIT_FFI_SAVE_RESULT %s */' % op
  767. def OP_JIT_ENTER_PORTAL_FRAME(self, op):
  768. return '/* JIT_ENTER_PORTAL_FRAME %s */' % op
  769. def OP_JIT_LEAVE_PORTAL_FRAME(self, op):
  770. return '/* JIT_LEAVE_PORTAL_FRAME %s */' % op
  771. def OP_GET_GROUP_MEMBER(self, op):
  772. typename = self.db.gettype(op.result.concretetype)
  773. return '%s = (%s)_OP_GET_GROUP_MEMBER(%s, %s);' % (
  774. self.expr(op.result),
  775. cdecl(typename, ''),
  776. self.expr(op.args[0]),
  777. self.expr(op.args[1]))
  778. def OP_GET_NEXT_GROUP_MEMBER(self, op):
  779. typename = self.db.gettype(op.result.concretetype)
  780. return '%s = (%s)_OP_GET_NEXT_GROUP_MEMBER(%s, %s, %s);' % (
  781. self.expr(op.result),
  782. cdecl(typename, ''),
  783. self.expr(op.args[0]),
  784. self.expr(op.args[1]),
  785. self.expr(op.args[2]))
  786. def getdebugfunctionname(self):
  787. name = self.functionname
  788. if name.startswith('pypy_g_'):
  789. name = name[7:]
  790. return name
  791. def OP_DEBUG_RECORD_TRACEBACK(self, op):
  792. return 'PYPY_DEBUG_RECORD_TRACEBACK("%s");' % (
  793. self.getdebugfunctionname(),)
  794. def OP_DEBUG_CATCH_EXCEPTION(self, op):
  795. gottype = self.expr(op.args[0])
  796. exprs = []
  797. for c_limited_type in op.args[1:]:
  798. exprs.append('%s == %s' % (gottype, self.expr(c_limited_type)))
  799. return 'PYPY_DEBUG_CATCH_EXCEPTION("%s", %s, %s);' % (
  800. self.getdebugfunctionname(), gottype, ' || '.join(exprs))
  801. def OP_INT_BETWEEN(self, op):
  802. if (isinstance(op.args[0], Constant) and
  803. isinstance(op.args[2], Constant) and
  804. op.args[2].value - op.args[0].value == 1):
  805. # (a <= b < a+1) ----> (b == a)
  806. return '%s = (%s == %s); /* was INT_BETWEEN */' % (
  807. self.expr(op.result),
  808. self.expr(op.args[1]),
  809. self.expr(op.args[0]))
  810. else:
  811. return None # use the default
  812. def OP_THREADLOCALREF_GET(self, op):
  813. typename = self.db.gettype(op.result.concretetype)
  814. if isinstance(op.args[0], Constant):
  815. assert isinstance(op.args[0].value, CDefinedIntSymbolic)
  816. fieldname = op.args[0].value.expr
  817. assert fieldname.startswith('RPY_TLOFS_')
  818. fieldname = fieldname[10:]
  819. return '%s = (%s)RPY_THREADLOCALREF_GET(%s);' % (
  820. self.expr(op.result),
  821. cdecl(typename, ''),
  822. fieldname)
  823. else:
  824. return 'OP_THREADLOCALREF_GET_NONCONST(%s, %s, %s);' % (
  825. cdecl(typename, ''),
  826. self.expr(op.args[0]),
  827. self.expr(op.result))