test_emitfunc.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. from __future__ import annotations
  2. import unittest
  3. from mypy.test.helpers import assert_string_arrays_equal
  4. from mypyc.codegen.emit import Emitter, EmitterContext
  5. from mypyc.codegen.emitfunc import FunctionEmitterVisitor, generate_native_function
  6. from mypyc.common import PLATFORM_SIZE
  7. from mypyc.ir.class_ir import ClassIR
  8. from mypyc.ir.func_ir import FuncDecl, FuncIR, FuncSignature, RuntimeArg
  9. from mypyc.ir.ops import (
  10. ERR_NEVER,
  11. Assign,
  12. AssignMulti,
  13. BasicBlock,
  14. Box,
  15. Branch,
  16. Call,
  17. CallC,
  18. Cast,
  19. ComparisonOp,
  20. DecRef,
  21. Extend,
  22. GetAttr,
  23. GetElementPtr,
  24. Goto,
  25. IncRef,
  26. Integer,
  27. IntOp,
  28. LoadAddress,
  29. LoadMem,
  30. Op,
  31. Register,
  32. Return,
  33. SetAttr,
  34. SetMem,
  35. TupleGet,
  36. Unbox,
  37. Unreachable,
  38. Value,
  39. )
  40. from mypyc.ir.pprint import generate_names_for_ir
  41. from mypyc.ir.rtypes import (
  42. RArray,
  43. RInstance,
  44. RStruct,
  45. RTuple,
  46. RType,
  47. bool_rprimitive,
  48. c_int_rprimitive,
  49. dict_rprimitive,
  50. int32_rprimitive,
  51. int64_rprimitive,
  52. int_rprimitive,
  53. list_rprimitive,
  54. object_rprimitive,
  55. pointer_rprimitive,
  56. short_int_rprimitive,
  57. )
  58. from mypyc.irbuild.vtable import compute_vtable
  59. from mypyc.namegen import NameGenerator
  60. from mypyc.primitives.dict_ops import (
  61. dict_get_item_op,
  62. dict_new_op,
  63. dict_set_item_op,
  64. dict_update_op,
  65. )
  66. from mypyc.primitives.int_ops import int_neg_op
  67. from mypyc.primitives.list_ops import list_append_op, list_get_item_op, list_set_item_op
  68. from mypyc.primitives.misc_ops import none_object_op
  69. from mypyc.primitives.registry import binary_ops
  70. from mypyc.subtype import is_subtype
  71. class TestFunctionEmitterVisitor(unittest.TestCase):
  72. """Test generation of fragments of C from individual IR ops."""
  73. def setUp(self) -> None:
  74. self.registers: list[Register] = []
  75. def add_local(name: str, rtype: RType) -> Register:
  76. reg = Register(rtype, name)
  77. self.registers.append(reg)
  78. return reg
  79. self.n = add_local("n", int_rprimitive)
  80. self.m = add_local("m", int_rprimitive)
  81. self.k = add_local("k", int_rprimitive)
  82. self.l = add_local("l", list_rprimitive)
  83. self.ll = add_local("ll", list_rprimitive)
  84. self.o = add_local("o", object_rprimitive)
  85. self.o2 = add_local("o2", object_rprimitive)
  86. self.d = add_local("d", dict_rprimitive)
  87. self.b = add_local("b", bool_rprimitive)
  88. self.s1 = add_local("s1", short_int_rprimitive)
  89. self.s2 = add_local("s2", short_int_rprimitive)
  90. self.i32 = add_local("i32", int32_rprimitive)
  91. self.i32_1 = add_local("i32_1", int32_rprimitive)
  92. self.i64 = add_local("i64", int64_rprimitive)
  93. self.i64_1 = add_local("i64_1", int64_rprimitive)
  94. self.ptr = add_local("ptr", pointer_rprimitive)
  95. self.t = add_local("t", RTuple([int_rprimitive, bool_rprimitive]))
  96. self.tt = add_local(
  97. "tt", RTuple([RTuple([int_rprimitive, bool_rprimitive]), bool_rprimitive])
  98. )
  99. ir = ClassIR("A", "mod")
  100. ir.attributes = {
  101. "x": bool_rprimitive,
  102. "y": int_rprimitive,
  103. "i1": int64_rprimitive,
  104. "i2": int32_rprimitive,
  105. }
  106. ir.bitmap_attrs = ["i1", "i2"]
  107. compute_vtable(ir)
  108. ir.mro = [ir]
  109. self.r = add_local("r", RInstance(ir))
  110. self.context = EmitterContext(NameGenerator([["mod"]]))
  111. def test_goto(self) -> None:
  112. self.assert_emit(Goto(BasicBlock(2)), "goto CPyL2;")
  113. def test_goto_next_block(self) -> None:
  114. next_block = BasicBlock(2)
  115. self.assert_emit(Goto(next_block), "", next_block=next_block)
  116. def test_return(self) -> None:
  117. self.assert_emit(Return(self.m), "return cpy_r_m;")
  118. def test_integer(self) -> None:
  119. self.assert_emit(Assign(self.n, Integer(5)), "cpy_r_n = 10;")
  120. self.assert_emit(Assign(self.i32, Integer(5, c_int_rprimitive)), "cpy_r_i32 = 5;")
  121. def test_tuple_get(self) -> None:
  122. self.assert_emit(TupleGet(self.t, 1, 0), "cpy_r_r0 = cpy_r_t.f1;")
  123. def test_load_None(self) -> None:
  124. self.assert_emit(
  125. LoadAddress(none_object_op.type, none_object_op.src, 0),
  126. "cpy_r_r0 = (PyObject *)&_Py_NoneStruct;",
  127. )
  128. def test_assign_int(self) -> None:
  129. self.assert_emit(Assign(self.m, self.n), "cpy_r_m = cpy_r_n;")
  130. def test_int_add(self) -> None:
  131. self.assert_emit_binary_op(
  132. "+", self.n, self.m, self.k, "cpy_r_r0 = CPyTagged_Add(cpy_r_m, cpy_r_k);"
  133. )
  134. def test_int_sub(self) -> None:
  135. self.assert_emit_binary_op(
  136. "-", self.n, self.m, self.k, "cpy_r_r0 = CPyTagged_Subtract(cpy_r_m, cpy_r_k);"
  137. )
  138. def test_int_neg(self) -> None:
  139. self.assert_emit(
  140. CallC(
  141. int_neg_op.c_function_name,
  142. [self.m],
  143. int_neg_op.return_type,
  144. int_neg_op.steals,
  145. int_neg_op.is_borrowed,
  146. int_neg_op.is_borrowed,
  147. int_neg_op.error_kind,
  148. 55,
  149. ),
  150. "cpy_r_r0 = CPyTagged_Negate(cpy_r_m);",
  151. )
  152. def test_branch(self) -> None:
  153. self.assert_emit(
  154. Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.BOOL),
  155. """if (cpy_r_b) {
  156. goto CPyL8;
  157. } else
  158. goto CPyL9;
  159. """,
  160. )
  161. b = Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.BOOL)
  162. b.negated = True
  163. self.assert_emit(
  164. b,
  165. """if (!cpy_r_b) {
  166. goto CPyL8;
  167. } else
  168. goto CPyL9;
  169. """,
  170. )
  171. def test_branch_no_else(self) -> None:
  172. next_block = BasicBlock(9)
  173. b = Branch(self.b, BasicBlock(8), next_block, Branch.BOOL)
  174. self.assert_emit(b, """if (cpy_r_b) goto CPyL8;""", next_block=next_block)
  175. next_block = BasicBlock(9)
  176. b = Branch(self.b, BasicBlock(8), next_block, Branch.BOOL)
  177. b.negated = True
  178. self.assert_emit(b, """if (!cpy_r_b) goto CPyL8;""", next_block=next_block)
  179. def test_branch_no_else_negated(self) -> None:
  180. next_block = BasicBlock(1)
  181. b = Branch(self.b, next_block, BasicBlock(2), Branch.BOOL)
  182. self.assert_emit(b, """if (!cpy_r_b) goto CPyL2;""", next_block=next_block)
  183. next_block = BasicBlock(1)
  184. b = Branch(self.b, next_block, BasicBlock(2), Branch.BOOL)
  185. b.negated = True
  186. self.assert_emit(b, """if (cpy_r_b) goto CPyL2;""", next_block=next_block)
  187. def test_branch_is_error(self) -> None:
  188. b = Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR)
  189. self.assert_emit(
  190. b,
  191. """if (cpy_r_b == 2) {
  192. goto CPyL8;
  193. } else
  194. goto CPyL9;
  195. """,
  196. )
  197. b = Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR)
  198. b.negated = True
  199. self.assert_emit(
  200. b,
  201. """if (cpy_r_b != 2) {
  202. goto CPyL8;
  203. } else
  204. goto CPyL9;
  205. """,
  206. )
  207. def test_branch_is_error_next_block(self) -> None:
  208. next_block = BasicBlock(8)
  209. b = Branch(self.b, next_block, BasicBlock(9), Branch.IS_ERROR)
  210. self.assert_emit(b, """if (cpy_r_b != 2) goto CPyL9;""", next_block=next_block)
  211. b = Branch(self.b, next_block, BasicBlock(9), Branch.IS_ERROR)
  212. b.negated = True
  213. self.assert_emit(b, """if (cpy_r_b == 2) goto CPyL9;""", next_block=next_block)
  214. def test_branch_rare(self) -> None:
  215. self.assert_emit(
  216. Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.BOOL, rare=True),
  217. """if (unlikely(cpy_r_b)) {
  218. goto CPyL8;
  219. } else
  220. goto CPyL9;
  221. """,
  222. )
  223. next_block = BasicBlock(9)
  224. self.assert_emit(
  225. Branch(self.b, BasicBlock(8), next_block, Branch.BOOL, rare=True),
  226. """if (unlikely(cpy_r_b)) goto CPyL8;""",
  227. next_block=next_block,
  228. )
  229. next_block = BasicBlock(8)
  230. b = Branch(self.b, next_block, BasicBlock(9), Branch.BOOL, rare=True)
  231. self.assert_emit(b, """if (likely(!cpy_r_b)) goto CPyL9;""", next_block=next_block)
  232. next_block = BasicBlock(8)
  233. b = Branch(self.b, next_block, BasicBlock(9), Branch.BOOL, rare=True)
  234. b.negated = True
  235. self.assert_emit(b, """if (likely(cpy_r_b)) goto CPyL9;""", next_block=next_block)
  236. def test_call(self) -> None:
  237. decl = FuncDecl(
  238. "myfn", None, "mod", FuncSignature([RuntimeArg("m", int_rprimitive)], int_rprimitive)
  239. )
  240. self.assert_emit(Call(decl, [self.m], 55), "cpy_r_r0 = CPyDef_myfn(cpy_r_m);")
  241. def test_call_two_args(self) -> None:
  242. decl = FuncDecl(
  243. "myfn",
  244. None,
  245. "mod",
  246. FuncSignature(
  247. [RuntimeArg("m", int_rprimitive), RuntimeArg("n", int_rprimitive)], int_rprimitive
  248. ),
  249. )
  250. self.assert_emit(
  251. Call(decl, [self.m, self.k], 55), "cpy_r_r0 = CPyDef_myfn(cpy_r_m, cpy_r_k);"
  252. )
  253. def test_inc_ref(self) -> None:
  254. self.assert_emit(IncRef(self.o), "CPy_INCREF(cpy_r_o);")
  255. self.assert_emit(IncRef(self.o), "CPy_INCREF(cpy_r_o);", rare=True)
  256. def test_dec_ref(self) -> None:
  257. self.assert_emit(DecRef(self.o), "CPy_DECREF(cpy_r_o);")
  258. self.assert_emit(DecRef(self.o), "CPy_DecRef(cpy_r_o);", rare=True)
  259. def test_inc_ref_int(self) -> None:
  260. self.assert_emit(IncRef(self.m), "CPyTagged_INCREF(cpy_r_m);")
  261. self.assert_emit(IncRef(self.m), "CPyTagged_IncRef(cpy_r_m);", rare=True)
  262. def test_dec_ref_int(self) -> None:
  263. self.assert_emit(DecRef(self.m), "CPyTagged_DECREF(cpy_r_m);")
  264. self.assert_emit(DecRef(self.m), "CPyTagged_DecRef(cpy_r_m);", rare=True)
  265. def test_dec_ref_tuple(self) -> None:
  266. self.assert_emit(DecRef(self.t), "CPyTagged_DECREF(cpy_r_t.f0);")
  267. def test_dec_ref_tuple_nested(self) -> None:
  268. self.assert_emit(DecRef(self.tt), "CPyTagged_DECREF(cpy_r_tt.f0.f0);")
  269. def test_list_get_item(self) -> None:
  270. self.assert_emit(
  271. CallC(
  272. list_get_item_op.c_function_name,
  273. [self.m, self.k],
  274. list_get_item_op.return_type,
  275. list_get_item_op.steals,
  276. list_get_item_op.is_borrowed,
  277. list_get_item_op.error_kind,
  278. 55,
  279. ),
  280. """cpy_r_r0 = CPyList_GetItem(cpy_r_m, cpy_r_k);""",
  281. )
  282. def test_list_set_item(self) -> None:
  283. self.assert_emit(
  284. CallC(
  285. list_set_item_op.c_function_name,
  286. [self.l, self.n, self.o],
  287. list_set_item_op.return_type,
  288. list_set_item_op.steals,
  289. list_set_item_op.is_borrowed,
  290. list_set_item_op.error_kind,
  291. 55,
  292. ),
  293. """cpy_r_r0 = CPyList_SetItem(cpy_r_l, cpy_r_n, cpy_r_o);""",
  294. )
  295. def test_box_int(self) -> None:
  296. self.assert_emit(Box(self.n), """cpy_r_r0 = CPyTagged_StealAsObject(cpy_r_n);""")
  297. def test_unbox_int(self) -> None:
  298. self.assert_emit(
  299. Unbox(self.m, int_rprimitive, 55),
  300. """if (likely(PyLong_Check(cpy_r_m)))
  301. cpy_r_r0 = CPyTagged_FromObject(cpy_r_m);
  302. else {
  303. CPy_TypeError("int", cpy_r_m); cpy_r_r0 = CPY_INT_TAG;
  304. }
  305. """,
  306. )
  307. def test_box_i64(self) -> None:
  308. self.assert_emit(Box(self.i64), """cpy_r_r0 = PyLong_FromLongLong(cpy_r_i64);""")
  309. def test_unbox_i64(self) -> None:
  310. self.assert_emit(
  311. Unbox(self.o, int64_rprimitive, 55), """cpy_r_r0 = CPyLong_AsInt64(cpy_r_o);"""
  312. )
  313. def test_list_append(self) -> None:
  314. self.assert_emit(
  315. CallC(
  316. list_append_op.c_function_name,
  317. [self.l, self.o],
  318. list_append_op.return_type,
  319. list_append_op.steals,
  320. list_append_op.is_borrowed,
  321. list_append_op.error_kind,
  322. 1,
  323. ),
  324. """cpy_r_r0 = PyList_Append(cpy_r_l, cpy_r_o);""",
  325. )
  326. def test_get_attr(self) -> None:
  327. self.assert_emit(
  328. GetAttr(self.r, "y", 1),
  329. """cpy_r_r0 = ((mod___AObject *)cpy_r_r)->_y;
  330. if (unlikely(cpy_r_r0 == CPY_INT_TAG)) {
  331. PyErr_SetString(PyExc_AttributeError, "attribute 'y' of 'A' undefined");
  332. } else {
  333. CPyTagged_INCREF(cpy_r_r0);
  334. }
  335. """,
  336. )
  337. def test_get_attr_non_refcounted(self) -> None:
  338. self.assert_emit(
  339. GetAttr(self.r, "x", 1),
  340. """cpy_r_r0 = ((mod___AObject *)cpy_r_r)->_x;
  341. if (unlikely(cpy_r_r0 == 2)) {
  342. PyErr_SetString(PyExc_AttributeError, "attribute 'x' of 'A' undefined");
  343. }
  344. """,
  345. )
  346. def test_get_attr_merged(self) -> None:
  347. op = GetAttr(self.r, "y", 1)
  348. branch = Branch(op, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR)
  349. branch.traceback_entry = ("foobar", 123)
  350. self.assert_emit(
  351. op,
  352. """\
  353. cpy_r_r0 = ((mod___AObject *)cpy_r_r)->_y;
  354. if (unlikely(cpy_r_r0 == CPY_INT_TAG)) {
  355. CPy_AttributeError("prog.py", "foobar", "A", "y", 123, CPyStatic_prog___globals);
  356. goto CPyL8;
  357. }
  358. CPyTagged_INCREF(cpy_r_r0);
  359. goto CPyL9;
  360. """,
  361. next_branch=branch,
  362. skip_next=True,
  363. )
  364. def test_get_attr_with_bitmap(self) -> None:
  365. self.assert_emit(
  366. GetAttr(self.r, "i1", 1),
  367. """cpy_r_r0 = ((mod___AObject *)cpy_r_r)->_i1;
  368. if (unlikely(cpy_r_r0 == -113) && !(((mod___AObject *)cpy_r_r)->bitmap & 1)) {
  369. PyErr_SetString(PyExc_AttributeError, "attribute 'i1' of 'A' undefined");
  370. }
  371. """,
  372. )
  373. def test_set_attr(self) -> None:
  374. self.assert_emit(
  375. SetAttr(self.r, "y", self.m, 1),
  376. """if (((mod___AObject *)cpy_r_r)->_y != CPY_INT_TAG) {
  377. CPyTagged_DECREF(((mod___AObject *)cpy_r_r)->_y);
  378. }
  379. ((mod___AObject *)cpy_r_r)->_y = cpy_r_m;
  380. cpy_r_r0 = 1;
  381. """,
  382. )
  383. def test_set_attr_non_refcounted(self) -> None:
  384. self.assert_emit(
  385. SetAttr(self.r, "x", self.b, 1),
  386. """((mod___AObject *)cpy_r_r)->_x = cpy_r_b;
  387. cpy_r_r0 = 1;
  388. """,
  389. )
  390. def test_set_attr_no_error(self) -> None:
  391. op = SetAttr(self.r, "y", self.m, 1)
  392. op.error_kind = ERR_NEVER
  393. self.assert_emit(
  394. op,
  395. """if (((mod___AObject *)cpy_r_r)->_y != CPY_INT_TAG) {
  396. CPyTagged_DECREF(((mod___AObject *)cpy_r_r)->_y);
  397. }
  398. ((mod___AObject *)cpy_r_r)->_y = cpy_r_m;
  399. """,
  400. )
  401. def test_set_attr_non_refcounted_no_error(self) -> None:
  402. op = SetAttr(self.r, "x", self.b, 1)
  403. op.error_kind = ERR_NEVER
  404. self.assert_emit(
  405. op,
  406. """((mod___AObject *)cpy_r_r)->_x = cpy_r_b;
  407. """,
  408. )
  409. def test_set_attr_with_bitmap(self) -> None:
  410. # For some rtypes the error value overlaps a valid value, so we need
  411. # to use a separate bitmap to track defined attributes.
  412. self.assert_emit(
  413. SetAttr(self.r, "i1", self.i64, 1),
  414. """if (unlikely(cpy_r_i64 == -113)) {
  415. ((mod___AObject *)cpy_r_r)->bitmap |= 1;
  416. }
  417. ((mod___AObject *)cpy_r_r)->_i1 = cpy_r_i64;
  418. cpy_r_r0 = 1;
  419. """,
  420. )
  421. self.assert_emit(
  422. SetAttr(self.r, "i2", self.i32, 1),
  423. """if (unlikely(cpy_r_i32 == -113)) {
  424. ((mod___AObject *)cpy_r_r)->bitmap |= 2;
  425. }
  426. ((mod___AObject *)cpy_r_r)->_i2 = cpy_r_i32;
  427. cpy_r_r0 = 1;
  428. """,
  429. )
  430. def test_set_attr_init_with_bitmap(self) -> None:
  431. op = SetAttr(self.r, "i1", self.i64, 1)
  432. op.is_init = True
  433. self.assert_emit(
  434. op,
  435. """if (unlikely(cpy_r_i64 == -113)) {
  436. ((mod___AObject *)cpy_r_r)->bitmap |= 1;
  437. }
  438. ((mod___AObject *)cpy_r_r)->_i1 = cpy_r_i64;
  439. cpy_r_r0 = 1;
  440. """,
  441. )
  442. def test_dict_get_item(self) -> None:
  443. self.assert_emit(
  444. CallC(
  445. dict_get_item_op.c_function_name,
  446. [self.d, self.o2],
  447. dict_get_item_op.return_type,
  448. dict_get_item_op.steals,
  449. dict_get_item_op.is_borrowed,
  450. dict_get_item_op.error_kind,
  451. 1,
  452. ),
  453. """cpy_r_r0 = CPyDict_GetItem(cpy_r_d, cpy_r_o2);""",
  454. )
  455. def test_dict_set_item(self) -> None:
  456. self.assert_emit(
  457. CallC(
  458. dict_set_item_op.c_function_name,
  459. [self.d, self.o, self.o2],
  460. dict_set_item_op.return_type,
  461. dict_set_item_op.steals,
  462. dict_set_item_op.is_borrowed,
  463. dict_set_item_op.error_kind,
  464. 1,
  465. ),
  466. """cpy_r_r0 = CPyDict_SetItem(cpy_r_d, cpy_r_o, cpy_r_o2);""",
  467. )
  468. def test_dict_update(self) -> None:
  469. self.assert_emit(
  470. CallC(
  471. dict_update_op.c_function_name,
  472. [self.d, self.o],
  473. dict_update_op.return_type,
  474. dict_update_op.steals,
  475. dict_update_op.is_borrowed,
  476. dict_update_op.error_kind,
  477. 1,
  478. ),
  479. """cpy_r_r0 = CPyDict_Update(cpy_r_d, cpy_r_o);""",
  480. )
  481. def test_new_dict(self) -> None:
  482. self.assert_emit(
  483. CallC(
  484. dict_new_op.c_function_name,
  485. [],
  486. dict_new_op.return_type,
  487. dict_new_op.steals,
  488. dict_new_op.is_borrowed,
  489. dict_new_op.error_kind,
  490. 1,
  491. ),
  492. """cpy_r_r0 = PyDict_New();""",
  493. )
  494. def test_dict_contains(self) -> None:
  495. self.assert_emit_binary_op(
  496. "in", self.b, self.o, self.d, """cpy_r_r0 = PyDict_Contains(cpy_r_d, cpy_r_o);"""
  497. )
  498. def test_int_op(self) -> None:
  499. self.assert_emit(
  500. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.ADD, 1),
  501. """cpy_r_r0 = cpy_r_s1 + cpy_r_s2;""",
  502. )
  503. self.assert_emit(
  504. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.SUB, 1),
  505. """cpy_r_r0 = cpy_r_s1 - cpy_r_s2;""",
  506. )
  507. self.assert_emit(
  508. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.MUL, 1),
  509. """cpy_r_r0 = cpy_r_s1 * cpy_r_s2;""",
  510. )
  511. self.assert_emit(
  512. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.DIV, 1),
  513. """cpy_r_r0 = cpy_r_s1 / cpy_r_s2;""",
  514. )
  515. self.assert_emit(
  516. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.MOD, 1),
  517. """cpy_r_r0 = cpy_r_s1 % cpy_r_s2;""",
  518. )
  519. self.assert_emit(
  520. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.AND, 1),
  521. """cpy_r_r0 = cpy_r_s1 & cpy_r_s2;""",
  522. )
  523. self.assert_emit(
  524. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.OR, 1),
  525. """cpy_r_r0 = cpy_r_s1 | cpy_r_s2;""",
  526. )
  527. self.assert_emit(
  528. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.XOR, 1),
  529. """cpy_r_r0 = cpy_r_s1 ^ cpy_r_s2;""",
  530. )
  531. self.assert_emit(
  532. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.LEFT_SHIFT, 1),
  533. """cpy_r_r0 = cpy_r_s1 << cpy_r_s2;""",
  534. )
  535. self.assert_emit(
  536. IntOp(short_int_rprimitive, self.s1, self.s2, IntOp.RIGHT_SHIFT, 1),
  537. """cpy_r_r0 = (Py_ssize_t)cpy_r_s1 >> (Py_ssize_t)cpy_r_s2;""",
  538. )
  539. self.assert_emit(
  540. IntOp(short_int_rprimitive, self.i64, self.i64_1, IntOp.RIGHT_SHIFT, 1),
  541. """cpy_r_r0 = cpy_r_i64 >> cpy_r_i64_1;""",
  542. )
  543. def test_comparison_op(self) -> None:
  544. # signed
  545. self.assert_emit(
  546. ComparisonOp(self.s1, self.s2, ComparisonOp.SLT, 1),
  547. """cpy_r_r0 = (Py_ssize_t)cpy_r_s1 < (Py_ssize_t)cpy_r_s2;""",
  548. )
  549. self.assert_emit(
  550. ComparisonOp(self.i32, self.i32_1, ComparisonOp.SLT, 1),
  551. """cpy_r_r0 = cpy_r_i32 < cpy_r_i32_1;""",
  552. )
  553. self.assert_emit(
  554. ComparisonOp(self.i64, self.i64_1, ComparisonOp.SLT, 1),
  555. """cpy_r_r0 = cpy_r_i64 < cpy_r_i64_1;""",
  556. )
  557. # unsigned
  558. self.assert_emit(
  559. ComparisonOp(self.s1, self.s2, ComparisonOp.ULT, 1),
  560. """cpy_r_r0 = cpy_r_s1 < cpy_r_s2;""",
  561. )
  562. self.assert_emit(
  563. ComparisonOp(self.i32, self.i32_1, ComparisonOp.ULT, 1),
  564. """cpy_r_r0 = (uint32_t)cpy_r_i32 < (uint32_t)cpy_r_i32_1;""",
  565. )
  566. self.assert_emit(
  567. ComparisonOp(self.i64, self.i64_1, ComparisonOp.ULT, 1),
  568. """cpy_r_r0 = (uint64_t)cpy_r_i64 < (uint64_t)cpy_r_i64_1;""",
  569. )
  570. # object type
  571. self.assert_emit(
  572. ComparisonOp(self.o, self.o2, ComparisonOp.EQ, 1),
  573. """cpy_r_r0 = cpy_r_o == cpy_r_o2;""",
  574. )
  575. self.assert_emit(
  576. ComparisonOp(self.o, self.o2, ComparisonOp.NEQ, 1),
  577. """cpy_r_r0 = cpy_r_o != cpy_r_o2;""",
  578. )
  579. def test_load_mem(self) -> None:
  580. self.assert_emit(LoadMem(bool_rprimitive, self.ptr), """cpy_r_r0 = *(char *)cpy_r_ptr;""")
  581. def test_set_mem(self) -> None:
  582. self.assert_emit(
  583. SetMem(bool_rprimitive, self.ptr, self.b), """*(char *)cpy_r_ptr = cpy_r_b;"""
  584. )
  585. def test_get_element_ptr(self) -> None:
  586. r = RStruct(
  587. "Foo", ["b", "i32", "i64"], [bool_rprimitive, int32_rprimitive, int64_rprimitive]
  588. )
  589. self.assert_emit(
  590. GetElementPtr(self.o, r, "b"), """cpy_r_r0 = (CPyPtr)&((Foo *)cpy_r_o)->b;"""
  591. )
  592. self.assert_emit(
  593. GetElementPtr(self.o, r, "i32"), """cpy_r_r0 = (CPyPtr)&((Foo *)cpy_r_o)->i32;"""
  594. )
  595. self.assert_emit(
  596. GetElementPtr(self.o, r, "i64"), """cpy_r_r0 = (CPyPtr)&((Foo *)cpy_r_o)->i64;"""
  597. )
  598. def test_load_address(self) -> None:
  599. self.assert_emit(
  600. LoadAddress(object_rprimitive, "PyDict_Type"),
  601. """cpy_r_r0 = (PyObject *)&PyDict_Type;""",
  602. )
  603. def test_assign_multi(self) -> None:
  604. t = RArray(object_rprimitive, 2)
  605. a = Register(t, "a")
  606. self.registers.append(a)
  607. self.assert_emit(
  608. AssignMulti(a, [self.o, self.o2]), """PyObject *cpy_r_a[2] = {cpy_r_o, cpy_r_o2};"""
  609. )
  610. def test_long_unsigned(self) -> None:
  611. a = Register(int64_rprimitive, "a")
  612. self.assert_emit(
  613. Assign(a, Integer(1 << 31, int64_rprimitive)), """cpy_r_a = 2147483648LL;"""
  614. )
  615. self.assert_emit(
  616. Assign(a, Integer((1 << 31) - 1, int64_rprimitive)), """cpy_r_a = 2147483647;"""
  617. )
  618. def test_long_signed(self) -> None:
  619. a = Register(int64_rprimitive, "a")
  620. self.assert_emit(
  621. Assign(a, Integer(-(1 << 31) + 1, int64_rprimitive)), """cpy_r_a = -2147483647;"""
  622. )
  623. self.assert_emit(
  624. Assign(a, Integer(-(1 << 31), int64_rprimitive)), """cpy_r_a = -2147483648LL;"""
  625. )
  626. def test_cast_and_branch_merge(self) -> None:
  627. op = Cast(self.r, dict_rprimitive, 1)
  628. next_block = BasicBlock(9)
  629. branch = Branch(op, BasicBlock(8), next_block, Branch.IS_ERROR)
  630. branch.traceback_entry = ("foobar", 123)
  631. self.assert_emit(
  632. op,
  633. """\
  634. if (likely(PyDict_Check(cpy_r_r)))
  635. cpy_r_r0 = cpy_r_r;
  636. else {
  637. CPy_TypeErrorTraceback("prog.py", "foobar", 123, CPyStatic_prog___globals, "dict", cpy_r_r);
  638. goto CPyL8;
  639. }
  640. """,
  641. next_block=next_block,
  642. next_branch=branch,
  643. skip_next=True,
  644. )
  645. def test_cast_and_branch_no_merge_1(self) -> None:
  646. op = Cast(self.r, dict_rprimitive, 1)
  647. branch = Branch(op, BasicBlock(8), BasicBlock(9), Branch.IS_ERROR)
  648. branch.traceback_entry = ("foobar", 123)
  649. self.assert_emit(
  650. op,
  651. """\
  652. if (likely(PyDict_Check(cpy_r_r)))
  653. cpy_r_r0 = cpy_r_r;
  654. else {
  655. CPy_TypeError("dict", cpy_r_r);
  656. cpy_r_r0 = NULL;
  657. }
  658. """,
  659. next_block=BasicBlock(10),
  660. next_branch=branch,
  661. skip_next=False,
  662. )
  663. def test_cast_and_branch_no_merge_2(self) -> None:
  664. op = Cast(self.r, dict_rprimitive, 1)
  665. next_block = BasicBlock(9)
  666. branch = Branch(op, BasicBlock(8), next_block, Branch.IS_ERROR)
  667. branch.negated = True
  668. branch.traceback_entry = ("foobar", 123)
  669. self.assert_emit(
  670. op,
  671. """\
  672. if (likely(PyDict_Check(cpy_r_r)))
  673. cpy_r_r0 = cpy_r_r;
  674. else {
  675. CPy_TypeError("dict", cpy_r_r);
  676. cpy_r_r0 = NULL;
  677. }
  678. """,
  679. next_block=next_block,
  680. next_branch=branch,
  681. )
  682. def test_cast_and_branch_no_merge_3(self) -> None:
  683. op = Cast(self.r, dict_rprimitive, 1)
  684. next_block = BasicBlock(9)
  685. branch = Branch(op, BasicBlock(8), next_block, Branch.BOOL)
  686. branch.traceback_entry = ("foobar", 123)
  687. self.assert_emit(
  688. op,
  689. """\
  690. if (likely(PyDict_Check(cpy_r_r)))
  691. cpy_r_r0 = cpy_r_r;
  692. else {
  693. CPy_TypeError("dict", cpy_r_r);
  694. cpy_r_r0 = NULL;
  695. }
  696. """,
  697. next_block=next_block,
  698. next_branch=branch,
  699. )
  700. def test_cast_and_branch_no_merge_4(self) -> None:
  701. op = Cast(self.r, dict_rprimitive, 1)
  702. next_block = BasicBlock(9)
  703. branch = Branch(op, BasicBlock(8), next_block, Branch.IS_ERROR)
  704. self.assert_emit(
  705. op,
  706. """\
  707. if (likely(PyDict_Check(cpy_r_r)))
  708. cpy_r_r0 = cpy_r_r;
  709. else {
  710. CPy_TypeError("dict", cpy_r_r);
  711. cpy_r_r0 = NULL;
  712. }
  713. """,
  714. next_block=next_block,
  715. next_branch=branch,
  716. )
  717. def test_extend(self) -> None:
  718. a = Register(int32_rprimitive, "a")
  719. self.assert_emit(Extend(a, int64_rprimitive, signed=True), """cpy_r_r0 = cpy_r_a;""")
  720. self.assert_emit(
  721. Extend(a, int64_rprimitive, signed=False), """cpy_r_r0 = (uint32_t)cpy_r_a;"""
  722. )
  723. if PLATFORM_SIZE == 4:
  724. self.assert_emit(
  725. Extend(self.n, int64_rprimitive, signed=True),
  726. """cpy_r_r0 = (Py_ssize_t)cpy_r_n;""",
  727. )
  728. self.assert_emit(
  729. Extend(self.n, int64_rprimitive, signed=False), """cpy_r_r0 = cpy_r_n;"""
  730. )
  731. if PLATFORM_SIZE == 8:
  732. self.assert_emit(Extend(a, int_rprimitive, signed=True), """cpy_r_r0 = cpy_r_a;""")
  733. self.assert_emit(
  734. Extend(a, int_rprimitive, signed=False), """cpy_r_r0 = (uint32_t)cpy_r_a;"""
  735. )
  736. def assert_emit(
  737. self,
  738. op: Op,
  739. expected: str,
  740. next_block: BasicBlock | None = None,
  741. *,
  742. rare: bool = False,
  743. next_branch: Branch | None = None,
  744. skip_next: bool = False,
  745. ) -> None:
  746. block = BasicBlock(0)
  747. block.ops.append(op)
  748. value_names = generate_names_for_ir(self.registers, [block])
  749. emitter = Emitter(self.context, value_names)
  750. declarations = Emitter(self.context, value_names)
  751. emitter.fragments = []
  752. declarations.fragments = []
  753. visitor = FunctionEmitterVisitor(emitter, declarations, "prog.py", "prog")
  754. visitor.next_block = next_block
  755. visitor.rare = rare
  756. if next_branch:
  757. visitor.ops = [op, next_branch]
  758. else:
  759. visitor.ops = [op]
  760. visitor.op_index = 0
  761. op.accept(visitor)
  762. frags = declarations.fragments + emitter.fragments
  763. actual_lines = [line.strip(" ") for line in frags]
  764. assert all(line.endswith("\n") for line in actual_lines)
  765. actual_lines = [line.rstrip("\n") for line in actual_lines]
  766. if not expected.strip():
  767. expected_lines = []
  768. else:
  769. expected_lines = expected.rstrip().split("\n")
  770. expected_lines = [line.strip(" ") for line in expected_lines]
  771. assert_string_arrays_equal(expected_lines, actual_lines, msg="Generated code unexpected")
  772. if skip_next:
  773. assert visitor.op_index == 1
  774. else:
  775. assert visitor.op_index == 0
  776. def assert_emit_binary_op(
  777. self, op: str, dest: Value, left: Value, right: Value, expected: str
  778. ) -> None:
  779. if op in binary_ops:
  780. ops = binary_ops[op]
  781. for desc in ops:
  782. if is_subtype(left.type, desc.arg_types[0]) and is_subtype(
  783. right.type, desc.arg_types[1]
  784. ):
  785. args = [left, right]
  786. if desc.ordering is not None:
  787. args = [args[i] for i in desc.ordering]
  788. self.assert_emit(
  789. CallC(
  790. desc.c_function_name,
  791. args,
  792. desc.return_type,
  793. desc.steals,
  794. desc.is_borrowed,
  795. desc.error_kind,
  796. 55,
  797. ),
  798. expected,
  799. )
  800. return
  801. else:
  802. assert False, "Could not find matching op"
  803. class TestGenerateFunction(unittest.TestCase):
  804. def setUp(self) -> None:
  805. self.arg = RuntimeArg("arg", int_rprimitive)
  806. self.reg = Register(int_rprimitive, "arg")
  807. self.block = BasicBlock(0)
  808. def test_simple(self) -> None:
  809. self.block.ops.append(Return(self.reg))
  810. fn = FuncIR(
  811. FuncDecl("myfunc", None, "mod", FuncSignature([self.arg], int_rprimitive)),
  812. [self.reg],
  813. [self.block],
  814. )
  815. value_names = generate_names_for_ir(fn.arg_regs, fn.blocks)
  816. emitter = Emitter(EmitterContext(NameGenerator([["mod"]])), value_names)
  817. generate_native_function(fn, emitter, "prog.py", "prog")
  818. result = emitter.fragments
  819. assert_string_arrays_equal(
  820. ["CPyTagged CPyDef_myfunc(CPyTagged cpy_r_arg) {\n", " return cpy_r_arg;\n", "}\n"],
  821. result,
  822. msg="Generated code invalid",
  823. )
  824. def test_register(self) -> None:
  825. reg = Register(int_rprimitive)
  826. op = Assign(reg, Integer(5))
  827. self.block.ops.append(op)
  828. self.block.ops.append(Unreachable())
  829. fn = FuncIR(
  830. FuncDecl("myfunc", None, "mod", FuncSignature([self.arg], list_rprimitive)),
  831. [self.reg],
  832. [self.block],
  833. )
  834. value_names = generate_names_for_ir(fn.arg_regs, fn.blocks)
  835. emitter = Emitter(EmitterContext(NameGenerator([["mod"]])), value_names)
  836. generate_native_function(fn, emitter, "prog.py", "prog")
  837. result = emitter.fragments
  838. assert_string_arrays_equal(
  839. [
  840. "PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n",
  841. " CPyTagged cpy_r_r0;\n",
  842. " cpy_r_r0 = 10;\n",
  843. " CPy_Unreachable();\n",
  844. "}\n",
  845. ],
  846. result,
  847. msg="Generated code invalid",
  848. )