Python Front-end Wiki
This is a front-end to GCC to compile python as an AOT (ahead-of-time) compiled language on GCC.
Getting the Code
The repository can be browsed on http://gcc.gnu.org/git/?p=gcc.git in the gccpy branch
Typical Compile/Usage
$ mkdir gcc-python-build
$ cd gcc-python-build/
$ ../gccpy/configure --enable-languages=c,python --disable-bootstrap ...
$ make
$ make install
$ emacs/vim t.py
$ gccpy -O0 -v -fdump-tree-gimple t.py
$ ./a.out
Motivation
Dynamic languages like Python, Perl or JavaScript are becoming more and more present in everyday technologies. Though they have remained Interpreted implemented usually as a C interpreter which adds a layer of abstraction generally slowing the system down, instead of an AOT system with target code generated and assembled which may make things smaller and faster. This project may serve something akin to that of PHC a PHP compiler. There are many problems present in building such a dynamic language AOT, being that Static Analysis, implicit type conversion or dynamic includes and imports will be difficult to implement. I hope this project could at least serve as a proof of concept in that GCC is still a very important platform for building new languages, as you not only get a strong, portable back-end code-generator but the GCC middle-end will perform all of it's built-in optimization passes defined in the 'gcc/tree-ssa-*.c'.
Code Overview
The code is split into 2 parts: there is the runtime library in libgpython and the front-end code in gcc/python. Let's start with the Front-end Code.
Within GCC we had to create our own IL before lowering down to GENERIC before passing to GCC's middle-end. This is because python is dynamically typed and GENERIC requires us to know what types were talking about at each declaration but in python we dont. So to get around this very big problem we had to wrap every type within python code into a gpy_object_t similar to how cpython works. But first when we read in this code into out IL our IL simply represents the code as is in the beginning nothing fancy is done to the code.
So now we enter the gccpy's pass phase in the py-stmt-pass-mangr.c, We first enter the:
*check1 - we do simple sanity checks here where we can do some name lookup checks and just general sanity checks over the code.
*const_fold - we cant rely on gcc's const fold pass to do constant folding this pass isnt implemented yet and probably wont for some time, but the reason we cant rely on gcc's constant folding is we deal with primitive types very differently since they have to be initialized at runtime.
*translate - inside class's in python you dont have to fully qualify your names using self.attribute but we use this pass to make sure this is always the case so there is no ambiguity incase were accessing some global.
*pretty_print - not implemented ye but if you pass -fpy-dump-dot we can dump out what our IL looks like before generating types and lowering.
*generate_types - when we look at a class we need to generate its type this is dont here and i would outline how it works when we come to that.
*genericify - we lower our code to GENERIC here and is the most important pass.
Lets take a look at some simple examples of what we generate:
1 t.py.__main_start__ ()
2 {
3 struct gpy_object_t * * __GPY_RR_STACK_PTR.44;
4 struct gpy_object_t * * __GPY_RR_STACK_PTR.45;
5 struct gpy_object_t * * __GPY_RR_STACK_PTR.46;
6 void <retval>;
7
8 __GPY_RR_STACK_PTR.44 = __GPY_RR_STACK_PTR;
9 gpy_rr_initRRStack (3, __GPY_RR_STACK_PTR.44, "t.py");
10 x = __GPY_RR_STACK_PTR;
11 __GPY_RR_STACK_PTR.45 = __GPY_RR_STACK_PTR;
12 date = __GPY_RR_STACK_PTR.45 + -8;
13 __GPY_RR_STACK_PTR.46 = __GPY_RR_STACK_PTR;
14 t.py.__main_start__ = __GPY_RR_STACK_PTR.46 + -16;
15 FNAD.12 = t.py.date.__init__;
16 AT.13 = gpy_rr_fold_attribute ("__init__", FNAD.12, 0, 4);
17 FNAD.14 = t.py.date.print_date;
18 AT.15 = gpy_rr_fold_attribute ("print_date", FNAD.14, 8, 1);
19 FNAD.16 = 0B;
20 AT.17 = gpy_rr_fold_attribute ("year", FNAD.16, 16, 0);
21 FNAD.18 = 0B;
22 AT.19 = gpy_rr_fold_attribute ("day", FNAD.18, 24, 0);
23 FNAD.20 = 0B;
24 AT.21 = gpy_rr_fold_attribute ("month", FNAD.20, 32, 0);
25 FNAD.22 = t.py.date.__field_init__;
26 AT.23 = gpy_rr_fold_attribute ("__field_init__", FNAD.22, 40, 1);
27 AL.24 = gpy_rr_fold_attrib_list (6, AT.13, AT.15, AT.17, AT.19, AT.21, AT.23);
28 ATFC.25 = gpy_rr_fold_class_decl (AL.24, 48, "t.py.date");
29 *date = ATFC.25;
30 ATAR.26 = *date;
31 PI.27 = gpy_rr_fold_integer (1);
32 PI.28 = gpy_rr_fold_integer (2);
33 PI.29 = gpy_rr_fold_integer (3);
34 RET.30 = gpy_rr_fold_call (ATAR.26, 3, PI.27, PI.28, PI.29);
35 *x = RET.30;
36 ATRDF.32 = *x;
37 ATRD.31 = gpy_rr_eval_attrib_reference (ATRDF.32, "print_date");
38 ATAR.33 = *ATRD.31;
39 ATRDF.34 = *x;
40 RET.35 = gpy_rr_fold_call (ATAR.33, 1, ATRDF.34);
41 PI.36 = gpy_rr_fold_integer (10);
42 ATRDF.38 = *x;
43 ATRD.37 = gpy_rr_eval_attrib_reference (ATRDF.38, "day");
44 *ATRD.37 = PI.36;
45 ATRDF.40 = *x;
46 ATRD.39 = gpy_rr_eval_attrib_reference (ATRDF.40, "print_date");
47 ATAR.41 = *ATRD.39;
48 ATRDF.42 = *x;
49 RET.43 = gpy_rr_fold_call (ATAR.41, 1, ATRDF.42);
50 }
51
52
53 t.py.date.__field_init__ (struct t.py.date * __object_state__)
54 {
55 void <retval>;
56
57 PI.0 = gpy_rr_fold_integer (0);
58 __object_state__->day = PI.0;
59 PI.1 = gpy_rr_fold_integer (0);
60 __object_state__->month = PI.1;
61 PI.2 = gpy_rr_fold_integer (0);
62 __object_state__->year = PI.2;
63 }
64
65
66 t.py.date.print_date (struct gpy_object_t * self)
67 {
68 void <retval>;
69
70 ATRD.6 = gpy_rr_eval_attrib_reference (self, "day");
71 ATAR.7 = *ATRD.6;
72 ATRD.8 = gpy_rr_eval_attrib_reference (self, "month");
73 ATAR.9 = *ATRD.8;
74 ATRD.10 = gpy_rr_eval_attrib_reference (self, "year");
75 ATAR.11 = *ATRD.10;
76 gpy_rr_eval_print (1, 3, ATAR.7, ATAR.9, ATAR.11);
77 }
78
79
80 t.py.date.__init__ (struct gpy_object_t * self, struct gpy_object_t * x, struct gpy_object_t * y, struct gpy_object_t * z)
81 {
82 void <retval>;
83
84 ATRD.3 = gpy_rr_eval_attrib_reference (self, "day");
85 *ATRD.3 = x;
86 ATRD.4 = gpy_rr_eval_attrib_reference (self, "month");
87 *ATRD.4 = y;
88 ATRD.5 = gpy_rr_eval_attrib_reference (self, "year");
89 *ATRD.5 = z;
90 }
Runtime Library (libgpython.so)
There is quite a heavy reliance on the runtime library for builtins; some of them we can get rid of with better front-end code when things become more standardized but that takes more time.
Contact
Philip Herron <redbrain@gcc.gnu.org> Andi Hellmund <mail@andihellmund.com>
Ian Lance Taylor has given a lot of support mentoing this project.