diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2017-11-13 14:16:10 +0100 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2017-11-13 14:16:10 +0100 |
| commit | 1f6cd6fe94fc440a9bbd9c2f1070bd016e550be4 (patch) | |
| tree | 73d5dee14c2d20e92b37b868ae3e12fb8d3b8cc3 | |
| parent | 5d7a65b06e8f8d42f80a046950e8f990d149b48e (diff) | |
| parent | 555217d63d01f31d6322d475e33b5912a5926169 (diff) | |
| download | sparse-dev-1f6cd6fe94fc440a9bbd9c2f1070bd016e550be4.tar.gz | |
Merge branch 'dump-ir' into tip
| -rw-r--r-- | Documentation/options.md | 29 | ||||
| -rwxr-xr-x | cgcc | 3 | ||||
| -rw-r--r-- | lib.c | 246 | ||||
| -rw-r--r-- | lib.h | 19 | ||||
| -rw-r--r-- | linearize.c | 12 | ||||
| -rw-r--r-- | sparse.1 | 8 | ||||
| -rw-r--r-- | test-linearize.c | 2 | ||||
| -rw-r--r-- | test-unssa.c | 2 | ||||
| -rw-r--r-- | validation/linear/bitfield-init-mask.c | 2 | ||||
| -rw-r--r-- | validation/option-parsing-00.c | 5 | ||||
| -rw-r--r-- | validation/option-parsing-01.c | 5 |
11 files changed, 257 insertions, 76 deletions
diff --git a/Documentation/options.md b/Documentation/options.md new file mode 100644 index 00000000..14698a98 --- /dev/null +++ b/Documentation/options.md @@ -0,0 +1,29 @@ +# Options + +This file is a complement of man page for sparse but meant +for options not to be used by sparse itself but by the other +tools. + +## Developer options: + +### Select the passes + +* '-f\<name-of-the-pass\>[-disable|-enable|=last]' + + If '=last' is used, all passes after the specified one are disabled. + By default all passes are enabled. + + The passes currently understood are: + * 'mem2reg' + * 'optim' + +### Internal Representation + +* '-fdump-ir[=\<pass\>[,\<pass\>...]]' + + Dump the IR at each of the given passes. + + The passes currently understood are: + * 'linearize' + * 'mem2reg' + * 'final' @@ -103,7 +103,8 @@ sub check_only_option { my ($arg) = @_; return 1 if $arg =~ /^-W(no-?)?(address-space|bitwise|cast-to-as|cast-truncate|context|decl|default-bitfield-sign|designated-init|do-while|enum-mismatch|init-cstring|memcpy-max-count|non-pointer-null|old-initializer|one-bit-signed-bitfield|override-init-all|paren-string|ptr-subtraction-blows|return-void|sizeof-bool|sparse-all|sparse-error|transparent-union|typesign|undef|unknown-attribute)$/; return 1 if $arg =~ /^-v(no-?)?(entry|dead)$/; - return 1 if $arg =~ /^-f(dump-linearize|memcpy-max-count)(=\S*)?$/; + return 1 if $arg =~ /^-f(dump-ir|memcpy-max-count)(=\S*)?$/; + return 1 if $arg =~ /^-f(mem2reg|optim)(-enable|-disable|=last)?$/; return 0; } @@ -259,9 +259,10 @@ int dump_macro_defs = 0; int dbg_entry = 0; int dbg_dead = 0; +unsigned long fdump_ir; int fmem_report = 0; -int fdump_linearize; unsigned long long fmemcpy_max_count = 100000; +unsigned long fpasses = ~0UL; int preprocess_only; @@ -477,9 +478,77 @@ static void handle_arch_finalize(void) handle_arch_msize_long_finalize(); } +const char *match_option(const char *arg, const char *prefix) +{ + unsigned int n = strlen(prefix); + if (strncmp(arg, prefix, n) == 0) + return arg + n; + return NULL; +} + + +struct mask_map { + const char *name; + unsigned long mask; +}; + +static int apply_mask(unsigned long *val, const char *str, unsigned len, const struct mask_map *map, int neg) +{ + const char *name; + + for (;(name = map->name); map++) { + if (!strncmp(name, str, len) && !name[len]) { + if (neg == 0) + *val |= map->mask; + else + *val &= ~map->mask; + return 0; + } + } + return 1; +} + +static int handle_suboption_mask(const char *arg, const char *opt, const struct mask_map *map, unsigned long *flag) +{ + if (*opt == '\0') { + apply_mask(flag, "", 0, map, 0); + return 1; + } + if (*opt++ != '=') + return 0; + while (1) { + unsigned int len = strcspn(opt, ",+"); + int neg = 0; + if (len == 0) + goto end; + if (!strncmp(opt, "no-", 3)) { + opt += 3; + len -= 3; + neg = 1; + } + if (apply_mask(flag, opt, len, map, neg)) + die("error: wrong option '%.*s' for \'%s\'", len, opt, arg); + +end: + opt += len; + if (*opt++ == '\0') + break; + } + return 1; +} + + +#define OPT_INVERSE 1 +struct flag { + const char *name; + int *flag; + int (*fun)(const char *arg, const char *opt, const struct flag *, int options); + unsigned long mask; +}; -static int handle_simple_switch(const char *arg, const char *name, int *flag) +static int handle_switches(const char *ori, const char *opt, const struct flag *flags) { + const char *arg = opt; int val = 1; // Prefixe "no-" mean to turn flag off. @@ -488,15 +557,58 @@ static int handle_simple_switch(const char *arg, const char *name, int *flag) val = 0; } - if (strcmp(arg, name) == 0) { - *flag = val; - return 1; + for (; flags->name; flags++) { + const char *opt = match_option(arg, flags->name); + int rc; + + if (!opt) + continue; + + if (flags->fun) { + int options = 0; + if (!val) + options |= OPT_INVERSE; + if ((rc = flags->fun(ori, opt, flags, options))) + return rc; + } + + // boolean flag + if (opt[0] == '\0' && flags->flag) { + *flags->flag = val; + return 1; + } } // not handled return 0; } + +#define OPTNUM_ZERO_IS_INF 1 +#define OPTNUM_UNLIMITED 2 + +#define OPT_NUMERIC(NAME, TYPE, FUNCTION) \ +static int opt_##NAME(const char *arg, const char *opt, TYPE *ptr, int flag) \ +{ \ + char *end; \ + TYPE val; \ + \ + val = FUNCTION(opt, &end, 0); \ + if (*end != '\0' || end == opt) { \ + if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited")) \ + val = ~val; \ + else \ + die("error: wrong argument to \'%s\'", arg); \ + } \ + if ((flag & OPTNUM_ZERO_IS_INF) && val == 0) \ + val = ~val; \ + *ptr = val; \ + return 1; \ +} + +OPT_NUMERIC(ullong, unsigned long long, strtoull) + + static char **handle_switch_o(char *arg, char **next) { if (!strcmp (arg, "o")) { // "-o foo" @@ -508,10 +620,7 @@ static char **handle_switch_o(char *arg, char **next) return next; } -static const struct warning { - const char *name; - int *flag; -} warnings[] = { +static const struct flag warnings[] = { { "address", &Waddress }, { "address-space", &Waddress_space }, { "bitwise", &Wbitwise }, @@ -554,7 +663,7 @@ enum { }; -static char **handle_onoff_switch(char *arg, char **next, const struct warning warnings[], int n) +static char **handle_onoff_switch(char *arg, char **next, const struct flag warnings[], int n) { int flag = WARNING_ON; char *p = arg + 1; @@ -596,7 +705,7 @@ static char **handle_switch_W(char *arg, char **next) return next; } -static struct warning debugs[] = { +static struct flag debugs[] = { { "entry", &dbg_entry}, { "dead", &dbg_dead}, }; @@ -615,7 +724,7 @@ static char **handle_switch_v(char *arg, char **next) return next; } -static struct warning dumps[] = { +static struct flag dumps[] = { { "D", &dump_macro_defs}, }; @@ -629,7 +738,7 @@ static char **handle_switch_d(char *arg, char **next) } -static void handle_onoff_switch_finalize(const struct warning warnings[], int n) +static void handle_onoff_switch_finalize(const struct flag warnings[], int n) { unsigned i; @@ -690,69 +799,85 @@ static char **handle_switch_O(char *arg, char **next) return next; } -static char **handle_switch_fmemcpy_max_count(char *arg, char **next) -{ - unsigned long long val; - char *end; - - val = strtoull(arg, &end, 0); - if (*end != '\0' || end == arg) - die("error: missing argument to \"-fmemcpy-max-count=\""); - - if (val == 0) - val = ~0ULL; - fmemcpy_max_count = val; - return next; -} - -static char **handle_switch_ftabstop(char *arg, char **next) +static int handle_ftabstop(const char *arg, const char *opt, const struct flag *flag, int options) { - char *end; unsigned long val; + char *end; - if (*arg == '\0') - die("error: missing argument to \"-ftabstop=\""); + if (*opt == '\0') + die("error: missing argument to \"%s\"", arg); /* we silently ignore silly values */ - val = strtoul(arg, &end, 10); + val = strtoul(opt, &end, 10); if (*end == '\0' && 1 <= val && val <= 100) tabstop = val; - return next; + return 1; } -static char **handle_switch_fdump(char *arg, char **next) +static int handle_fpasses(const char *arg, const char *opt, const struct flag *flag, int options) { - if (!strncmp(arg, "linearize", 9)) { - arg += 9; - if (*arg == '\0') - fdump_linearize = 1; - else if (!strcmp(arg, "=only")) - fdump_linearize = 2; + unsigned long mask; + + mask = flag->mask; + if (*opt == '\0') { + if (options & OPT_INVERSE) + fpasses &= ~mask; else - goto err; + fpasses |= mask; + return 1; } + if (options & OPT_INVERSE) + return 0; + if (!strcmp(opt, "-enable")) { + fpasses |= mask; + return 1; + } + if (!strcmp(opt, "-disable")) { + fpasses &= ~mask; + return 1; + } + if (!strcmp(opt, "=last")) { + // clear everything above + mask |= mask - 1; + fpasses &= mask; + return 1; + } + return 0; +} - /* ignore others flags */ - return next; +static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options) +{ + static const struct mask_map dump_ir_options[] = { + { "", PASS_LINEARIZE }, + { "linearize", PASS_LINEARIZE }, + { "mem2reg", PASS_MEM2REG }, + { "final", PASS_FINAL }, + { }, + }; -err: - die("error: unknown flag \"-fdump-%s\"", arg); + return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir); } -static char **handle_switch_f(char *arg, char **next) +static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options) { - arg++; + opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED); + return 1; +} - if (!strncmp(arg, "tabstop=", 8)) - return handle_switch_ftabstop(arg+8, next); - if (!strncmp(arg, "dump-", 5)) - return handle_switch_fdump(arg+5, next); - if (!strncmp(arg, "memcpy-max-count=", 17)) - return handle_switch_fmemcpy_max_count(arg+17, next); +static struct flag fflags[] = { + { "dump-ir", NULL, handle_fdump_ir }, + { "mem-report", &fmem_report }, + { "memcpy-max-count=", NULL, handle_fmemcpy_max_count }, + { "tabstop=", NULL, handle_ftabstop }, + { "mem2reg", NULL, handle_fpasses, PASS_MEM2REG }, + { "optim", NULL, handle_fpasses, PASS_OPTIM }, + { }, +}; - /* handle switches w/ arguments above, boolean and only boolean below */ - if (handle_simple_switch(arg, "mem-report", &fmem_report)) +static char **handle_switch_f(char *arg, char **next) +{ + if (handle_switches(arg-1, arg+1, fflags)) return next; return next; @@ -774,12 +899,9 @@ static char **handle_switch_a(char *arg, char **next) return next; } -static char **handle_switch_s(char *arg, char **next) +static char **handle_switch_s(const char *arg, char **next) { - if (!strncmp (arg, "std=", 4)) - { - arg += 4; - + if ((arg = match_option(arg, "std="))) { if (!strcmp (arg, "c89") || !strcmp (arg, "iso9899:1990")) standard = STANDARD_C89; @@ -1333,6 +1455,8 @@ struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list handle_switch_v_finalize(); handle_arch_finalize(); + if (fdump_ir == 0) + fdump_ir = PASS_FINAL; list = NULL; if (!ptr_list_empty(filelist)) { @@ -107,6 +107,22 @@ extern void expression_error(struct expression *, const char *, ...) FORMAT_ATTR #define ERROR_PREV_PHASE (1 << 1) extern int has_error; + +enum phase { + PASS__PARSE, + PASS__LINEARIZE, + PASS__MEM2REG, + PASS__OPTIM, + PASS__FINAL, +}; + +#define PASS_PARSE (1UL << PASS__PARSE) +#define PASS_LINEARIZE (1UL << PASS__LINEARIZE) +#define PASS_MEM2REG (1UL << PASS__MEM2REG) +#define PASS_OPTIM (1UL << PASS__OPTIM) +#define PASS_FINAL (1UL << PASS__FINAL) + + extern void add_pre_buffer(const char *fmt, ...) FORMAT_ATTR(1); extern int preprocess_only; @@ -152,8 +168,9 @@ extern int dbg_entry; extern int dbg_dead; extern int fmem_report; -extern int fdump_linearize; +extern unsigned long fdump_ir; extern unsigned long long fmemcpy_max_count; +extern unsigned long fpasses; extern int arch_m64; extern int arch_msize_long; diff --git a/linearize.c b/linearize.c index 905b473e..9040d5d9 100644 --- a/linearize.c +++ b/linearize.c @@ -2186,11 +2186,8 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t add_one_insn(ep, insn); } - if (fdump_linearize) { - if (fdump_linearize == 2) - return ep; + if (fdump_ir & PASS_LINEARIZE) show_entry(ep); - } /* * Do trivial flow simplification - branches to @@ -2201,8 +2198,13 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t /* * Turn symbols into pseudos */ - simplify_symbol_usage(ep); + if (fpasses & PASS_MEM2REG) + simplify_symbol_usage(ep); + if (fdump_ir & PASS_MEM2REG) + show_entry(ep); + if (!(fpasses & PASS_OPTIM)) + return ep; repeat: /* * Remove trivial instructions, and try to CSE @@ -365,12 +365,6 @@ The \fIdir\fR name would normally take the form of the target's normalized GNU triplet. (e.g. i386-linux-gnu). . .SH DEBUG OPTIONS -.TP -.B \-fdump-linearize[=only] -Dump the IR code of a function directly after its linearization, -before any simplifications is made. If the argument \fB=only\fR is -also given no further processing is done on the function. -. .B \-fmem-report Report some statistics about memory allocation used by the tool. . @@ -378,7 +372,7 @@ Report some statistics about memory allocation used by the tool. .TP .B \-fmemcpy-max-count=COUNT Set the limit for the warnings given by \fB-Wmemcpy-max-count\fR. -A COUNT of 0, useless in itself, will effectively disable the warning. +A COUNT of 'unlimited' or '0' will effectively disable the warning. The default limit is 100000. . .TP diff --git a/test-linearize.c b/test-linearize.c index fe0673be..e6d1ee3c 100644 --- a/test-linearize.c +++ b/test-linearize.c @@ -47,6 +47,8 @@ static void clean_up_symbols(struct symbol_list *list) expand_symbol(sym); ep = linearize_symbol(sym); + if (!(fdump_ir & PASS_FINAL)) + continue; if (ep) show_entry(ep); } END_FOR_EACH_PTR(sym); diff --git a/test-unssa.c b/test-unssa.c index 240d9960..80752f43 100644 --- a/test-unssa.c +++ b/test-unssa.c @@ -62,6 +62,8 @@ static int compile(struct symbol_list *list) struct entrypoint *ep; expand_symbol(sym); ep = linearize_symbol(sym); + if (!(fdump_ir & PASS_FINAL)) + continue; if (ep) output_fn(ep); else diff --git a/validation/linear/bitfield-init-mask.c b/validation/linear/bitfield-init-mask.c index 94afa400..aac21e61 100644 --- a/validation/linear/bitfield-init-mask.c +++ b/validation/linear/bitfield-init-mask.c @@ -18,7 +18,7 @@ struct bfu bfu_init_20_23(int a) /* * check-name: bitfield initializer mask - * check-command: test-linearize -fdump-linearize=only -Wno-decl $file + * check-command: test-linearize -fdump-ir=linearize -Wno-decl $file * check-output-ignore * * check-output-contains: and\\..*fffff800\$ diff --git a/validation/option-parsing-00.c b/validation/option-parsing-00.c new file mode 100644 index 00000000..9b85943c --- /dev/null +++ b/validation/option-parsing-00.c @@ -0,0 +1,5 @@ + +/* + * check-name: option parsing 00 + * check-command sparse -foptimize-xyz $file + */ diff --git a/validation/option-parsing-01.c b/validation/option-parsing-01.c new file mode 100644 index 00000000..e33a2ef0 --- /dev/null +++ b/validation/option-parsing-01.c @@ -0,0 +1,5 @@ + +/* + * check-name: option parsing 01 + * check-command sparse -fno-optimize-xyz $file + */ |
