From 5e1d94a00cd15e91468e8277497c34dca93fe5f4 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 25 Jun 2017 17:44:24 +0200 Subject: option: add helper to parse/match command line options The goal of this helper is: - to avoid to have to hardoce the length od the substring - separate the suffix/option part from the whole argument which help for error message. Signed-off-by: Luc Van Oostenryck --- lib.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/lib.c b/lib.c index 73e9a2fe..351da6f4 100644 --- a/lib.c +++ b/lib.c @@ -475,6 +475,13 @@ static void handle_arch_finalize(void) handle_arch_msize_long_finalize(); } +char *match_option(char *arg, const char *prefix) +{ + unsigned int n = strlen(prefix); + if (strncmp(arg, prefix, n) == 0) + return arg + n; + return NULL; +} static int handle_simple_switch(const char *arg, const char *name, int *flag) { @@ -720,11 +727,12 @@ static char **handle_switch_ftabstop(char *arg, char **next) static char **handle_switch_fdump(char *arg, char **next) { - if (!strncmp(arg, "linearize", 9)) { - arg += 9; - if (*arg == '\0') + const char *opt; + + if ((opt = match_option(arg, "linearize"))) { + if (*opt == '\0') fdump_linearize = 1; - else if (!strcmp(arg, "=only")) + else if (!strcmp(opt, "=only")) fdump_linearize = 2; else goto err; @@ -739,14 +747,15 @@ err: static char **handle_switch_f(char *arg, char **next) { + char *opt; arg++; - 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); + if ((opt = match_option(arg, "tabstop="))) + return handle_switch_ftabstop(opt, next); + if ((opt = match_option(arg, "dump-"))) + return handle_switch_fdump(opt, next); + if ((opt = match_option(arg, "memcpy-max-count="))) + return handle_switch_fmemcpy_max_count(opt, next); /* handle switches w/ arguments above, boolean and only boolean below */ if (handle_simple_switch(arg, "mem-report", &fmem_report)) @@ -773,10 +782,7 @@ static char **handle_switch_a(char *arg, char **next) static char **handle_switch_s(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; -- cgit 1.2.3-korg From 2ee3305ea8d50558bdc678745da5f10cf38ab80c Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 28 May 2017 23:44:48 +0200 Subject: option: rename 'struct warning' to 'struct flag' 'struct warning' can be reused for flags other than warnings. To avoid future confusion, rename it to something more general: 'struct flag' (which in its context, handling of compiler flags, is clear enough). Signed-off-by: Luc Van Oostenryck --- lib.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib.c b/lib.c index 351da6f4..04f9de5a 100644 --- a/lib.c +++ b/lib.c @@ -513,7 +513,7 @@ static char **handle_switch_o(char *arg, char **next) return next; } -static const struct warning { +static const struct flag { const char *name; int *flag; } warnings[] = { @@ -558,7 +558,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; @@ -600,7 +600,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}, }; @@ -619,7 +619,7 @@ static char **handle_switch_v(char *arg, char **next) return next; } -static struct warning dumps[] = { +static struct flag dumps[] = { { "D", &dump_macro_defs}, }; @@ -633,7 +633,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; -- cgit 1.2.3-korg From 64f0308da4b59b743a7cbf77915576b613639447 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 28 May 2017 23:51:35 +0200 Subject: option: let handle_simple_switch() handle an array of flags This was used to handle a single flag but we need something more compact when we need to handle several flags. So, adapt this helper so that it now takes an array of flags instead of a single flag. Signed-off-by: Luc Van Oostenryck --- lib.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib.c b/lib.c index 04f9de5a..992fdb49 100644 --- a/lib.c +++ b/lib.c @@ -483,7 +483,12 @@ char *match_option(char *arg, const char *prefix) return NULL; } -static int handle_simple_switch(const char *arg, const char *name, int *flag) +struct flag { + const char *name; + int *flag; +}; + +static int handle_simple_switch(const char *arg, const struct flag *flags) { int val = 1; @@ -493,9 +498,11 @@ 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++) { + if (strcmp(arg, flags->name) == 0) { + *flags->flag = val; + return 1; + } } // not handled @@ -513,10 +520,7 @@ static char **handle_switch_o(char *arg, char **next) return next; } -static const struct flag { - const char *name; - int *flag; -} warnings[] = { +static const struct flag warnings[] = { { "address", &Waddress }, { "address-space", &Waddress_space }, { "bitwise", &Wbitwise }, @@ -745,6 +749,11 @@ err: die("error: unknown flag \"-fdump-%s\"", arg); } +static struct flag fflags[] = { + { "mem-report", &fmem_report }, + { }, +}; + static char **handle_switch_f(char *arg, char **next) { char *opt; @@ -758,7 +767,7 @@ static char **handle_switch_f(char *arg, char **next) return handle_switch_fmemcpy_max_count(opt, next); /* handle switches w/ arguments above, boolean and only boolean below */ - if (handle_simple_switch(arg, "mem-report", &fmem_report)) + if (handle_simple_switch(arg, fflags)) return next; return next; -- cgit 1.2.3-korg From dc54f0c9a44c084f894e346eea3ea626733052bb Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 25 Jun 2017 17:53:56 +0200 Subject: option: extract OPTION_NUMERIC() from handle_switch_fmemcpy_max_count() Signed-off-by: Luc Van Oostenryck --- lib.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib.c b/lib.c index 992fdb49..5fda4b02 100644 --- a/lib.c +++ b/lib.c @@ -509,6 +509,25 @@ static int handle_simple_switch(const char *arg, const struct flag *flags) return 0; } +#define OPT_NUMERIC(NAME, TYPE, FUNCTION) \ +static int opt_##NAME(char *arg, const char *name, TYPE *ptr) \ +{ \ + char *opt; \ + char *end; \ + TYPE val; \ + \ + if (!(opt = match_option(arg, name+2))) \ + return 0; \ + opt++; /* opt's last char is '=' */ \ + val = FUNCTION(opt, &end, 0); \ + if (*end != '\0' || end == opt) { \ + die("error: missing argument to \"%s\"", name); \ + } \ + *ptr = val; \ + return 1; \ +} + + static char **handle_switch_o(char *arg, char **next) { if (!strcmp (arg, "o")) { // "-o foo" -- cgit 1.2.3-korg From 443142fb7e0f62e7e4fde9edc23166e21a7cbbd4 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 13 Sep 2017 09:57:49 +0200 Subject: option: add support for options with 'zero is infinity' For some options with a numerical value, it is sometimes desirable, to easily specify we want the maximum possible value. This patch allow to interpret '=0' as meaning the maximum value. Signed-off-by: Luc Van Oostenryck --- lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib.c b/lib.c index 5fda4b02..6352b4e9 100644 --- a/lib.c +++ b/lib.c @@ -509,8 +509,11 @@ static int handle_simple_switch(const char *arg, const struct flag *flags) return 0; } + +#define OPTNUM_ZERO_IS_INF 1 + #define OPT_NUMERIC(NAME, TYPE, FUNCTION) \ -static int opt_##NAME(char *arg, const char *name, TYPE *ptr) \ +static int opt_##NAME(char *arg, const char *name, TYPE *ptr, int flag) \ { \ char *opt; \ char *end; \ @@ -523,6 +526,8 @@ static int opt_##NAME(char *arg, const char *name, TYPE *ptr) \ if (*end != '\0' || end == opt) { \ die("error: missing argument to \"%s\"", name); \ } \ + if ((flag & OPTNUM_ZERO_IS_INF) && val == 0) \ + val = ~val; \ *ptr = val; \ return 1; \ } -- cgit 1.2.3-korg From f28fb7268ce372c6c0c4bf10b1153017f6f8a994 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 13 Sep 2017 10:11:49 +0200 Subject: option: add support for '-=unlimited' For some options with a numerical value, it is sometimes desirable, when the value is used to limits something, to easily specify we want to remove any limits. This patch allow to use 'unlimited' for this by interpreting it as the maximum value. Signed-off-by: Luc Van Oostenryck --- lib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib.c b/lib.c index 6352b4e9..4c210d58 100644 --- a/lib.c +++ b/lib.c @@ -511,6 +511,7 @@ static int handle_simple_switch(const char *arg, const struct flag *flags) #define OPTNUM_ZERO_IS_INF 1 +#define OPTNUM_UNLIMITED 2 #define OPT_NUMERIC(NAME, TYPE, FUNCTION) \ static int opt_##NAME(char *arg, const char *name, TYPE *ptr, int flag) \ @@ -524,6 +525,9 @@ static int opt_##NAME(char *arg, const char *name, TYPE *ptr, int flag) \ opt++; /* opt's last char is '=' */ \ val = FUNCTION(opt, &end, 0); \ if (*end != '\0' || end == opt) { \ + if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited")) \ + val = ~val; \ + else \ die("error: missing argument to \"%s\"", name); \ } \ if ((flag & OPTNUM_ZERO_IS_INF) && val == 0) \ -- cgit 1.2.3-korg From dd761bbd09c8684adae9c783ef3d2d20cf5e06ad Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 13 Sep 2017 09:08:49 +0200 Subject: option: use OPTION_NUMERIC() for handle_switch_fmemcpy_max_count() Signed-off-by: Luc Van Oostenryck --- lib.c | 22 +++++----------------- sparse.1 | 2 +- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/lib.c b/lib.c index 4c210d58..95601b00 100644 --- a/lib.c +++ b/lib.c @@ -536,6 +536,8 @@ static int opt_##NAME(char *arg, const char *name, TYPE *ptr, int flag) \ return 1; \ } +OPT_NUMERIC(ullong, unsigned long long, strtoull) + static char **handle_switch_o(char *arg, char **next) { @@ -726,21 +728,6 @@ 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) { char *end; @@ -791,8 +778,9 @@ static char **handle_switch_f(char *arg, char **next) return handle_switch_ftabstop(opt, next); if ((opt = match_option(arg, "dump-"))) return handle_switch_fdump(opt, next); - if ((opt = match_option(arg, "memcpy-max-count="))) - return handle_switch_fmemcpy_max_count(opt, next); + if (opt_ullong(arg, "-fmemcpy-max-count=", &fmemcpy_max_count, + OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED)) + return next; /* handle switches w/ arguments above, boolean and only boolean below */ if (handle_simple_switch(arg, fflags)) diff --git a/sparse.1 b/sparse.1 index b79c5876..bec8d6d7 100644 --- a/sparse.1 +++ b/sparse.1 @@ -369,7 +369,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 -- cgit 1.2.3-korg From 2412de935e06139a2abee9a49ee4af0cb6dfdd62 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 14 Sep 2017 16:24:31 +0200 Subject: option: constify match_option() Until now, match_option() needed a non-const argment and returned a non-const result. Since it is no more needed, let's use const. Signed-off-by: Luc Van Oostenryck --- lib.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib.c b/lib.c index 95601b00..3c9618a0 100644 --- a/lib.c +++ b/lib.c @@ -475,7 +475,7 @@ static void handle_arch_finalize(void) handle_arch_msize_long_finalize(); } -char *match_option(char *arg, const char *prefix) +const char *match_option(const char *arg, const char *prefix) { unsigned int n = strlen(prefix); if (strncmp(arg, prefix, n) == 0) @@ -514,9 +514,9 @@ static int handle_simple_switch(const char *arg, const struct flag *flags) #define OPTNUM_UNLIMITED 2 #define OPT_NUMERIC(NAME, TYPE, FUNCTION) \ -static int opt_##NAME(char *arg, const char *name, TYPE *ptr, int flag) \ +static int opt_##NAME(const char *arg, const char *name, TYPE *ptr, int flag)\ { \ - char *opt; \ + const char *opt; \ char *end; \ TYPE val; \ \ @@ -728,7 +728,7 @@ static char **handle_switch_O(char *arg, char **next) return next; } -static char **handle_switch_ftabstop(char *arg, char **next) +static char **handle_switch_ftabstop(const char *arg, char **next) { char *end; unsigned long val; @@ -744,7 +744,7 @@ static char **handle_switch_ftabstop(char *arg, char **next) return next; } -static char **handle_switch_fdump(char *arg, char **next) +static char **handle_switch_fdump(const char *arg, char **next) { const char *opt; @@ -771,7 +771,7 @@ static struct flag fflags[] = { static char **handle_switch_f(char *arg, char **next) { - char *opt; + const char *opt; arg++; if ((opt = match_option(arg, "tabstop="))) @@ -805,7 +805,7 @@ 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 ((arg = match_option(arg, "std="))) { if (!strcmp (arg, "c89") || -- cgit 1.2.3-korg From fbf903ffecc0dbaf27283329ef8bac81b4dfc1e2 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 13 Sep 2017 18:31:43 +0200 Subject: option: handle switches by table Currently, the parsing of options is often quite ad-hoc and thus: - need a lot of code - is not clear at all Improve this by making this table driven. Signed-off-by: Luc Van Oostenryck --- lib.c | 91 +++++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/lib.c b/lib.c index 3c9618a0..a03a94d6 100644 --- a/lib.c +++ b/lib.c @@ -483,13 +483,18 @@ const char *match_option(const char *arg, const char *prefix) return NULL; } + +#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 struct flag *flags) +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. @@ -499,7 +504,22 @@ static int handle_simple_switch(const char *arg, const struct flag *flags) } for (; flags->name; flags++) { - if (strcmp(arg, flags->name) == 0) { + 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; } @@ -514,21 +534,17 @@ static int handle_simple_switch(const char *arg, const struct flag *flags) #define OPTNUM_UNLIMITED 2 #define OPT_NUMERIC(NAME, TYPE, FUNCTION) \ -static int opt_##NAME(const char *arg, const char *name, TYPE *ptr, int flag)\ +static int opt_##NAME(const char *arg, const char *opt, TYPE *ptr, int flag) \ { \ - const char *opt; \ char *end; \ TYPE val; \ \ - if (!(opt = match_option(arg, name+2))) \ - return 0; \ - opt++; /* opt's last char is '=' */ \ val = FUNCTION(opt, &end, 0); \ if (*end != '\0' || end == opt) { \ if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited")) \ val = ~val; \ else \ - die("error: missing argument to \"%s\"", name); \ + die("error: wrong argument to \'%s\'", arg); \ } \ if ((flag & OPTNUM_ZERO_IS_INF) && val == 0) \ val = ~val; \ @@ -728,62 +744,51 @@ static char **handle_switch_O(char *arg, char **next) return next; } -static char **handle_switch_ftabstop(const 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(const char *arg, char **next) +static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options) { - const char *opt; - - if ((opt = match_option(arg, "linearize"))) { - if (*opt == '\0') - fdump_linearize = 1; - else if (!strcmp(opt, "=only")) - fdump_linearize = 2; - else - goto err; - } + if (*opt == '\0') + fdump_linearize = 1; + else if (!strcmp(opt, "=only")) + fdump_linearize = 2; + else + die("error: wrong option \"%s\"", arg); - /* ignore others flags */ - return next; + return 1; +} -err: - die("error: unknown flag \"-fdump-%s\"", arg); +static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options) +{ + opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED); + return 1; } static struct flag fflags[] = { - { "mem-report", &fmem_report }, + { "dump-linearize", NULL, handle_fdump_ir }, + { "mem-report", &fmem_report }, + { "memcpy-max-count=", NULL, handle_fmemcpy_max_count }, + { "tabstop=", NULL, handle_ftabstop }, { }, }; static char **handle_switch_f(char *arg, char **next) { - const char *opt; - arg++; - - if ((opt = match_option(arg, "tabstop="))) - return handle_switch_ftabstop(opt, next); - if ((opt = match_option(arg, "dump-"))) - return handle_switch_fdump(opt, next); - if (opt_ullong(arg, "-fmemcpy-max-count=", &fmemcpy_max_count, - OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED)) - return next; - - /* handle switches w/ arguments above, boolean and only boolean below */ - if (handle_simple_switch(arg, fflags)) + if (handle_switches(arg-1, arg+1, fflags)) return next; return next; -- cgit 1.2.3-korg From 8e7c25a638aaa30d8902289480810c681b5d1a45 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sat, 2 Sep 2017 09:48:59 +0200 Subject: dump-ir: add defines for the compilation passes Signed-off-by: Luc Van Oostenryck --- lib.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib.h b/lib.h index 307ccaeb..27c99025 100644 --- a/lib.h +++ b/lib.h @@ -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; -- cgit 1.2.3-korg From e7a9d67e1834758a9a5f6e3ce9b497cf32a52674 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Sun, 12 Nov 2017 09:38:25 +0100 Subject: dump-ir: add testcase for option parsing corner case --- validation/option-parsing-00.c | 5 +++++ validation/option-parsing-01.c | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 validation/option-parsing-00.c create mode 100644 validation/option-parsing-01.c 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 + */ -- cgit 1.2.3-korg From a5f0d96243ac8597e46c6713cbafb197a1b7d35c Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 14 Sep 2017 06:34:51 +0200 Subject: dump-ir: allow to specify the passes to execute via cli's options Signed-off-by: Luc Van Oostenryck --- Documentation/options.md | 18 ++++++++++++++++++ cgcc | 1 + lib.c | 34 ++++++++++++++++++++++++++++++++++ lib.h | 1 + 4 files changed, 54 insertions(+) create mode 100644 Documentation/options.md diff --git a/Documentation/options.md b/Documentation/options.md new file mode 100644 index 00000000..5677789e --- /dev/null +++ b/Documentation/options.md @@ -0,0 +1,18 @@ +# 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\[-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' diff --git a/cgcc b/cgcc index a8d7b4f2..75eee26f 100755 --- a/cgcc +++ b/cgcc @@ -104,6 +104,7 @@ sub check_only_option { 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(mem2reg|optim)(-enable|-disable|=last)?$/; return 0; } diff --git a/lib.c b/lib.c index a03a94d6..a714dc2b 100644 --- a/lib.c +++ b/lib.c @@ -260,6 +260,7 @@ int dbg_dead = 0; int fmem_report = 0; int fdump_linearize; unsigned long long fmemcpy_max_count = 100000; +unsigned long fpasses = ~0UL; int preprocess_only; @@ -760,6 +761,37 @@ static int handle_ftabstop(const char *arg, const char *opt, const struct flag * return 1; } +static int handle_fpasses(const char *arg, const char *opt, const struct flag *flag, int options) +{ + unsigned long mask; + + mask = flag->mask; + if (*opt == '\0') { + if (options & OPT_INVERSE) + fpasses &= ~mask; + else + 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; +} + static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options) { if (*opt == '\0') @@ -783,6 +815,8 @@ static struct flag fflags[] = { { "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 }, { }, }; diff --git a/lib.h b/lib.h index 27c99025..5111a0eb 100644 --- a/lib.h +++ b/lib.h @@ -169,6 +169,7 @@ extern int dbg_dead; extern int fmem_report; extern int fdump_linearize; extern unsigned long long fmemcpy_max_count; +extern unsigned long fpasses; extern int arch_m64; extern int arch_msize_long; -- cgit 1.2.3-korg From 092e22f01df4dfd54a55bec0c40e8cda9b6a7161 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 14 Sep 2017 06:51:10 +0200 Subject: dump-ir: activate/deactive pass 'mem2reg' Signed-off-by: Luc Van Oostenryck --- linearize.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linearize.c b/linearize.c index ba76397e..31cc9480 100644 --- a/linearize.c +++ b/linearize.c @@ -2235,7 +2235,8 @@ 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); repeat: /* -- cgit 1.2.3-korg From b1f6b9740bd8a542ece0d0ec5c41d26b2e0ca56a Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 14 Sep 2017 06:51:21 +0200 Subject: dump-ir: allow to skip the optimization pass(es) For experimenting with some optimization and the linearization process, it's useful to see the raw result, without any kind of optimization. This patch test PASS_OPTIM (-foptim-{enable,disable}) to see if the whole optimization process can be skipped. Note: ideally, this should be coupled with -O0 but this could create problems with the 'sparse' tools when used on file wit an optimization level of 0 (since the sparse tools depends on the optimization for the context checking to be accurate and in general diagnostics also need at least basic optimization). Signed-off-by: Luc Van Oostenryck --- linearize.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linearize.c b/linearize.c index 31cc9480..55448a8c 100644 --- a/linearize.c +++ b/linearize.c @@ -2238,6 +2238,8 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t if (fpasses & PASS_MEM2REG) simplify_symbol_usage(ep); + if (!(fpasses & PASS_OPTIM)) + return ep; repeat: /* * Remove trivial instructions, and try to CSE -- cgit 1.2.3-korg From 383015dbad3785b08220a932a9adb43c574a44f2 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 14 Sep 2017 07:04:30 +0200 Subject: dump-ir: saner use of fdump_linearize Signed-off-by: Luc Van Oostenryck --- linearize.c | 5 +---- test-linearize.c | 2 ++ test-unssa.c | 2 ++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/linearize.c b/linearize.c index 55448a8c..5a2e8dfa 100644 --- a/linearize.c +++ b/linearize.c @@ -2220,11 +2220,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_linearize) show_entry(ep); - } /* * Do trivial flow simplification - branches to diff --git a/test-linearize.c b/test-linearize.c index fe0673be..28452678 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_linearize == 2) + continue; if (ep) show_entry(ep); } END_FOR_EACH_PTR(sym); diff --git a/test-unssa.c b/test-unssa.c index 240d9960..ec5c9301 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_linearize == 2) + continue; if (ep) output_fn(ep); else -- cgit 1.2.3-korg From 8a1c335f12107f504bcb8733be357babfc0cb0b2 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 23 Aug 2017 13:13:24 +0200 Subject: dump-ir: rename -fdump-linearize to -fdump-ir as it will be used for dumping the IR not only just after linearization but after other passes too. Signed-off-by: Luc Van Oostenryck --- cgcc | 2 +- lib.c | 8 ++++---- lib.h | 2 +- linearize.c | 2 +- sparse.1 | 2 +- test-linearize.c | 2 +- test-unssa.c | 2 +- validation/linear/bitfield-init-mask.c | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cgcc b/cgcc index 75eee26f..4aeb2da6 100755 --- a/cgcc +++ b/cgcc @@ -103,7 +103,7 @@ 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; } diff --git a/lib.c b/lib.c index a714dc2b..7d7a3647 100644 --- a/lib.c +++ b/lib.c @@ -257,8 +257,8 @@ int dump_macro_defs = 0; int dbg_entry = 0; int dbg_dead = 0; +int fdump_ir; int fmem_report = 0; -int fdump_linearize; unsigned long long fmemcpy_max_count = 100000; unsigned long fpasses = ~0UL; @@ -795,9 +795,9 @@ static int handle_fpasses(const char *arg, const char *opt, const struct flag *f static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options) { if (*opt == '\0') - fdump_linearize = 1; + fdump_ir = 1; else if (!strcmp(opt, "=only")) - fdump_linearize = 2; + fdump_ir = 2; else die("error: wrong option \"%s\"", arg); @@ -811,7 +811,7 @@ static int handle_fmemcpy_max_count(const char *arg, const char *opt, const stru } static struct flag fflags[] = { - { "dump-linearize", NULL, handle_fdump_ir }, + { "dump-ir", NULL, handle_fdump_ir }, { "mem-report", &fmem_report }, { "memcpy-max-count=", NULL, handle_fmemcpy_max_count }, { "tabstop=", NULL, handle_ftabstop }, diff --git a/lib.h b/lib.h index 5111a0eb..bfcfd2a0 100644 --- a/lib.h +++ b/lib.h @@ -167,7 +167,7 @@ extern int dbg_entry; extern int dbg_dead; extern int fmem_report; -extern int fdump_linearize; +extern int fdump_ir; extern unsigned long long fmemcpy_max_count; extern unsigned long fpasses; diff --git a/linearize.c b/linearize.c index 5a2e8dfa..c2243645 100644 --- a/linearize.c +++ b/linearize.c @@ -2220,7 +2220,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t add_one_insn(ep, insn); } - if (fdump_linearize) + if (fdump_ir) show_entry(ep); /* diff --git a/sparse.1 b/sparse.1 index bec8d6d7..810fb321 100644 --- a/sparse.1 +++ b/sparse.1 @@ -357,7 +357,7 @@ normalized GNU triplet. (e.g. i386-linux-gnu). . .SH DEBUG OPTIONS .TP -.B \-fdump-linearize[=only] +.B \-fdump-ir[=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. diff --git a/test-linearize.c b/test-linearize.c index 28452678..c7122080 100644 --- a/test-linearize.c +++ b/test-linearize.c @@ -47,7 +47,7 @@ static void clean_up_symbols(struct symbol_list *list) expand_symbol(sym); ep = linearize_symbol(sym); - if (fdump_linearize == 2) + if (fdump_ir == 2) continue; if (ep) show_entry(ep); diff --git a/test-unssa.c b/test-unssa.c index ec5c9301..e0981802 100644 --- a/test-unssa.c +++ b/test-unssa.c @@ -62,7 +62,7 @@ static int compile(struct symbol_list *list) struct entrypoint *ep; expand_symbol(sym); ep = linearize_symbol(sym); - if (fdump_linearize == 2) + if (fdump_ir == 2) continue; if (ep) output_fn(ep); diff --git a/validation/linear/bitfield-init-mask.c b/validation/linear/bitfield-init-mask.c index 94afa400..f4360585 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=only -Wno-decl $file * check-output-ignore * * check-output-contains: and\\..*fffff800\$ -- cgit 1.2.3-korg From ec09161825544d4111b2d833fa66b1288f39f19c Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 23 Aug 2017 13:53:48 +0200 Subject: dump-ir: make it more flexible Signed-off-by: Luc Van Oostenryck --- Documentation/options.md | 11 ++++++ lib.c | 70 ++++++++++++++++++++++++++++++---- lib.h | 2 +- linearize.c | 2 +- sparse.1 | 6 --- test-linearize.c | 2 +- test-unssa.c | 2 +- validation/linear/bitfield-init-mask.c | 2 +- 8 files changed, 78 insertions(+), 19 deletions(-) diff --git a/Documentation/options.md b/Documentation/options.md index 5677789e..14698a98 100644 --- a/Documentation/options.md +++ b/Documentation/options.md @@ -16,3 +16,14 @@ tools. The passes currently understood are: * 'mem2reg' * 'optim' + +### Internal Representation + +* '-fdump-ir[=\[,\...]]' + + Dump the IR at each of the given passes. + + The passes currently understood are: + * 'linearize' + * 'mem2reg' + * 'final' diff --git a/lib.c b/lib.c index 7d7a3647..369b21df 100644 --- a/lib.c +++ b/lib.c @@ -257,7 +257,7 @@ int dump_macro_defs = 0; int dbg_entry = 0; int dbg_dead = 0; -int fdump_ir; +unsigned long fdump_ir; int fmem_report = 0; unsigned long long fmemcpy_max_count = 100000; unsigned long fpasses = ~0UL; @@ -485,6 +485,57 @@ const char *match_option(const char *arg, const char *prefix) } +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; @@ -794,14 +845,15 @@ static int handle_fpasses(const char *arg, const char *opt, const struct flag *f static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options) { - if (*opt == '\0') - fdump_ir = 1; - else if (!strcmp(opt, "=only")) - fdump_ir = 2; - else - die("error: wrong option \"%s\"", arg); + static const struct mask_map dump_ir_options[] = { + { "", PASS_LINEARIZE }, + { "linearize", PASS_LINEARIZE }, + { "mem2reg", PASS_MEM2REG }, + { "final", PASS_FINAL }, + { }, + }; - return 1; + return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir); } static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options) @@ -1400,6 +1452,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)) { diff --git a/lib.h b/lib.h index bfcfd2a0..8d3c67a0 100644 --- a/lib.h +++ b/lib.h @@ -167,7 +167,7 @@ extern int dbg_entry; extern int dbg_dead; extern int fmem_report; -extern int fdump_ir; +extern unsigned long fdump_ir; extern unsigned long long fmemcpy_max_count; extern unsigned long fpasses; diff --git a/linearize.c b/linearize.c index c2243645..48db6784 100644 --- a/linearize.c +++ b/linearize.c @@ -2220,7 +2220,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t add_one_insn(ep, insn); } - if (fdump_ir) + if (fdump_ir & PASS_LINEARIZE) show_entry(ep); /* diff --git a/sparse.1 b/sparse.1 index 810fb321..377d1d3c 100644 --- a/sparse.1 +++ b/sparse.1 @@ -356,12 +356,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-ir[=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. . diff --git a/test-linearize.c b/test-linearize.c index c7122080..e6d1ee3c 100644 --- a/test-linearize.c +++ b/test-linearize.c @@ -47,7 +47,7 @@ static void clean_up_symbols(struct symbol_list *list) expand_symbol(sym); ep = linearize_symbol(sym); - if (fdump_ir == 2) + if (!(fdump_ir & PASS_FINAL)) continue; if (ep) show_entry(ep); diff --git a/test-unssa.c b/test-unssa.c index e0981802..80752f43 100644 --- a/test-unssa.c +++ b/test-unssa.c @@ -62,7 +62,7 @@ static int compile(struct symbol_list *list) struct entrypoint *ep; expand_symbol(sym); ep = linearize_symbol(sym); - if (fdump_ir == 2) + if (!(fdump_ir & PASS_FINAL)) continue; if (ep) output_fn(ep); diff --git a/validation/linear/bitfield-init-mask.c b/validation/linear/bitfield-init-mask.c index f4360585..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-ir=only -Wno-decl $file + * check-command: test-linearize -fdump-ir=linearize -Wno-decl $file * check-output-ignore * * check-output-contains: and\\..*fffff800\$ -- cgit 1.2.3-korg From 555217d63d01f31d6322d475e33b5912a5926169 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Fri, 15 Sep 2017 12:30:55 +0200 Subject: dump-ir: activate -fdump-ir=mem2reg Signed-off-by: Luc Van Oostenryck --- linearize.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linearize.c b/linearize.c index 48db6784..9a92291f 100644 --- a/linearize.c +++ b/linearize.c @@ -2234,6 +2234,8 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t */ if (fpasses & PASS_MEM2REG) simplify_symbol_usage(ep); + if (fdump_ir & PASS_MEM2REG) + show_entry(ep); if (!(fpasses & PASS_OPTIM)) return ep; -- cgit 1.2.3-korg