Skip to content

Commit 62c544e

Browse files
committed
Add new file
1 parent b10960f commit 62c544e

File tree

1 file changed

+333
-0
lines changed

1 file changed

+333
-0
lines changed

Python/optimizer_symbols.c

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
2+
#include "Python.h"
3+
4+
#include "cpython/optimizer.h"
5+
#include "pycore_code.h"
6+
#include "pycore_frame.h"
7+
#include "pycore_optimizer.h"
8+
9+
#include <stdbool.h>
10+
#include <stdint.h>
11+
#include <stddef.h>
12+
13+
// Flags for below.
14+
#define KNOWN 1 << 0
15+
#define TRUE_CONST 1 << 1
16+
#define IS_NULL 1 << 2
17+
#define NOT_NULL 1 << 3
18+
19+
#ifdef Py_DEBUG
20+
static inline int get_lltrace(void) {
21+
char *uop_debug = Py_GETENV("PYTHON_OPT_DEBUG");
22+
int lltrace = 0;
23+
if (uop_debug != NULL && *uop_debug >= '0') {
24+
lltrace = *uop_debug - '0'; // TODO: Parse an int and all that
25+
}
26+
return lltrace;
27+
}
28+
#define DPRINTF(level, ...) \
29+
if (get_lltrace() >= (level)) { printf(__VA_ARGS__); }
30+
#else
31+
#define DPRINTF(level, ...)
32+
#endif
33+
34+
// Takes a borrowed reference to const_val, turns that into a strong reference.
35+
static _Py_UOpsSymType*
36+
sym_new(_Py_UOpsAbstractInterpContext *ctx,
37+
PyObject *const_val)
38+
{
39+
_Py_UOpsSymType *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number];
40+
if (ctx->t_arena.ty_curr_number >= ctx->t_arena.ty_max_number) {
41+
OPT_STAT_INC(optimizer_failure_reason_no_memory);
42+
DPRINTF(1, "out of space for symbolic expression type\n");
43+
return NULL;
44+
}
45+
ctx->t_arena.ty_curr_number++;
46+
self->const_val = NULL;
47+
self->typ = NULL;
48+
self->flags = 0;
49+
50+
if (const_val != NULL) {
51+
self->const_val = Py_NewRef(const_val);
52+
}
53+
54+
return self;
55+
}
56+
57+
static inline void
58+
sym_set_flag(_Py_UOpsSymType *sym, int flag)
59+
{
60+
sym->flags |= flag;
61+
}
62+
63+
static inline bool
64+
sym_has_flag(_Py_UOpsSymType *sym, int flag)
65+
{
66+
return (sym->flags & flag) != 0;
67+
}
68+
69+
bool
70+
_Py_uop_sym_is_not_null(_Py_UOpsSymType *sym)
71+
{
72+
return (sym->flags & (IS_NULL | NOT_NULL)) == NOT_NULL;
73+
}
74+
75+
bool
76+
_Py_uop_sym_is_null(_Py_UOpsSymType *sym)
77+
{
78+
return (sym->flags & (IS_NULL | NOT_NULL)) == IS_NULL;
79+
}
80+
81+
bool
82+
_Py_uop_sym_is_const(_Py_UOpsSymType *sym)
83+
{
84+
return (sym->flags & TRUE_CONST) != 0;
85+
}
86+
87+
PyObject *
88+
_Py_uop_sym_get_const(_Py_UOpsSymType *sym)
89+
{
90+
assert(_Py_uop_sym_is_const(sym));
91+
assert(sym->const_val);
92+
return sym->const_val;
93+
}
94+
95+
void
96+
_Py_uop_sym_set_type(_Py_UOpsSymType *sym, PyTypeObject *tp)
97+
{
98+
assert(PyType_Check(tp));
99+
sym->typ = tp;
100+
sym_set_flag(sym, KNOWN);
101+
sym_set_flag(sym, NOT_NULL);
102+
}
103+
104+
void
105+
_Py_uop_sym_set_null(_Py_UOpsSymType *sym)
106+
{
107+
sym_set_flag(sym, IS_NULL);
108+
sym_set_flag(sym, KNOWN);
109+
}
110+
111+
112+
_Py_UOpsSymType *
113+
_Py_uop_sym_new_unknown(_Py_UOpsAbstractInterpContext *ctx)
114+
{
115+
return sym_new(ctx,NULL);
116+
}
117+
118+
_Py_UOpsSymType *
119+
_Py_uop_sym_new_notnull(_Py_UOpsAbstractInterpContext *ctx)
120+
{
121+
_Py_UOpsSymType *res = _Py_uop_sym_new_unknown(ctx);
122+
if (res == NULL) {
123+
return NULL;
124+
}
125+
sym_set_flag(res, KNOWN);
126+
sym_set_flag(res, NOT_NULL);
127+
return res;
128+
}
129+
130+
_Py_UOpsSymType *
131+
_Py_uop_sym_new_type(_Py_UOpsAbstractInterpContext *ctx,
132+
PyTypeObject *typ)
133+
{
134+
_Py_UOpsSymType *res = sym_new(ctx,NULL);
135+
if (res == NULL) {
136+
return NULL;
137+
}
138+
_Py_uop_sym_set_type(res, typ);
139+
return res;
140+
}
141+
142+
// Takes a borrowed reference to const_val.
143+
_Py_UOpsSymType*
144+
_Py_uop_sym_new_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val)
145+
{
146+
assert(const_val != NULL);
147+
_Py_UOpsSymType *temp = sym_new(
148+
ctx,
149+
const_val
150+
);
151+
if (temp == NULL) {
152+
return NULL;
153+
}
154+
_Py_uop_sym_set_type(temp, Py_TYPE(const_val));
155+
sym_set_flag(temp, TRUE_CONST);
156+
sym_set_flag(temp, KNOWN);
157+
sym_set_flag(temp, NOT_NULL);
158+
return temp;
159+
}
160+
161+
_Py_UOpsSymType*
162+
_Py_uop_sym_new_null(_Py_UOpsAbstractInterpContext *ctx)
163+
{
164+
_Py_UOpsSymType *null_sym = _Py_uop_sym_new_unknown(ctx);
165+
if (null_sym == NULL) {
166+
return NULL;
167+
}
168+
_Py_uop_sym_set_null(null_sym);
169+
return null_sym;
170+
}
171+
172+
bool
173+
_Py_uop_sym_matches_type(_Py_UOpsSymType *sym, PyTypeObject *typ)
174+
{
175+
assert(typ == NULL || PyType_Check(typ));
176+
if (!sym_has_flag(sym, KNOWN)) {
177+
return false;
178+
}
179+
return sym->typ == typ;
180+
}
181+
182+
// 0 on success, -1 on error.
183+
_Py_UOpsAbstractFrame *
184+
_Py_uop_ctx_frame_new(
185+
_Py_UOpsAbstractInterpContext *ctx,
186+
PyCodeObject *co,
187+
_Py_UOpsSymType **localsplus_start,
188+
int n_locals_already_filled,
189+
int curr_stackentries
190+
)
191+
{
192+
assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH);
193+
_Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth];
194+
195+
frame->stack_len = co->co_stacksize;
196+
frame->locals_len = co->co_nlocalsplus;
197+
198+
frame->locals = localsplus_start;
199+
frame->stack = frame->locals + co->co_nlocalsplus;
200+
frame->stack_pointer = frame->stack + curr_stackentries;
201+
ctx->n_consumed = localsplus_start + (co->co_nlocalsplus + co->co_stacksize);
202+
if (ctx->n_consumed >= ctx->limit) {
203+
return NULL;
204+
}
205+
206+
207+
// Initialize with the initial state of all local variables
208+
for (int i = n_locals_already_filled; i < co->co_nlocalsplus; i++) {
209+
_Py_UOpsSymType *local = _Py_uop_sym_new_unknown(ctx);
210+
if (local == NULL) {
211+
return NULL;
212+
}
213+
frame->locals[i] = local;
214+
}
215+
216+
217+
// Initialize the stack as well
218+
for (int i = 0; i < curr_stackentries; i++) {
219+
_Py_UOpsSymType *stackvar = _Py_uop_sym_new_unknown(ctx);
220+
if (stackvar == NULL) {
221+
return NULL;
222+
}
223+
frame->stack[i] = stackvar;
224+
}
225+
226+
return frame;
227+
}
228+
229+
void
230+
_Py_uop_abstractcontext_fini(_Py_UOpsAbstractInterpContext *ctx)
231+
{
232+
if (ctx == NULL) {
233+
return;
234+
}
235+
ctx->curr_frame_depth = 0;
236+
int tys = ctx->t_arena.ty_curr_number;
237+
for (int i = 0; i < tys; i++) {
238+
Py_CLEAR(ctx->t_arena.arena[i].const_val);
239+
}
240+
}
241+
242+
int
243+
_Py_uop_abstractcontext_init(
244+
_Py_UOpsAbstractInterpContext *ctx
245+
)
246+
{
247+
ctx->limit = ctx->locals_and_stack + MAX_ABSTRACT_INTERP_SIZE;
248+
ctx->n_consumed = ctx->locals_and_stack;
249+
#ifdef Py_DEBUG // Aids debugging a little. There should never be NULL in the abstract interpreter.
250+
for (int i = 0 ; i < MAX_ABSTRACT_INTERP_SIZE; i++) {
251+
ctx->locals_and_stack[i] = NULL;
252+
}
253+
#endif
254+
255+
// Setup the arena for sym expressions.
256+
ctx->t_arena.ty_curr_number = 0;
257+
ctx->t_arena.ty_max_number = TY_ARENA_SIZE;
258+
259+
// Frame setup
260+
ctx->curr_frame_depth = 0;
261+
262+
return 0;
263+
}
264+
265+
int
266+
_Py_uop_ctx_frame_pop(
267+
_Py_UOpsAbstractInterpContext *ctx
268+
)
269+
{
270+
_Py_UOpsAbstractFrame *frame = ctx->frame;
271+
272+
ctx->n_consumed = frame->locals;
273+
ctx->curr_frame_depth--;
274+
assert(ctx->curr_frame_depth >= 1);
275+
ctx->frame = &ctx->frames[ctx->curr_frame_depth - 1];
276+
277+
return 0;
278+
}
279+
280+
#define TEST_PREDICATE(PRED, MSG) \
281+
do { \
282+
if (!(PRED)) { \
283+
PyErr_SetString( \
284+
PyExc_AssertionError, \
285+
(MSG)); \
286+
goto fail; \
287+
} \
288+
} while (0)
289+
290+
/*
291+
static _Py_UOpsSymType *
292+
make_top(_Py_UOpsAbstractInterpContext *ctx)
293+
{
294+
_Py_UOpsSymType *top = _Py_uop_sym_new_unknown(ctx);
295+
_Py_uop_sym_set_null(top);
296+
_Py_uop_sym_set_type(top, &PyLong_Type);
297+
return top;
298+
}*/
299+
300+
PyObject *
301+
_Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
302+
{
303+
_Py_UOpsAbstractInterpContext context;
304+
_Py_UOpsAbstractInterpContext *ctx = &context;
305+
_Py_uop_abstractcontext_init(ctx);
306+
307+
_Py_UOpsSymType *bottom = _Py_uop_sym_new_unknown(ctx);
308+
if (bottom == NULL) {
309+
return NULL;
310+
}
311+
TEST_PREDICATE(!_Py_uop_sym_is_null(bottom), "unknown is NULL");
312+
TEST_PREDICATE(!_Py_uop_sym_is_not_null(bottom), "unknown is not NULL");
313+
TEST_PREDICATE(!_Py_uop_sym_is_const(bottom), "unknown is a constant");
314+
// TEST_PREDICATE(_Py_uop_sym_get_const(bottom) == NULL, "unknown as constant is not NULL");
315+
316+
// _Py_UOpsSymType *top = make_top(ctx);
317+
// TEST_PREDICATE(_Py_uop_sym_is_null(top), "top is NULL is not true");
318+
// TEST_PREDICATE(_Py_uop_sym_is_not_null(top), "top is not NULL is not true");
319+
// TEST_PREDICATE(_Py_uop_sym_is_const(top), "top is a constant is not true");
320+
321+
_Py_UOpsSymType *int_type = _Py_uop_sym_new_type(ctx, &PyLong_Type);
322+
TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type");
323+
_Py_uop_sym_set_type(int_type, &PyLong_Type);
324+
TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "inconsistent type");
325+
_Py_uop_sym_set_type(int_type, &PyFloat_Type);
326+
// git TEST_PREDICATE(_Py_uop_sym_matches_type(int_type, &PyLong_Type), "top doesn't match int");
327+
328+
_Py_uop_abstractcontext_fini(ctx);
329+
Py_RETURN_NONE;
330+
fail:
331+
_Py_uop_abstractcontext_fini(ctx);
332+
return NULL;
333+
}

0 commit comments

Comments
 (0)