/* This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "ansidecl.h" #include "coretypes.h" #include "tm.h" #include "opts.h" #include "tree.h" #include "tree-iterator.h" #include "tree-pass.h" #include "gimple.h" #include "toplev.h" #include "debug.h" #include "options.h" #include "flags.h" #include "convert.h" #include "diagnostic-core.h" #include "langhooks.h" #include "langhooks-def.h" #include "target.h" #include "cgraph.h" #include #include #include "vec.h" #include "hashtab.h" #include "gpython.h" #include "py-dot.h" #include "py-vec.h" #include "py-tree.h" #include "py-builtins.h" static VEC(tree,gc) * gpy_stmt_pass_lower_genericify (gpy_hash_tab_t *, VEC(gpydot,gc) *); static tree gpy_stmt_pass_lower_get_module_type (const char *, gpy_hash_tab_t *); static void gpy_stmt_pass_lower_gen_toplevl_context (tree, tree, gpy_hash_tab_t *); static tree gpy_stmt_pass_lower_gen_concat_identifier (const char *, const char *); static tree gpy_stmt_pass_lower_gen_main (tree); static tree gpy_stmt_pass_lower_gen_concat_identifier (const char * s1, const char * s2) { debug ("s1 = <%s> s2 = <%s>!\n", s1, s2); size_t s1len = strlen (s1); size_t s2len = strlen (s2); size_t tlen = s1len + s2len; size_t idx = 0, idy = 0; char buffer[tlen+3]; strncpy (buffer,s1,s1len); buffer[s1len] = '.'; for (idx = s1len+1; idx!\n", buffer); return get_identifier (buffer); } static tree gpy_stmt_pass_lower_get_module_type (const char * s, gpy_hash_tab_t * modules) { tree retval = error_mark_node; gpy_hashval_t h = gpy_dd_hash_string (s); gpy_hash_entry_t * e = gpy_dd_hash_lookup_table (modules, h); if (e) { if (e->data) retval = (tree) e->data; } return retval; } static void gpy_stmt_pass_lower_gen_toplevl_context (tree module, tree param_decl, gpy_hash_tab_t * context) { if (module == error_mark_node) return; else { tree field = TYPE_FIELDS (module); do { gcc_assert (TREE_CODE (field) == FIELD_DECL); debug ("generating refernence to <%s>!\n", IDENTIFIER_POINTER(DECL_NAME (field))); gpy_hashval_t h = gpy_dd_hash_string (IDENTIFIER_POINTER(DECL_NAME (field))); tree ref = build3 (COMPONENT_REF, TREE_TYPE (field), build_fold_indirect_ref(param_decl), field, NULL_TREE); void ** e = gpy_dd_hash_insert (h, ref, context); debug_tree (ref); if (e) fatal_error ("problem inserting component reference into context!\n"); } while ((field = DECL_CHAIN (field))); } } /* Creates a DECL_CHAIN of stmts to fold the scalar with the last tree being the address of the primitive */ tree gpy_stmt_decl_lower_scalar (gpy_dot_tree_t * decl, tree * cblock) { tree retval = error_mark_node; gcc_assert (DOT_TYPE (decl) == D_PRIMITIVE); gcc_assert (DOT_lhs_T (decl) == D_TD_COM); switch (DOT_lhs_TC (decl)->T) { case D_T_INTEGER: { retval = build_decl (UNKNOWN_LOCATION, VAR_DECL, create_tmp_var_name ("P"), gpy_object_type_ptr); append_to_statement_list (build2 (MODIFY_EXPR, gpy_object_type_ptr, retval, gpy_builtin_get_fold_int_call (DOT_lhs_TC (decl)->o.integer)), cblock); } break; default: error ("invalid scalar type!\n"); break; } return retval; } tree gpy_stmt_decl_lower_modify (gpy_dot_tree_t * decl, tree * cblock, VEC(gpy_ctx_t,gc) * context) { tree retval = error_mark_node; gpy_dot_tree_t * lhs = DOT_lhs_TT (decl); gpy_dot_tree_t * rhs = DOT_rhs_TT (decl); /* We dont handle full target lists yet all targets are in the lhs tree. To implment a target list such as: x,y,z = 1 The lhs should be a DOT_CHAIN of identifiers! So we just iterate over them and deal with it as such! */ gcc_assert (DOT_TYPE (lhs) == D_IDENTIFIER); tree addr = gpy_ctx_lookup_decl (context, DOT_IDENTIFIER_POINTER (lhs)); if (!addr) { /* since not previously declared we need to declare the variable! */ gpy_hash_tab_t * current_context = VEC_index (gpy_ctx_t, context, (VEC_length (gpy_ctx_t, context) - 1) ); addr = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (DOT_IDENTIFIER_POINTER (lhs)), gpy_object_type_ptr); if (!gpy_ctx_push_decl (addr, DOT_IDENTIFIER_POINTER (lhs), current_context)) fatal_error ("error pushing decl <%q+E>!\n", addr); } gcc_assert (addr != error_mark_node); tree addr_rhs_tree = gpy_stmt_decl_lower_expr (rhs, cblock, context); append_to_statement_list (build2 (MODIFY_EXPR, gpy_object_type_ptr, addr, addr_rhs_tree), cblock); append_to_statement_list (gpy_builtin_get_incr_ref_call (addr), cblock); retval = addr; return retval; } tree gpy_stmt_decl_lower_binary_op (gpy_dot_tree_t * decl, tree * cblock, VEC(gpy_ctx_t,gc) * context) { tree retval = error_mark_node; gcc_assert (DOT_T_FIELD (decl) == D_D_EXPR); gpy_dot_tree_t * lhs = DOT_lhs_TT (decl); gpy_dot_tree_t * rhs = DOT_rhs_TT (decl); tree lhs_eval = gpy_stmt_decl_lower_expr (lhs, cblock, context); tree rhs_eval = gpy_stmt_decl_lower_expr (rhs, cblock, context); tree op = error_mark_node; switch (DOT_TYPE (decl)) { case D_ADD_EXPR: op = gpy_builtin_get_eval_expression_call (lhs_eval, rhs_eval, DOT_TYPE (decl)); break; // .... default: error ("unhandled binary operation type!\n"); break; } gcc_assert (op != error_mark_node); tree retaddr = build_decl (UNKNOWN_LOCATION, VAR_DECL, create_tmp_var_name("T"), gpy_object_type_ptr); append_to_statement_list (build2 (MODIFY_EXPR, gpy_object_type_ptr, retaddr, op), cblock); retval = retaddr; return retval; } tree gpy_stmt_decl_lower_expr (gpy_dot_tree_t * decl, tree * cblock, VEC(gpy_ctx_t,gc) * context) { tree retval = error_mark_node; switch (DOT_TYPE (decl)) { case D_PRIMITIVE: retval = gpy_stmt_decl_lower_scalar (decl, cblock); break; case D_IDENTIFIER: retval = gpy_ctx_lookup_decl (context, DOT_IDENTIFIER_POINTER (decl)); break; default: { switch (DOT_TYPE (decl)) { case D_MODIFY_EXPR: retval = gpy_stmt_decl_lower_modify (decl, cblock, context); break; case D_ADD_EXPR: retval = gpy_stmt_decl_lower_binary_op (decl, cblock, context); break; // ... the rest of the binary operators! default: error ("unhandled operation type!\n"); break; } } break; } return retval; } tree gpy_stmt_pass_lower_functor (gpy_dot_tree_t * decl, gpy_hash_tab_t * modules) { tree block = alloc_stmt_list (); gpy_hash_tab_t toplvl, topnxt; gpy_dd_hash_init_table (&toplvl); gpy_dd_hash_init_table (&topnxt); tree main_init_module = gpy_stmt_pass_lower_get_module_type ("main.main", modules); tree pdecl_t = build_pointer_type (main_init_module); tree fntype = build_function_type_list (void_type_node, pdecl_t, /* handle function parameters ... */ NULL_TREE); tree concat_ident = gpy_stmt_pass_lower_gen_concat_identifier ("main.main", DOT_IDENTIFIER_POINTER (DOT_FIELD (decl))); tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, concat_ident, fntype); DECL_EXTERNAL (fndecl) = 0; TREE_PUBLIC (fndecl) = 1; TREE_STATIC (fndecl) = 1; tree arglist = NULL_TREE; tree result_decl = build_decl (BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); DECL_RESULT (fndecl) = result_decl; SET_DECL_ASSEMBLER_NAME (fndecl, concat_ident); tree self_parm_decl = build_decl (BUILTINS_LOCATION, PARM_DECL, get_identifier ("__self__"), pdecl_t); DECL_CONTEXT (self_parm_decl) = fndecl; DECL_ARG_TYPE (self_parm_decl) = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); TREE_READONLY (self_parm_decl) = 1; arglist = chainon (arglist, self_parm_decl); TREE_USED (self_parm_decl) = 1; DECL_ARGUMENTS (fndecl) = arglist; gpy_stmt_pass_lower_gen_toplevl_context (main_init_module, self_parm_decl, &toplvl); VEC(gpy_ctx_t,gc) * toplevl_context = VEC_alloc (gpy_ctx_t, gc, 0); VEC_safe_push (gpy_ctx_t, gc, toplevl_context, &toplvl); VEC_safe_push (gpy_ctx_t, gc, toplevl_context, &topnxt); DECL_INITIAL(fndecl) = block; gpy_dot_tree_t * idtx = DOT_rhs_TT (decl); /* Iterating over the DOT IL to lower/generate the GENERIC code required to compile the stmts and decls */ do { if (DOT_T_FIELD (idtx) == D_D_EXPR) { // append to stmt list as this goes into the module initilizer... gpy_stmt_decl_lower_expr (idtx, &block, toplevl_context); continue; } switch (DOT_TYPE (idtx)) { default: fatal_error ("unhandled dot tree code <%i>!\n", DOT_TYPE (idtx)); break; } } while ((idtx = DOT_CHAIN (idtx))); tree bl = make_node(BLOCK); BLOCK_SUPERCONTEXT(bl) = fndecl; DECL_INITIAL(fndecl) = bl; BLOCK_VARS(bl) = NULL_TREE; TREE_USED(bl) = 1; tree bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(bl), NULL_TREE, bl); TREE_SIDE_EFFECTS(bind) = 1; BIND_EXPR_BODY(bind) = block; block = bind; DECL_SAVED_TREE(fndecl) = block; gimplify_function_tree (fndecl); cgraph_add_new_function (fndecl, false); cgraph_finalize_function (fndecl, true); return fndecl; } static VEC(tree,gc) * gpy_stmt_pass_lower_genericify (gpy_hash_tab_t * modules, VEC(gpydot,gc) * decls) { VEC(tree,gc) * retval = VEC_alloc (tree,gc,0); tree block = alloc_stmt_list (); // tree declvars = NULL_TREE; gpy_hash_tab_t toplvl, topnxt; gpy_dd_hash_init_table (&toplvl); gpy_dd_hash_init_table (&topnxt); tree main_init_module = gpy_stmt_pass_lower_get_module_type ("main.main", modules); tree pdecl_t = build_pointer_type (main_init_module); tree main_init_fntype = build_function_type_list (void_type_node, pdecl_t, NULL_TREE); tree main_init_fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier ("main.main.init"), main_init_fntype); DECL_EXTERNAL (main_init_fndecl) = 0; TREE_PUBLIC (main_init_fndecl) = 1; TREE_STATIC (main_init_fndecl) = 1; tree result_decl = build_decl (BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); DECL_RESULT (main_init_fndecl) = result_decl; tree arglist = NULL_TREE; SET_DECL_ASSEMBLER_NAME (main_init_fndecl, get_identifier("main.main.init")); tree self_parm_decl = build_decl (BUILTINS_LOCATION, PARM_DECL, get_identifier ("__self__"), pdecl_t); DECL_CONTEXT (self_parm_decl) = main_init_fndecl; DECL_ARG_TYPE (self_parm_decl) = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (main_init_fndecl))); TREE_READONLY (self_parm_decl) = 1; arglist = chainon (arglist, self_parm_decl); TREE_USED (self_parm_decl) = 1; DECL_ARGUMENTS (main_init_fndecl) = arglist; gpy_stmt_pass_lower_gen_toplevl_context (main_init_module, self_parm_decl, &toplvl); VEC(gpy_ctx_t,gc) * toplevl_context = VEC_alloc (gpy_ctx_t, gc, 0); VEC_safe_push (gpy_ctx_t, gc, toplevl_context, &toplvl); VEC_safe_push (gpy_ctx_t, gc, toplevl_context, &topnxt); DECL_INITIAL(main_init_fndecl) = block; int idx = 0; gpy_dot_tree_t * idtx = NULL_DOT; /* Iterating over the DOT IL to lower/generate the GENERIC code required to compile the stmts and decls */ for (idx = 0; VEC_iterate (gpydot, decls, idx, idtx); ++idx) { if (DOT_T_FIELD (idtx) == D_D_EXPR) { // append to stmt list as this goes into the module initilizer... gpy_stmt_decl_lower_expr (idtx, &block, toplevl_context); continue; } switch (DOT_TYPE (idtx)) { case D_STRUCT_METHOD: { /* They are self contained decls so we just pass them to the return vector for gimplification */ debug ("lowering function toplevel!\n"); VEC_safe_push (tree, gc, retval, gpy_stmt_pass_lower_functor (idtx, modules) ); debug ("lowered function toplevel!\n"); } break; default: fatal_error ("unhandled dot tree code <%i>!\n", DOT_TYPE (idtx)); break; } } tree bl = make_node(BLOCK); BLOCK_SUPERCONTEXT(bl) = main_init_fndecl; DECL_INITIAL(main_init_fndecl) = bl; BLOCK_VARS(bl) = NULL_TREE; TREE_USED(bl) = 1; tree bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(bl), NULL_TREE, bl); TREE_SIDE_EFFECTS(bind) = 1; BIND_EXPR_BODY(bind) = block; block = bind; DECL_SAVED_TREE(main_init_fndecl) = block; gimplify_function_tree (main_init_fndecl); cgraph_add_new_function (main_init_fndecl, false); cgraph_finalize_function (main_init_fndecl, true); VEC_safe_push (tree,gc,retval, main_init_fndecl); return retval; } static tree gpy_stmt_pass_lower_gen_main (tree module) { tree main_fn_type = build_function_type_list (integer_type_node, NULL_TREE); tree main_fn_decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier("main"), main_fn_type); DECL_CONTEXT (main_fn_decl) = NULL_TREE; TREE_STATIC (main_fn_decl) = 1; TREE_PUBLIC (main_fn_decl) = 1; DECL_ARGUMENTS (main_fn_decl) = NULL_TREE; /* Define the return type (represented by RESULT_DECL) for the main functin */ tree main_ret = build_decl (BUILTINS_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(main_fn_type)); DECL_CONTEXT(main_ret) = main_fn_decl; DECL_ARTIFICIAL(main_ret) = 1; DECL_IGNORED_P(main_ret) = 1; DECL_RESULT(main_fn_decl) = main_ret; tree main_art_block = build_block(NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); DECL_INITIAL(main_fn_decl) = main_art_block; tree declare_vars = NULL_TREE; tree main_stmts = alloc_stmt_list (); append_to_statement_list (gpy_builtin_get_init_call(), &main_stmts); tree mod_decl = build_decl (BUILTINS_LOCATION, VAR_DECL, create_tmp_var_name ("I"), module); declare_vars = mod_decl; tree module_init_fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier ("main.main.init"), build_function_type_list (void_type_node, build_pointer_type (module), NULL_TREE) ); append_to_statement_list (build_call_expr (module_init_fndecl, 1, build_fold_addr_expr(mod_decl)), &main_stmts); append_to_statement_list ( gpy_builtin_get_cleanup_final_call (), &main_stmts); tree main_set_ret = build2 (MODIFY_EXPR, TREE_TYPE(main_ret), main_ret, build_int_cst(integer_type_node, 0)); tree main_ret_expr = build1 (RETURN_EXPR, void_type_node, main_set_ret); append_to_statement_list (main_ret_expr, &main_stmts); tree bind = NULL_TREE; tree bl = make_node(BLOCK); BLOCK_SUPERCONTEXT(bl) = main_fn_decl; DECL_INITIAL(main_fn_decl) = bl; BLOCK_VARS(bl) = declare_vars; TREE_USED(bl) = 1; bind = build3( BIND_EXPR, void_type_node, BLOCK_VARS(bl), NULL_TREE, bl ); TREE_SIDE_EFFECTS(bind) = 1; BIND_EXPR_BODY(bind) = main_stmts; main_stmts = bind; DECL_SAVED_TREE(main_fn_decl) = main_stmts; gimplify_function_tree (main_fn_decl); cgraph_finalize_function (main_fn_decl, false); return main_fn_decl; } /* Now we start to iterate over the dot IL to lower it down to */ /* a vector of GENERIC decls */ /* Which is then passed over to the pass manager for any other */ /* defined passes which can be placed into the queue but arent */ /* nessecary for now. */ VEC(tree,gc) * gpy_stmt_pass_lower (VEC(tree,gc) *modules, VEC(gpydot,gc) *decls) { VEC(tree,gc) * retval; gpy_hash_tab_t module_ctx; gpy_dd_hash_init_table (&module_ctx); int idx = 0; tree itx = NULL_TREE; for (; VEC_iterate (tree, modules, idx, itx); ++idx) { debug ("hashing module name <%s>!\n", IDENTIFIER_POINTER (TYPE_NAME(itx))); gpy_hashval_t h = gpy_dd_hash_string (IDENTIFIER_POINTER (TYPE_NAME(itx))); void ** e = gpy_dd_hash_insert (h, itx, &module_ctx); if (e) fatal_error ("module <%q+E> is already defined!\n", itx); } retval = gpy_stmt_pass_lower_genericify (&module_ctx, decls); VEC_safe_push (tree, gc, retval, gpy_stmt_pass_lower_gen_main (gpy_stmt_pass_lower_get_module_type ("main.main", &module_ctx) ) ); // free (context.array); return retval; }