diff options
Diffstat (limited to 'iburg/briggs/icg-filter.c')
-rw-r--r-- | iburg/briggs/icg-filter.c | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/iburg/briggs/icg-filter.c b/iburg/briggs/icg-filter.c new file mode 100644 index 00000000000..b437e612852 --- /dev/null +++ b/iburg/briggs/icg-filter.c @@ -0,0 +1,415 @@ +/* Decide whether to use IRA or ICG at function granularity. + Copyright (C) 2008 Free Software Foundation, Inc. + +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 +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "flags.h" +#include "tm_p.h" +#include "errors.h" +#include "function.h" +#include "basic-block.h" +#include "tree-pass.h" +#include "df.h" +#include "langhooks.h" +#include "icg.h" + +#define MAX_NAME_SIZE 256 + +static int original_flag_icg = -1; +static int original_flag_late_codegen = -1; + +/* Strip leading and trailing white space and comments from line. + Modifies STR. Stupid C, I hate you. */ + +static +char *strip_string(char *str) +{ + char *start, *end; + + for (start = str; + *start && (*start == ' ' || *start == '\t' || *start == '\n'); + start++) { } + if (*start) + { + for (end = start; *end; end++) { + if (*end == '#') + { + *end = '\0'; + break; + } + } + for (; end >= start && (*end == '\0' || *end == ' ' + || *end == '\t' || *end == '\n'); end--) + *end = '\0'; + } + return start; +} + + +/* Reads in a file specified by FLAG_VALUE into NAMES. Memory is + allocated for NAMES. Returns sense of filter based on + existence of leading '-' in FLAG_VALUE. */ + +static bool +read_allocate_names (const char *flag_value, char ***names) +{ + const char *filename; + bool sense; + int n, nlines; + char buf[MAX_NAME_SIZE] ; + FILE *fp; + + /* FLAG_VALUE always begins with '='. */ + gcc_assert (flag_value[0] == '='); + if (flag_value[1] == '-') { + sense = true; + filename = &(flag_value[2]); + } else { + sense = false; + filename = &(flag_value[1]); + } + fp = fopen (filename, "r"); + if (fp == NULL) + internal_error ("Can't open ICG filter file \"%s\".", filename); + + /* First run through, count number of lines. */ + nlines = 0; + while (fgets (buf, MAX_NAME_SIZE, fp) == buf) + if (*(strip_string (buf))) + nlines++; + *names = XNEWVEC (char *, nlines + 1); + (*names)[nlines] = NULL; + + /* Second run, save lines. */ + rewind(fp); + n = 0; + while (fgets (buf, MAX_NAME_SIZE, fp) == buf) + { + char *str = strip_string (buf); + if (*str) + { + gcc_assert (n < nlines); + (*names)[n] = XNEWVEC (char, MAX_NAME_SIZE); + strncpy((*names)[n], str, MAX_NAME_SIZE); + n++; + } + } + fclose(fp); + return sense; +} + +/* Returns TRUE if NAME is in NAMES, where NAMES is created with + read_allocate_names. */ + +static bool +name_in_array_p (const char *name, char **names) +{ + int i; + for (i = 0; names[i]; i++) + if (strcmp (name, names[i]) == 0) + return true; + return false; +} + +#define REJECT(msg) { \ + fflush(stdout); \ + fprintf(stderr, "ICG rejects \"%s\" (%s): %s\n", dname, aname, msg); \ + return true; \ +} + +/* + * Return TRUE if this node is to be rejected, + * eg it appears to contain things that the rest of ICG can not handle. + */ +static +bool icg_filter_walk_rtx_tree_test(rtx insn, const char *dname, const char *aname) +{ + enum rtx_code this_code; + enum machine_mode this_mode; + + this_code = GET_CODE(insn); + this_mode = GET_MODE(insn); + + switch (this_mode) { + + case XFmode: + REJECT("XFmode"); + /*NOTREACHED*/ + + case TFmode: + REJECT("TFmode"); + /*NOTREACHED*/ + + default: + break; + } + + switch (this_code) { + + case UNSPEC: + { + const int unspec_code = XINT(insn, 1); + if (unspec_code == UNSPEC_SSE_PROLOGUE_SAVE) { + REJECT("UNSPEC_SSE_PROLOGUE_SAVE in function"); + /*NOTREACHED*/ + } + if (unspec_code == UNSPEC_ADD_CARRY) { + REJECT("UNSPEC_ADD_CARRY in function"); + /*NOTREACHED*/ + } + } + break; + + case UNSPEC_VOLATILE: + { + const int unspec_code = XINT(insn, 1); + char buf[BUFSIZ]; + /* + * some candidates: + * UNSPEC_SET_GOT (done as a pattern sync_old_addsi), code: lock xaddl %eax + * (tarpit to support UNSPEC_SET_GOT in gcc/config/i386) + */ + snprintf(buf, sizeof(buf), + "unspec_volatile code in function: %d", unspec_code); + REJECT(buf); + /*NOTREACHED*/ + } + break; + + case ASM_OPERANDS: + { + const char *template = ASM_OPERANDS_TEMPLATE(insn); + char buf[BUFSIZ]; + snprintf(buf, sizeof(buf), "asm in function: \"%s\"", + template ? template : "?"); + if (icg_analyze_asm(insn, ICG_ASM_PHASE_FILTER)) { + fflush(stdout); + fprintf(stderr, "ICG consumes asm \"%s\" (%s): %s\n", dname, aname, buf); \ + /* We will attempt to accept this */ + } else { + REJECT(buf); + } + } + break; + + default: + break; + } + return false; /* this node is not rejected, eg it is accepted */ +} + +typedef struct icg_filter_closure_ { + const char *dname; + const char *aname; +} icg_filter_closure; + +/* + * This is a worker function for for_each_rtx. + * Return -1 to stop traversing sub expressions. + * Return 0 to continue traversing. + * Otherwise stop traversal immediately; we'll do this when we reject the tree. + */ +static +int icg_filter_walk_worker(rtx *x, void *data) +{ + const icg_filter_closure *cl = (const icg_filter_closure *)data; + if (x && *x) { + rtx insn = *x; + const bool node_rejected = icg_filter_walk_rtx_tree_test(insn, cl->dname, cl->aname); + if (node_rejected) { + return 1; /* return 1 immediately */ + } + } + return 0; /* continue traversing */ +} + +/* + * Return TRUE iff ICG rejects this tree as a candidate, + * eg return FALSE if ICG should accept this tree + * (Note logical inversion with skip_icg_p.) + */ +static +bool icg_filter_walk_rtx_tree(rtx insn, const char *dname, const char *aname) +{ + icg_filter_closure cld; + icg_filter_closure *cl = &cld; + bool is_rejected = false; + cl->dname = dname; + cl->aname = aname; + is_rejected = for_each_rtx(&insn, icg_filter_walk_worker, cl); + return is_rejected; +} + +/* Programmatically determine whether the function should be compiled + with ICG. (Note logical inversion with + icg_filter_walk_rtx_tree). */ + +static bool +skip_icg_programmatic_p (const char *dname, const char *aname) +{ + basic_block bb; + rtx insn; + + FOR_EACH_BB (bb) { + FOR_BB_INSNS (bb, insn) { + if (INSN_P (insn)) { + if (icg_filter_walk_rtx_tree(insn, dname, aname) == true) { + /* + * There's a rejected node somewhere in the tree. We return + * true indicating that we do not accept the tree. + */ + return true; + } + } + } + } + return false; +} + +/* Return TRUE iff ICG should not be applied to the current function based + on flag_icg_filter_file option. */ + +static bool +skip_icg_file_p (const char *dname, const char *aname) +{ + static char **names = NULL; + static bool skip_sense; + bool match; + + gcc_assert (flag_icg_filter_file); + if (!names) + skip_sense = read_allocate_names (flag_icg_filter_file, &names); + + match = name_in_array_p (main_input_filename, names); + if (skip_sense && match) + REJECT ("filename name matches in icg-filter reject file"); + if (!skip_sense && !match) + REJECT ("filename name not in icg-filter accept file"); + return false; +} + + +/* Return TRUE iff ICG should not be applied to the current function + based on flag_icg_filter_function option. */ + +static bool +skip_icg_function_p (const char *dname, const char *aname) +{ + static char **names = NULL; + static bool skip_sense; + bool match; + + gcc_assert (flag_icg_filter_function); + if (!names) + skip_sense = read_allocate_names (flag_icg_filter_function, &names); + + match = name_in_array_p (dname, names) || name_in_array_p (aname, names); + if (skip_sense && match) + REJECT ("function name matches in icg-filter reject file"); + if (!skip_sense && !match) + REJECT ("function name not in icg-filter accept file"); + return false; +} + +#undef REJECT + +/* Return TRUE iff ICG should not be applied to the current function + based on -ficg-filter-* flags. */ + +static bool +skip_icg_p (void) +{ + const char *dname = current_function_name(); + const char *aname = current_function_assembler_name(); + + if (flag_icg_filter_program && + skip_icg_programmatic_p (dname, aname)) { + return true; + } + + if (flag_icg_filter_file && skip_icg_file_p (dname, aname)) { + return true; + } + + if (flag_icg_filter_function && skip_icg_function_p (dname, aname)) { + return true; + } + + fflush(stdout); + fprintf(stderr, "ICG accepts \"%s\" (%s)\n", dname, aname); + return false; +} + +/* Decide whether to use ICG or IRA for this function and set the + flags accordingly. */ + +static unsigned +rest_of_handle_icg_filter (void) +{ + if (skip_icg_p ()) + { + flag_icg = 0; + flag_late_codegen = 1; + flag_ira = 1; + } + else + { + flag_icg = 1; + flag_late_codegen = original_flag_late_codegen; + flag_ira = 0; + } + return 0; +} + +static bool +gate_icg_filter (void) +{ + if (original_flag_icg == -1) + { + original_flag_icg = flag_icg; + original_flag_late_codegen = flag_late_codegen; + } + + return (original_flag_icg && (flag_icg_filter_program + || flag_icg_filter_file + || flag_icg_filter_function)); +} + + +struct rtl_opt_pass pass_icg_filter = +{ + { + RTL_PASS, + "icg", /* name */ + gate_icg_filter, /* gate */ + rest_of_handle_icg_filter, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + } +}; |