text: #include <assert.h>
  #include <stdio.h>
  #include <stdlib.h>
  
  #include <isl/options.h>
  #include <isl/union_set.h>
  #include <isl/schedule.h>
  #include <pet.h>
  
  #include "polyxb.h"
  #include "print.h"
  #include "schedule.h"
  #include "scop.h"
  #include "tactics.h"
  #include "utils.h"
  
  
  ISL_ARGS_START(struct polyxb_options, polyxb_options_args)
  ISL_ARG_CHILD(struct polyxb_options, isl, "isl", &isl_options_args,
      "isl options")
  ISL_ARG_STR(struct polyxb_options, ctx, 0, "ctx", "context", NULL,
      "constraints on parameters")
  ISL_ARG_BOOL(struct polyxb_options, en_tiling, 't', "tiling", 0,
      "enable tiling, tiling size should be specified with -M -N -K")
  ISL_ARG_INT(struct polyxb_options, mm_size[0], 'M', NULL, NULL, 128,
      "dimension 0 of matrix-multiplication")
  ISL_ARG_INT(struct polyxb_options, mm_size[1], 'N', NULL, NULL, 128,
      "dimension 1 of matrix-multiplication")
  ISL_ARG_INT(struct polyxb_options, mm_size[2], 'K', NULL, NULL, 128,
      "dimension 1 of matrix-multiplication")
  ISL_ARG_BOOL(struct polyxb_options, en_pipeline, 'p', "pipeline", 0,
      "enable supporting for pipeline")
  ISL_ARG_INT(struct polyxb_options, num_pes, 'n', NULL, NULL, 168,
      "number of PEs")
  ISL_ARG_BOOL(struct polyxb_options, en_conv, 'c', "conv", 0,
      "enable conv as a primitive")
  ISL_ARGS_END
  
  
  ISL_ARGS_START(struct options, options_args)
  ISL_ARG_CHILD(struct options, pet, "pet", &pet_options_args, "pet options")
  ISL_ARG_CHILD(struct options, polyxb, NULL, &polyxb_options_args,
      "polyxb options")
  ISL_ARG_STR(struct options, output, 'o', NULL, "filename", NULL,
      "output filename")
  ISL_ARG_ARG(struct options, input, "input", NULL)
  ISL_ARGS_END
  
  ISL_ARG_DEF(polyxb_options, struct polyxb_options, polyxb_options_args)
  ISL_ARG_DEF(options, struct options, options_args)
  
  /* Should we print the original code?
   * That is, does "scop" involve any data dependent conditions or
   * nested expressions that cannot be handled by pet_stmt_build_ast_exprs?
   */
  static int print_original(struct pet_scop *scop, struct polyxb_options *options)
  {
  	if (!pet_scop_can_build_ast_exprs(scop)) {
          fprintf(stderr, "Printing original code because "
              "some index expressions cannot currently "
              "be printed\n");
  		return 1;
  	}
  
  	if (pet_scop_has_data_dependent_conditions(scop)) {
          fprintf(stderr, "Printing original code because "
              "input involves data dependent conditions\n");
  		return 1;
  	}
  
  	return 0;
  }
  
  /*
   */
  static __isl_give isl_schedule *get_schedule(struct polyxb_scop *ps,
  	struct polyxb_options *options)
  {
  
  	isl_ctx *ctx;
  	isl_schedule *schedule;
      isl_union_set *domain;
  
  	if (!ps)
  		return NULL;
  
  	ctx = isl_union_set_get_ctx(ps->domain);
      schedule = isl_schedule_copy(ps->pet->schedule);
      domain = isl_union_set_copy(ps->domain);
      schedule = isl_schedule_intersect_domain(schedule, domain);
      fprintf(stderr, "\nOriginal schedule:\n");
      print_schedule(schedule);
  	// schedule = compute_schedule(ps);
      schedule = do_tactics(schedule, ps);
      fprintf(stderr, "\nSchedule after tactics:\n");
      print_schedule(schedule);
  
  	return schedule;
  }
  
  /*
   */
  static __isl_give isl_printer *print_with_schedule(
      __isl_take isl_printer *p, struct polyxb_scop *ps,
      __isl_take isl_schedule *schedule, struct polyxb_options *options)
  {
      int hidden;
      isl_set *context;
  
      p = isl_printer_start_line(p);
      p = isl_printer_print_str(p, "/* Generated by PolyXB */");
      p = isl_printer_end_line(p);
  
      p = set_macro_names(p);
      p = print_exposed_declarations(p, ps);
      hidden = polyxb_scop_any_hidden_declarations(ps);
      if (hidden) {
          p = start_block(p);
          p = print_hidden_declarations(p, ps);
      }
  
      context = isl_set_copy(ps->context);
      context = isl_set_from_params(context);
      schedule = isl_schedule_insert_context(schedule, context);
      p = print_scop(ps, schedule, p, options);
      if (hidden)
          p = end_block(p);
  
      return p;
  }
  
  /*
   */
  static __isl_give isl_printer *generate(__isl_take isl_printer *p,
      struct polyxb_scop *scop, struct polyxb_options *options)
  {
      isl_schedule *schedule;
      schedule = get_schedule(scop, options);
  
      return print_with_schedule(p, scop, schedule, options);
  }
  
  /*
   */
  static __isl_give isl_printer *print_xbar_wrap(__isl_take isl_printer *p,
      struct polyxb_scop *scop, void *user)
  {
      struct polyxb_options *options = user;
      return generate(p, scop, options);
  }
  
  /*
   */
  static __isl_give isl_printer *transform(__isl_take isl_printer *p,
      struct pet_scop *scop, void *user)
  {
      struct polyxb_transform_data *data = user;
      struct polyxb_scop *ps;
  
      if (print_original(scop, data->options)) {
          p = pet_scop_print_original(scop, p);
          pet_scop_free(scop);
          return p;
      }
  
      scop = pet_scop_align_params(scop);
      ps = polyxb_scop_from_pet_scop(scop, data->options);
     
      /* This is actually calling `print_xbar_wrap()`. */
      p = data->transform(p, ps, data->user);
  
      polyxb_scop_free(ps);
      pet_scop_free(scop);
  
      return p;
  }
  
  /* The main transform function.
   */
  int polyxb_transform(isl_ctx *ctx, const char *input, FILE *out,
      struct polyxb_options *options,
      __isl_give isl_printer *(*fn)(__isl_take isl_printer *p,
          struct polyxb_scop *scop, void *user), void *user)
  {
      struct polyxb_transform_data data = { options, fn, user };
      /* This contains a loop through all the scops. */
      return pet_transform_C_source(ctx, input, out, &transform, &data);
  }
  
  /* Main function.
   */
  int main(int argc, char **argv)
  {
      int r;
      isl_ctx *ctx;
      struct options *options;
  
      options = options_new_with_defaults();
      assert(options);
  
      ctx = isl_ctx_alloc_with_options(&options_args, options);
      argc = options_parse(options, argc, argv, ISL_ARG_ALL);
  
      // /* Sanity checks. */
      // if (options->polyxb->en_pipeline && ~options->polyxb->en_tiling) {
      //     fprintf(stderr, "-p option must be used along with -t option.\n");
      //     return 1;
      // }
  
      FILE *output_file;
      output_file = get_output_file(options->input, options->output);
      if (!output_file)
          return -1;
      
      r = polyxb_transform(ctx, options->input, output_file, options->polyxb,
              &print_xbar_wrap, options);
  
      fclose(output_file);
      isl_ctx_free(ctx);
  
      return r;
  }
  