Skip to content

Commit 0427e73

Browse files
committed
Expose APIs for getting at variables and their initializers, and start adding a test suite for the plugin API
- Add gcc.Variable class, and gcc.get_variables() - Add 'initial' property to gcc.VarDecl - Add 'elements' property to gcc.Constructor - Start adding a test suite for the plugin API: compile c source whilst running Python code, and checking the output is expected. - Add a test case to exercise the Python API for looking up initialization of arrays of structures.
1 parent d3c77a9 commit 0427e73

14 files changed

+467
-10
lines changed

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ PLUGIN_SOURCE_FILES= \
1010
gcc-python-pass.c \
1111
gcc-python-pretty-printer.c \
1212
gcc-python-tree.c \
13+
gcc-python-variable.c \
1314
autogenerated-tree.c \
14-
autogenerated-gimple.c
15+
autogenerated-gimple.c \
16+
autogenerated-variable.c
1517

1618
PLUGIN_OBJECT_FILES= $(patsubst %.c,%.o,$(PLUGIN_SOURCE_FILES))
1719
GCCPLUGINS_DIR:= $(shell $(GCC) --print-file-name=plugin)
@@ -45,6 +47,9 @@ autogenerated-tree.c: cpybuilder.py generate-tree-c.py autogenerated-tree-types.
4547
autogenerated-gimple.c: cpybuilder.py generate-gimple-c.py autogenerated-gimple-types.txt maketreetypes.py
4648
python generate-gimple-c.py > $@
4749

50+
autogenerated-variable.c: cpybuilder.py generate-variable-c.py autogenerated-gimple-types.txt maketreetypes.py
51+
python generate-variable-c.py > $@
52+
4853
# Hint for debugging: add -v to the gcc options
4954
# to get a command line for invoking individual subprocesses
5055
# Doing so seems to require that paths be absolute, rather than relative
@@ -74,3 +79,7 @@ debug: plugin
7479
# A simple demo, to make it easy to demonstrate the cpychecker:
7580
demo: plugin
7681
PYTHONPATH=$(shell pwd) gcc -fplugin=$(shell pwd)/python.so -fplugin-arg-python-script=cpychecker.py $(shell python-config --cflags) $(shell pwd)/demo.c
82+
83+
test-suite: plugin
84+
python run-test-suite.py
85+

cpybuilder.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,10 @@ def __init__(self, sm, builddir='.'):
333333

334334
class CommandError(RuntimeError):
335335
def __init__(self, out, err, p):
336+
assert isinstance(out, str)
337+
assert isinstance(err, str)
338+
assert isinstance(p, Popen)
339+
336340
self.out = out
337341
self.err = err
338342
self.p = p
@@ -343,12 +347,16 @@ def __str__(self):
343347
result += ' %s\n' % self._describe_activity()
344348
result += 'Stdout:\n'
345349
result += self._indent(self.out)
346-
result += 'Stderr:\n'
350+
result += '\nStderr:\n'
347351
result += self._indent(self.err, 4)
352+
result += self._extra_info()
348353
return result
349354

350355
def _indent(self, txt, size=2):
351356
return '\n'.join([' '*size + line for line in txt.splitlines()])
357+
358+
def _extra_info(self):
359+
return ''
352360

353361
class PyRuntimeError(CommandError):
354362
def __init__(self, runtime, cmd, out, err, p):

gcc-python-pretty-printer.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,12 @@ gcc_python_pretty_printer_as_string(PyObject *obj)
5858
/* Convert to a python string, leaving off the trailing newline: */
5959
len = strlen(ppobj->buf);
6060
assert(len > 0);
61-
assert('\n' == ppobj->buf[len - 1]);
62-
return PyString_FromStringAndSize(ppobj->buf,
63-
len - 1);
61+
if ('\n' == ppobj->buf[len - 1]) {
62+
return PyString_FromStringAndSize(ppobj->buf,
63+
len - 1);
64+
} else {
65+
return PyString_FromString(ppobj->buf);
66+
}
6467
}
6568

6669
void

gcc-python-tree.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,57 @@ gcc_Declaration_repr(struct PyGccTree * self)
118118
return NULL;
119119
}
120120

121+
PyObject *
122+
gcc_Constructor_get_elements(PyObject *self, void *closure)
123+
{
124+
struct PyGccTree * self_as_tree;
125+
PyObject *result = NULL;
126+
tree node;
127+
unsigned HOST_WIDE_INT cnt;
128+
tree index, value;
129+
130+
self_as_tree = (struct PyGccTree *)self; /* FIXME */
131+
node = self_as_tree->t;
132+
133+
result = PyList_New(VEC_length(constructor_elt, CONSTRUCTOR_ELTS (node)));
134+
if (!result) {
135+
goto error;
136+
}
137+
138+
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (node),
139+
cnt, index, value) {
140+
PyObject *obj_index = NULL;
141+
PyObject *obj_value = NULL;
142+
PyObject *obj_pair = NULL;
143+
obj_index = gcc_python_make_wrapper_tree(index);
144+
if (!obj_index) {
145+
goto error;
146+
}
147+
obj_value = gcc_python_make_wrapper_tree(value);
148+
if (!obj_value) {
149+
Py_DECREF(obj_index);
150+
goto error;
151+
}
152+
obj_pair = PyTuple_Pack(2, obj_index, obj_value);
153+
if (!obj_pair) {
154+
Py_DECREF(obj_value);
155+
Py_DECREF(obj_index);
156+
goto error;
157+
}
158+
159+
if (-1 == PyList_SetItem(result, cnt, obj_pair)) {
160+
Py_DECREF(obj_pair);
161+
goto error;
162+
}
163+
}
164+
165+
return result;
166+
167+
error:
168+
Py_XDECREF(result);
169+
return NULL;
170+
}
171+
121172
/*
122173
GCC's debug_tree is implemented in:
123174
gcc/print-tree.c

gcc-python-variable.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <Python.h>
2+
#include "gcc-python.h"
3+
#include "gcc-python-wrappers.h"
4+
5+
PyObject *
6+
gcc_python_make_wrapper_variable(struct varpool_node *node)
7+
{
8+
struct PyGccVariable *var_obj = NULL;
9+
10+
if (NULL == node) {
11+
Py_RETURN_NONE;
12+
}
13+
14+
var_obj = PyObject_New(struct PyGccVariable, &gcc_VariableType);
15+
if (!var_obj) {
16+
goto error;
17+
}
18+
19+
var_obj->var = node;
20+
/* FIXME: do we need to do something for the GCC GC? */
21+
22+
return (PyObject*)var_obj;
23+
24+
error:
25+
return NULL;
26+
}
27+
28+
29+
/*
30+
PEP-7
31+
Local variables:
32+
c-basic-offset: 4
33+
End:
34+
*/

gcc-python-wrappers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ gcc_Declaration_get_name(struct PyGccTree *self, void *closure);
4545
PyObject *
4646
gcc_Declaration_repr(struct PyGccTree * self);
4747

48+
PyObject *
49+
gcc_Constructor_get_elements(PyObject *self, void *closure);
50+
4851
PyObject *
4952
gcc_Gimple_repr(struct PyGccGimple * self);
5053

gcc-python.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ int plugin_is_GPL_compatible;
1111
#include "tree.h"
1212
#include "function.h"
1313
#include "diagnostic.h"
14+
#include "cgraph.h"
1415

1516
#define GCC_PYTHON_TRACE_ALL_EVENTS 0
1617
#if GCC_PYTHON_TRACE_ALL_EVENTS
@@ -261,13 +262,45 @@ gcc_python_permerror(PyObject *self, PyObject *args)
261262
return result_obj;
262263
}
263264

265+
static PyObject *
266+
gcc_python_get_variables(PyObject *self, PyObject *args)
267+
{
268+
PyObject *result;
269+
struct varpool_node *n;
270+
271+
result = PyList_New(0);
272+
if (!result) {
273+
goto error;
274+
}
275+
276+
for (n = varpool_nodes; n; n = n->next) {
277+
PyObject *obj_var = gcc_python_make_wrapper_variable(n);
278+
if (!obj_var) {
279+
goto error;
280+
}
281+
if (-1 == PyList_Append(result, obj_var)) {
282+
Py_DECREF(obj_var);
283+
goto error;
284+
}
285+
}
286+
287+
return result;
288+
289+
error:
290+
Py_XDECREF(result);
291+
return NULL;
292+
}
293+
264294
static PyMethodDef GccMethods[] = {
265295
{"register_callback", gcc_python_register_callback, METH_VARARGS,
266296
"Register a callback, to be called when various GCC events occur."},
267297

268298
{"permerror", gcc_python_permerror, METH_VARARGS,
269299
NULL},
270300

301+
{"get_variables", gcc_python_get_variables, METH_VARARGS,
302+
"Get all variables in this compilation unit as a list of gcc.Variable"},
303+
271304
/* Sentinel: */
272305
{NULL, NULL, 0, NULL}
273306
};
@@ -380,9 +413,12 @@ plugin_init (struct plugin_name_args *plugin_info,
380413

381414
gcc_python_autogenerated_tree_init_types(); /* FIXME: error checking! */
382415
autogenerated_gimple_init_types(); /* FIXME: error checking! */
416+
autogenerated_variable_init_types(); /* FIXME: error checking! */
383417

384418
gcc_python_autogenerated_tree_add_types(gcc_python_globals.module);
385419
autogenerated_gimple_add_types(gcc_python_globals.module);
420+
autogenerated_variable_add_types(gcc_python_globals.module);
421+
386422

387423
// inittree();
388424

gcc-python.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,20 @@ DECLARE_SIMPLE_WRAPPER(PyGccTree,
5959
gcc_TreeType,
6060
tree, tree, t)
6161

62+
DECLARE_SIMPLE_WRAPPER(PyGccVariable,
63+
gcc_VariableType,
64+
variable,
65+
struct varpool_node *, var)
66+
6267
/* autogenerated-gimple.c */
6368
int autogenerated_gimple_init_types(void);
6469
void autogenerated_gimple_add_types(PyObject *m);
6570
PyTypeObject* gcc_python_autogenerated_gimple_type_for_stmt(gimple g);
6671

72+
/* autogenerated-variable.c */
73+
int autogenerated_variable_init_types(void);
74+
void autogenerated_variable_add_types(PyObject *m);
75+
6776

6877
int
6978
gcc_python_autogenerated_tree_init_types(void);

generate-tree-c.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -535,14 +535,23 @@ def generate_tree_code_classes():
535535

536536
getsettable = PyGetSetDefTable('gcc_%s_getset_table' % cc, [])
537537

538+
def get_getter_identifier(name):
539+
return 'gcc_%s_get_%s' % (cc, name)
540+
538541
def add_simple_getter(name, c_expression, doc):
539542
getsettable.add_gsdef(name,
540-
cu.add_simple_getter('gcc_%s_get_%s' % (cc, name),
543+
cu.add_simple_getter(get_getter_identifier(name),
541544
'PyGccTree',
542545
c_expression),
543546
None,
544547
doc)
545548

549+
def add_complex_getter(name, doc):
550+
getsettable.add_gsdef(name,
551+
get_getter_identifier(name),
552+
None,
553+
doc)
554+
546555
if cc == 'AddrExpr':
547556
add_simple_getter('operand',
548557
'gcc_python_make_wrapper_tree(TREE_OPERAND (self->t, 0))',
@@ -591,7 +600,17 @@ def add_simple_getter(name, c_expression, doc):
591600
if tree_type.SYM == 'IDENTIFIER_NODE':
592601
add_simple_getter('name',
593602
'gcc_python_string_or_none(IDENTIFIER_POINTER(self->t))',
594-
"The name of this gcc.IdentifierNode, as a string'")
603+
"The name of this gcc.IdentifierNode, as a string")
604+
605+
if tree_type.SYM == 'VAR_DECL':
606+
add_simple_getter('initial',
607+
'gcc_python_make_wrapper_tree(DECL_INITIAL(self->t))',
608+
"The initial value for this variable as a gcc.Constructor, or None")
609+
610+
if tree_type.SYM == 'CONSTRUCTOR':
611+
add_complex_getter('elements',
612+
"The elements of this constructor, as a list of (index, gcc.Tree) pairs")
613+
595614

596615
cu.add_defn(getsettable.c_defn())
597616

@@ -641,7 +660,9 @@ def add_simple_getter(name, c_expression, doc):
641660
""")
642661

643662

644-
cu.add_defn("""
663+
generate_tree_code_classes()
664+
665+
cu.add_defn("""
645666
int gcc_python_autogenerated_tree_init_types(void)
646667
{
647668
""" + modinit_preinit + """
@@ -652,13 +673,13 @@ def add_simple_getter(name, c_expression, doc):
652673
}
653674
""")
654675

655-
cu.add_defn("""
676+
cu.add_defn("""
656677
void gcc_python_autogenerated_tree_add_types(PyObject *m)
657678
{
658679
""" + modinit_postinit + """
659680
}
660681
""")
661682

662-
generate_tree_code_classes()
683+
663684

664685
print(cu.as_str())

0 commit comments

Comments
 (0)