[Python-checkins] r86724 - in python/branches/dmalcolm-ast-optimization-branch: Include/Python-ast.h Lib/__optimizer__.py Lib/test/test_optimize.py Parser/Python.asdl Python/Python-ast.c Python/compile.c
david.malcolm
python-checkins at python.org
Wed Nov 24 00:46:30 CET 2010
Author: david.malcolm
Date: Wed Nov 24 00:46:30 2010
New Revision: 86724
Log:
Get more of the machinery for methodcall inlining working
Introduce "identifier expected_value" field within ast.Specialize (for supporting method calls and nested functions)
Modified:
python/branches/dmalcolm-ast-optimization-branch/Include/Python-ast.h
python/branches/dmalcolm-ast-optimization-branch/Lib/__optimizer__.py
python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py
python/branches/dmalcolm-ast-optimization-branch/Parser/Python.asdl
python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c
python/branches/dmalcolm-ast-optimization-branch/Python/compile.c
Modified: python/branches/dmalcolm-ast-optimization-branch/Include/Python-ast.h
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Include/Python-ast.h (original)
+++ python/branches/dmalcolm-ast-optimization-branch/Include/Python-ast.h Wed Nov 24 00:46:30 2010
@@ -281,6 +281,7 @@
struct {
expr_ty name;
+ identifier expected_value;
asdl_seq *specialized_body;
expr_ty specialized_result;
expr_ty generalized;
@@ -513,10 +514,10 @@
expr_ty _Py_Bytes(string s, int lineno, int col_offset, PyArena *arena);
#define Ellipsis(a0, a1, a2) _Py_Ellipsis(a0, a1, a2)
expr_ty _Py_Ellipsis(int lineno, int col_offset, PyArena *arena);
-#define Specialize(a0, a1, a2, a3, a4, a5, a6) _Py_Specialize(a0, a1, a2, a3, a4, a5, a6)
-expr_ty _Py_Specialize(expr_ty name, asdl_seq * specialized_body, expr_ty
- specialized_result, expr_ty generalized, int lineno, int
- col_offset, PyArena *arena);
+#define Specialize(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Specialize(a0, a1, a2, a3, a4, a5, a6, a7)
+expr_ty _Py_Specialize(expr_ty name, identifier expected_value, asdl_seq *
+ specialized_body, expr_ty specialized_result, expr_ty
+ generalized, int lineno, int col_offset, PyArena *arena);
#define Attribute(a0, a1, a2, a3, a4, a5) _Py_Attribute(a0, a1, a2, a3, a4, a5)
expr_ty _Py_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int
lineno, int col_offset, PyArena *arena);
Modified: python/branches/dmalcolm-ast-optimization-branch/Lib/__optimizer__.py
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Lib/__optimizer__.py (original)
+++ python/branches/dmalcolm-ast-optimization-branch/Lib/__optimizer__.py Wed Nov 24 00:46:30 2010
@@ -293,6 +293,7 @@
parent_nsp = NamespacePath.from_node_path(path).get_parent_path()
return parent_nsp.as_dotted_str() + '.' + attr.attr
# FIXME: only makes sense to traverse within this class and within subclasses
+# FIXME: fake the MRO and pick an appropriate class
# Don't try to inline where the function is a non-trivial
# expression e.g. "f()()", or for other awkward cases
@@ -315,18 +316,17 @@
self.log('Got inlinable callsite of:\n dotted_name: %r\n path: %s\n node:%s'
% (dotted_name, path, ast.dump(call)))
- if isinstance(call.func, ast.Attribute):
- # Don't try to inline method calls yet:
- self.log('Not inlining attribute %s' % ast.dump(call.func))
- return call
-
if not isinstance(call.func, (ast.Name, ast.Attribute)):
# Don't try to inline where the function is a non-trivial
# expression e.g. "f()()"
print('foo!')
return call
- # FIXME
+ if isinstance(call.func, ast.Attribute):
+ # Emergency cutoff for method inlining:
+ if 0:
+ self.log('Not inlining attribute %s' % ast.dump(call.func))
+ return call
self.log('Considering call to: %s' % ast.dump(call.func))
self.log('NodePath: %r' % path)
@@ -347,7 +347,7 @@
funcdef = self.def_dict[dotted_name]
self.log(ast.dump(funcdef))
- varprefix = '__inline_%s%x__' % (dotted_name, id(call))
+ varprefix = '__internal__inline_%s%x__' % (dotted_name.replace('.', '_'), id(call))
self.log('varprefix: %s' % varprefix)
# Generate a body of specialized statements that can replace the call:
@@ -399,6 +399,7 @@
call)
return ast.copy_location(ast.Specialize(name=call.func,
+ expected_value='__internal__.saved.' + dotted_name,
generalized=call,
specialized_body=specialized,
specialized_result=specialized_result),
@@ -792,7 +793,7 @@
# For now restrict ourselves to just a few places:
def is_test_code(t, filename):
- if filename.endswith('test_optimize.py'):
+ if filename == 'optimizable.py':
return True
for n in ast.walk(t):
if isinstance(n, ast.FunctionDef):
@@ -800,6 +801,14 @@
return True
return False
+def dump_dot(t, filename):
+ return False
+ for n in ast.walk(t):
+ if isinstance(n, ast.FunctionDef):
+ if n.name == 'simple_method':
+ return True
+ return False
+
#class OptimizationError(Exception):
# def __init__(self
@@ -815,9 +824,10 @@
# pprint(t)
# log(ast.dump(t))
- #dot_to_png(to_dot(t), 'before.png')
-
if isinstance(t, ast.Module):
+ if dump_dot(t, filename):
+ dot_to_png(to_dot(t), 'before.png')
+
t = _inline_function_calls(t)
#cfg = CFG.from_ast(t)
#print(cfg.to_dot())
@@ -827,11 +837,14 @@
t = _remove_redundant_locals(t)
- #dot_to_png(to_dot(t), 'after.png')
+ if dump_dot(t, filename):
+ dot_to_png(to_dot(t), 'after.png')
except:
print('Exception during optimization of %r' % filename)
# dot_to_png(dot_before, 'before.png')
raise
#print('finished optimizing')
+ #if filename == 'optimizable.py':
+ # print(ast.dump(t))
return t
Modified: python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py (original)
+++ python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py Wed Nov 24 00:46:30 2010
@@ -88,7 +88,7 @@
def compile_to_code(self, src, fnname):
# Compile the given source code, returning the code object for the given function name
- co = compile(src, 'test_optimize.py', 'exec')
+ co = compile(src, 'optimizable.py', 'exec')
return get_code_for_fn(co, fnname)
def test_simple_inlining(self):
@@ -233,7 +233,7 @@
def h(x, y):
return g(x, y, 0)
'''
- co = compile(src, 'test_optimize.py', 'exec')
+ co = compile(src, 'optimizable.py', 'exec')
g = get_code_for_fn(co, 'g')
h = get_code_for_fn(co, 'h')
co_asm = disassemble(co)
@@ -407,9 +407,7 @@
return self.bar + a + self.baz
def user_of_method(self):
- print(self.simple_method(1))
- print(self.simple_method(2))
- print(self.simple_method(3))
+ return self.simple_method(10)
'''
# "Foo.simple_method" should be inlinable
@@ -426,6 +424,11 @@
fn = self.compile_to_code(src, 'Foo.user_of_method')
asm = disassemble(fn)
#print(asm)
+ self.assertHasLineWith(asm,
+ ('LOAD_GLOBAL', '(__internal__.saved.Foo.simple_method)'))
+ self.assertIn('JUMP_IF_SPECIALIZABLE', asm)
+
+
def test_namespaces(self):
Modified: python/branches/dmalcolm-ast-optimization-branch/Parser/Python.asdl
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Parser/Python.asdl (original)
+++ python/branches/dmalcolm-ast-optimization-branch/Parser/Python.asdl Wed Nov 24 00:46:30 2010
@@ -74,6 +74,7 @@
-- Generated by the optimizer:
| Specialize(expr name,
+ identifier expected_value,
stmt* specialized_body,
expr specialized_result,
expr generalized) -- must be a Call
Modified: python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c (original)
+++ python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c Wed Nov 24 00:46:30 2010
@@ -244,6 +244,7 @@
static PyTypeObject *Specialize_type;
static char *Specialize_fields[]={
"name",
+ "expected_value",
"specialized_body",
"specialized_result",
"generalized",
@@ -758,7 +759,7 @@
Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0);
if (!Ellipsis_type) return 0;
Specialize_type = make_type("Specialize", expr_type, Specialize_fields,
- 4);
+ 5);
if (!Specialize_type) return 0;
Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3);
if (!Attribute_type) return 0;
@@ -1831,9 +1832,9 @@
}
expr_ty
-Specialize(expr_ty name, asdl_seq * specialized_body, expr_ty
- specialized_result, expr_ty generalized, int lineno, int col_offset,
- PyArena *arena)
+Specialize(expr_ty name, identifier expected_value, asdl_seq *
+ specialized_body, expr_ty specialized_result, expr_ty generalized,
+ int lineno, int col_offset, PyArena *arena)
{
expr_ty p;
if (!name) {
@@ -1841,6 +1842,11 @@
"field name is required for Specialize");
return NULL;
}
+ if (!expected_value) {
+ PyErr_SetString(PyExc_ValueError,
+ "field expected_value is required for Specialize");
+ return NULL;
+ }
if (!specialized_result) {
PyErr_SetString(PyExc_ValueError,
"field specialized_result is required for Specialize");
@@ -1856,6 +1862,7 @@
return NULL;
p->kind = Specialize_kind;
p->v.Specialize.name = name;
+ p->v.Specialize.expected_value = expected_value;
p->v.Specialize.specialized_body = specialized_body;
p->v.Specialize.specialized_result = specialized_result;
p->v.Specialize.generalized = generalized;
@@ -2975,6 +2982,12 @@
if (PyObject_SetAttrString(result, "name", value) == -1)
goto failed;
Py_DECREF(value);
+ value = ast2obj_identifier(o->v.Specialize.expected_value, st);
+ if (!value) goto failed;
+ if (PyObject_SetAttrString(result, "expected_value", value) ==
+ -1)
+ goto failed;
+ Py_DECREF(value);
value = ast2obj_list(o->v.Specialize.specialized_body,
ast2obj_stmt, st);
if (!value) goto failed;
@@ -5760,6 +5773,7 @@
}
if (isinstance) {
expr_ty name;
+ identifier expected_value;
asdl_seq* specialized_body;
expr_ty specialized_result;
expr_ty generalized;
@@ -5776,6 +5790,18 @@
PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from Specialize");
return 1;
}
+ if (PyObject_HasAttrString(obj, "expected_value")) {
+ int res;
+ tmp = PyObject_GetAttrString(obj, "expected_value");
+ if (tmp == NULL) goto failed;
+ res = obj2ast_identifier(tmp, &expected_value, arena);
+ if (res != 0) goto failed;
+ Py_XDECREF(tmp);
+ tmp = NULL;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "required field \"expected_value\" missing from Specialize");
+ return 1;
+ }
if (PyObject_HasAttrString(obj, "specialized_body")) {
int res;
Py_ssize_t len;
@@ -5825,8 +5851,9 @@
PyErr_SetString(PyExc_TypeError, "required field \"generalized\" missing from Specialize");
return 1;
}
- *out = Specialize(name, specialized_body, specialized_result,
- generalized, lineno, col_offset, arena);
+ *out = Specialize(name, expected_value, specialized_body,
+ specialized_result, generalized, lineno,
+ col_offset, arena);
if (*out == NULL) goto failed;
return 0;
}
Modified: python/branches/dmalcolm-ast-optimization-branch/Python/compile.c
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Python/compile.c (original)
+++ python/branches/dmalcolm-ast-optimization-branch/Python/compile.c Wed Nov 24 00:46:30 2010
@@ -398,7 +398,7 @@
NULL);
if (!py_ast_out)
goto finally;
-
+
/* 4. Convert the python objects back to an AST: */
new_mod = PyAST_obj2mod(py_ast_out, c->c_arena, mode);
if (!new_mod)
@@ -3252,7 +3252,7 @@
{
basicblock *specialized, *generalized, *end;
expr_ty call;
- identifier id;
+ identifier expected_value;
PyObject *saved_name = NULL;
assert(e->kind == Specialize_kind);
@@ -3267,12 +3267,9 @@
VISIT(c, expr, e->v.Specialize.name);
/* Push the expected version of the name, it will be the new TOS */
- /* For now, look for a global named "__saved__" + funcname */
- if (e->v.Specialize.name->kind != Name_kind)
- return 0;
- id = e->v.Specialize.name->v.Name.id;
- assert(id);
- saved_name = PyUnicode_FromFormat("__internal__.saved.%U", id);
+ expected_value = e->v.Specialize.expected_value;
+ assert(expected_value);
+ saved_name = PyUnicode_FromFormat("%U", expected_value); // FIXME
if (!saved_name)
return 0;
ADDOP_O(c, LOAD_GLOBAL, saved_name, names); /* takes ownership of the reference */
More information about the Python-checkins
mailing list