@@ -2224,5 +2224,202 @@ def test_validate_uop_unused_size_mismatch(self):
22242224 "Inputs must have equal sizes" ):
22252225 self .run_cases_test (input , input2 , output )
22262226
2227+ def test_pure_uop_body_copied_in (self ):
2228+ # Note: any non-escaping call works.
2229+ # In this case, we use PyStackRef_IsNone.
2230+ input = """
2231+ pure op(OP, (foo -- res)) {
2232+ res = PyStackRef_IsNone(foo);
2233+ }
2234+ """
2235+ input2 = """
2236+ op(OP, (foo -- res)) {
2237+ REPLACE_OPCODE_IF_EVALUATES_PURE(foo);
2238+ res = sym_new_known(ctx, foo);
2239+ }
2240+ """
2241+ output = """
2242+ case OP: {
2243+ JitOptRef foo;
2244+ JitOptRef res;
2245+ foo = stack_pointer[-1];
2246+ if (
2247+ sym_is_safe_const(ctx, foo)
2248+ ) {
2249+ JitOptRef foo_sym = foo;
2250+ _PyStackRef foo = sym_get_const_as_stackref(ctx, foo_sym);
2251+ _PyStackRef res_stackref;
2252+ /* Start of uop copied from bytecodes for constant evaluation */
2253+ res_stackref = PyStackRef_IsNone(foo);
2254+ /* End of uop copied from bytecodes for constant evaluation */
2255+ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
2256+ stack_pointer[-1] = res;
2257+ break;
2258+ }
2259+ res = sym_new_known(ctx, foo);
2260+ stack_pointer[-1] = res;
2261+ break;
2262+ }
2263+ """
2264+ self .run_cases_test (input , input2 , output )
2265+
2266+ def test_pure_uop_body_copied_in_deopt (self ):
2267+ # Note: any non-escaping call works.
2268+ # In this case, we use PyStackRef_IsNone.
2269+ input = """
2270+ pure op(OP, (foo -- res)) {
2271+ DEOPT_IF(PyStackRef_IsNull(foo));
2272+ res = foo;
2273+ }
2274+ """
2275+ input2 = """
2276+ op(OP, (foo -- res)) {
2277+ REPLACE_OPCODE_IF_EVALUATES_PURE(foo);
2278+ res = foo;
2279+ }
2280+ """
2281+ output = """
2282+ case OP: {
2283+ JitOptRef foo;
2284+ JitOptRef res;
2285+ foo = stack_pointer[-1];
2286+ if (
2287+ sym_is_safe_const(ctx, foo)
2288+ ) {
2289+ JitOptRef foo_sym = foo;
2290+ _PyStackRef foo = sym_get_const_as_stackref(ctx, foo_sym);
2291+ _PyStackRef res_stackref;
2292+ /* Start of uop copied from bytecodes for constant evaluation */
2293+ if (PyStackRef_IsNull(foo)) {
2294+ ctx->done = true;
2295+ break;
2296+ }
2297+ res_stackref = foo;
2298+ /* End of uop copied from bytecodes for constant evaluation */
2299+ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
2300+ stack_pointer[-1] = res;
2301+ break;
2302+ }
2303+ res = foo;
2304+ stack_pointer[-1] = res;
2305+ break;
2306+ }
2307+ """
2308+ self .run_cases_test (input , input2 , output )
2309+
2310+ def test_pure_uop_body_copied_in_error_if (self ):
2311+ # Note: any non-escaping call works.
2312+ # In this case, we use PyStackRef_IsNone.
2313+ input = """
2314+ pure op(OP, (foo -- res)) {
2315+ ERROR_IF(PyStackRef_IsNull(foo));
2316+ res = foo;
2317+ }
2318+ """
2319+ input2 = """
2320+ op(OP, (foo -- res)) {
2321+ REPLACE_OPCODE_IF_EVALUATES_PURE(foo);
2322+ res = foo;
2323+ }
2324+ """
2325+ output = """
2326+ case OP: {
2327+ JitOptRef foo;
2328+ JitOptRef res;
2329+ foo = stack_pointer[-1];
2330+ if (
2331+ sym_is_safe_const(ctx, foo)
2332+ ) {
2333+ JitOptRef foo_sym = foo;
2334+ _PyStackRef foo = sym_get_const_as_stackref(ctx, foo_sym);
2335+ _PyStackRef res_stackref;
2336+ /* Start of uop copied from bytecodes for constant evaluation */
2337+ if (PyStackRef_IsNull(foo)) {
2338+ goto error;
2339+ }
2340+ res_stackref = foo;
2341+ /* End of uop copied from bytecodes for constant evaluation */
2342+ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
2343+ stack_pointer[-1] = res;
2344+ break;
2345+ }
2346+ res = foo;
2347+ stack_pointer[-1] = res;
2348+ break;
2349+ }
2350+ """
2351+ self .run_cases_test (input , input2 , output )
2352+
2353+
2354+ def test_replace_opcode_uop_body_copied_in_complex (self ):
2355+ input = """
2356+ pure op(OP, (foo -- res)) {
2357+ if (foo) {
2358+ res = PyStackRef_IsNone(foo);
2359+ }
2360+ else {
2361+ res = 1;
2362+ }
2363+ }
2364+ """
2365+ input2 = """
2366+ op(OP, (foo -- res)) {
2367+ REPLACE_OPCODE_IF_EVALUATES_PURE(foo);
2368+ res = sym_new_known(ctx, foo);
2369+ }
2370+ """
2371+ output = """
2372+ case OP: {
2373+ JitOptRef foo;
2374+ JitOptRef res;
2375+ foo = stack_pointer[-1];
2376+ if (
2377+ sym_is_safe_const(ctx, foo)
2378+ ) {
2379+ JitOptRef foo_sym = foo;
2380+ _PyStackRef foo = sym_get_const_as_stackref(ctx, foo_sym);
2381+ _PyStackRef res_stackref;
2382+ /* Start of uop copied from bytecodes for constant evaluation */
2383+ if (foo) {
2384+ res_stackref = PyStackRef_IsNone(foo);
2385+ }
2386+ else {
2387+ res_stackref = 1;
2388+ }
2389+ /* End of uop copied from bytecodes for constant evaluation */
2390+ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
2391+ stack_pointer[-1] = res;
2392+ break;
2393+ }
2394+ res = sym_new_known(ctx, foo);
2395+ stack_pointer[-1] = res;
2396+ break;
2397+ }
2398+ """
2399+ self .run_cases_test (input , input2 , output )
2400+
2401+ def test_replace_opocode_uop_reject_array_effects (self ):
2402+ input = """
2403+ pure op(OP, (foo[2] -- res)) {
2404+ if (foo) {
2405+ res = PyStackRef_IsNone(foo);
2406+ }
2407+ else {
2408+ res = 1;
2409+ }
2410+ }
2411+ """
2412+ input2 = """
2413+ op(OP, (foo[2] -- res)) {
2414+ REPLACE_OPCODE_IF_EVALUATES_PURE(foo);
2415+ res = sym_new_unknown(ctx);
2416+ }
2417+ """
2418+ output = """
2419+ """
2420+ with self .assertRaisesRegex (SyntaxError ,
2421+ "Pure evaluation cannot take array-like inputs" ):
2422+ self .run_cases_test (input , input2 , output )
2423+
22272424if __name__ == "__main__" :
22282425 unittest .main ()
0 commit comments