On 25/05/2014 13:12, Roman Gareev wrote:
Hi Tobias, I tried to incorporate all your comments in the following patch. It also contains traversing of ISL AST and its dump to a file. You can find out more about this at the following link http://romangareev.blogspot.ru/2014/05/gsoc-report-i.html
Hi Roman, thanks for this update (and expecially the nice blog post). Also the size of the patch is great. Small enough to be easy to review and still adding good features.
diff --git a/gcc/common.opt b/gcc/common.opt index 5c3f834..005042d 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1250,6 +1250,10 @@ fgraphite-identity Common Report Var(flag_graphite_identity) Optimization Enable Graphite Identity transformation +fgraphite-isl-code-gen +Common Report Var(flag_graphite_isl_code_gen) Optimization +Enable isl code generator in Graphite
Can we use something like: -fgraphite-code-generator=[isl|cloog] This allows us to start with cloog as default and then flip the switch as soon as we are confident enough.
diff --git a/gcc/graphite-clast-to-gimple.c b/gcc/graphite-clast-to-gimple.c index 9ac9b67..d16439d 100644 --- a/gcc/graphite-clast-to-gimple.c +++ b/gcc/graphite-clast-to-gimple.c @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include <isl/constraint.h> #include <isl/ilp.h> #include <isl/aff.h> +#include <isl/ast_build.h>
Can we put this into a new file? clast stands for CLOOG-AST. I would prefer to have a new file ala graphite-isl-ast-to-gimple.c or graphite-ast-generation.c
#include <cloog/cloog.h> #include <cloog/isl/domain.h> #endif @@ -1657,6 +1658,221 @@ debug_generated_program (scop_p scop) print_generated_program (stderr, scop); } + +/* Integration of ISL code generator. */ + +/* TODO: eliminate this function as soon as possible */ + +void +print_indent (int indent, isl_printer *prn) +{ + int i; + for (i = 0; i < indent; i++) + { + prn = isl_printer_print_str (prn, " "); + } +}
Why is this function necessary in the first place? Are you aware of isl_printer_set_indent() and isl_printer_set_indent_prefix()?
+static void +translate_isl_ast (int indent, __isl_keep isl_ast_node *node, + isl_printer *prn); + +/* Translates a isl_ast_node_for STMT to gimple. + TODO: replace output to FILE with translation + to GCC representation. */ + +static void +translate_isl_ast_node_for (int indent, __isl_keep isl_ast_node *node_for, + isl_printer *prn) +{ + isl_id *id; + const char *name; + const char *type; + type = isl_options_get_ast_iterator_type (isl_printer_get_ctx (prn)); + isl_ast_expr *for_iterator = isl_ast_node_for_get_iterator (node_for); + isl_ast_expr_free (for_iterator); + id = isl_ast_expr_get_id (for_iterator); + name = isl_id_get_name (id); + isl_id_free (id); + prn = isl_printer_print_str (prn, "\n"); + print_indent (indent, prn); + prn = isl_printer_print_str (prn, "for ("); + prn = isl_printer_print_str (prn, type); + prn = isl_printer_print_str (prn, " "); + prn = isl_printer_print_str (prn, name); + prn = isl_printer_print_str (prn, " = "); + isl_ast_expr *for_init = isl_ast_node_for_get_init (node_for); + prn = isl_printer_print_ast_expr (prn, for_init); + isl_ast_expr_free (for_init); + prn = isl_printer_print_str (prn, "; "); + isl_ast_expr *for_cond = isl_ast_node_for_get_cond (node_for); + prn = isl_printer_print_ast_expr (prn, for_cond); + isl_ast_expr_free (for_cond); + prn = isl_printer_print_str (prn, "; "); + prn = isl_printer_print_str (prn, name); + prn = isl_printer_print_str (prn, " += "); + isl_ast_expr *for_inc = isl_ast_node_for_get_inc (node_for); + prn = isl_printer_print_ast_expr (prn, for_inc); + isl_ast_expr_free (for_inc); + prn = isl_printer_print_str (prn, ")"); + isl_ast_node *for_body = isl_ast_node_for_get_body (node_for); + translate_isl_ast (indent + 2, for_body, prn); + isl_ast_node_free (for_body); +} + +/* Translates a clast guard statement STMT to gimple. + TODO: replace output to FILE with translation + to GCC representation. */ + +static void +translate_isl_ast_node_if (int indent, __isl_keep isl_ast_node *node_if, + isl_printer *prn) +{ + prn = isl_printer_print_str (prn, "\n"); + print_indent (indent, prn); + prn = isl_printer_print_str (prn, "if ("); + isl_ast_expr *if_cond = isl_ast_node_if_get_cond (node_if); + prn = isl_printer_print_ast_expr (prn, if_cond); + isl_ast_expr_free (if_cond); + prn = isl_printer_print_str (prn, ")"); + isl_ast_node *if_then = isl_ast_node_if_get_then (node_if); + translate_isl_ast (indent + 2, if_then, prn); + isl_ast_node_free (if_then); + if (isl_ast_node_if_has_else (node_if)) + { + prn = isl_printer_print_str (prn, "else"); + isl_ast_node *if_else = isl_ast_node_if_get_else(node_if); + translate_isl_ast (indent + 2, if_else, prn); + isl_ast_node_free (if_else); + } +} + +/* Translates a clast guard statement STMT to gimple. + TODO: replace output to FILE with translation + to GCC representation. */ + +static void +translate_isl_ast_node_user (int indent, __isl_keep isl_ast_node *node_user, + isl_printer *prn) +{ + prn = isl_printer_print_str (prn, "\n"); + prn = isl_printer_set_indent (prn, indent); + prn = isl_printer_print_ast_node (prn, node_user); +} + +/* Translates a clast guard statement STMT to gimple. + TODO: replace output to FILE with translation + to GCC representation. */ + +static void +translate_isl_ast_node_block (int indent, __isl_keep isl_ast_node *node_block, + isl_printer *prn) +{ + isl_ast_node_list *node_list = isl_ast_node_block_get_children (node_block); + int i; + for (i = 0; i < isl_ast_node_list_n_ast_node (node_list); i++) + { + translate_isl_ast (indent + 2, + isl_ast_node_list_get_ast_node (node_list, i), prn); + } + isl_ast_node_list_free (node_list); +} + +/* Translates a ISL AST node NODE to GCC representation in the + context of a SESE. + TODO: replace output to FILE with translation + to GCC representation. */ + +static void +translate_isl_ast (int indent, __isl_keep isl_ast_node *node, isl_printer *prn) +{ + switch (isl_ast_node_get_type (node)) + { + case isl_ast_node_error: + gcc_unreachable (); + + case isl_ast_node_for: + translate_isl_ast_node_for (indent, node, prn); + return; + + case isl_ast_node_if: + translate_isl_ast_node_if (indent, node, prn); + return; + + case isl_ast_node_user: + translate_isl_ast_node_user (indent, node, prn); + return; + + case isl_ast_node_block: + translate_isl_ast_node_block (indent, node, prn); + return; + + default: + gcc_unreachable (); + } +} + +/* Prints NODE to FILE. */ + +void +print_isl_ast_node (FILE *file, __isl_keep isl_ast_node *node, + __isl_keep isl_ctx *ctx) +{ + isl_printer *prn = isl_printer_to_file (ctx, file); + prn = isl_printer_set_output_format (prn, ISL_FORMAT_C); + prn = isl_printer_print_ast_node (prn, node); + isl_printer_free (prn); +}
+ +/* Generates a build, which specifies the constraints on the parameters. */ + +static isl_ast_build * +generate_isl_context (scop_p scop) +{ + isl_set * context_isl = isl_set_params (isl_set_copy (scop->context)); + return isl_ast_build_from_context (context_isl); +} + +/* Generates a schedule, which specifies an order used to + visit elements in a domain. */ + +static isl_union_map * +generate_isl_schedule (scop_p scop) +{ + int i; + poly_bb_p pbb; + isl_union_map *schedule_isl = + isl_union_map_empty (isl_set_get_space (scop->context)); + + FOR_EACH_VEC_ELT (SCOP_BBS (scop), i, pbb) + { + /* Dead code elimination: when the domain of a PBB is empty, + don't generate code for the PBB. */ + if (isl_set_is_empty (pbb->domain)) + continue; + + isl_map *bb_schedule = isl_map_copy (pbb->transformed); + bb_schedule = isl_map_intersect_domain (bb_schedule, + isl_set_copy (pbb->domain)); + schedule_isl = + isl_union_map_union (schedule_isl, + isl_union_map_from_map (bb_schedule)); + } + return schedule_isl; +} + +static isl_ast_node * +scop_to_isl_ast (scop_p scop) +{ + isl_union_map *schedule_isl = generate_isl_schedule (scop); + isl_ast_build *context_isl = generate_isl_context (scop); + isl_ast_node *ast_isl = isl_ast_build_ast_from_schedule (context_isl, + schedule_isl); + isl_ast_build_free (context_isl); + return ast_isl; +} +
Allright. It seems you understood the tree traversel. For the actual patch that we want to commit, let's leave it out for now. Instead, let's try to get a minimal patch that only adds the flag and the new file for the isl_ast stuff. In case the isl is choosen as code generation option, the cloog pass is disabled (they would otherwise get into their way later) and we dump the ast. We also need a simple test case that checks that the dump is generated.
/* GIMPLE Loop Generator: generates loops from STMT in GIMPLE form for the given SCOP. Return true if code generation succeeded. BB_PBB_MAPPING is a basic_block and it's related poly_bb_p mapping. @@ -1680,6 +1896,24 @@ gloog (scop_p scop, bb_pbb_htab_type bb_pbb_mapping) clast = scop_to_clast (scop, params_index); + if (flag_graphite_isl_code_gen) + { + isl_ast_node *root_node = scop_to_isl_ast (scop); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nISL AST generated by ISL: \n"); + print_isl_ast_node (dump_file, root_node, scop->ctx); + fprintf (dump_file, "\nISL AST dumped by traversing: "); + isl_printer *prn = isl_printer_to_file (scop->ctx, dump_file); + prn = isl_printer_set_output_format (prn, ISL_FORMAT_C); + translate_isl_ast (0, root_node, prn); + isl_printer_free (prn); + fflush (dump_file); + fprintf (dump_file, "\n"); + } + isl_ast_node_free (root_node); + } + if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "\nCLAST generated by CLooG: \n");
Instead of adding this functionality to gloog() I would create a semilar function that provides the functionality gloog has for the isl codegen counterpart. -fgraphite-code-generator switches then between these two functions. To start with the isl counterpart is almost empty. It just contains the parts of this patch needed for printing. When we add more functionality and we encounter reuse opportunities, we can move parts of graphite-clast-to-gimple.c into a generic codegen file. What do you think? Cheers, Tobias