On Sat, Jan 22, 2022 at 01:47:08AM +0100, Jakub Jelinek via Gcc-patches wrote: > I think with the 2) patch I achieve what we want for Fortran, for 1) > the only behavior from gcc 11 is that > -fsanitize-coverage=trace-cmp,trace-cmp is now rejected. > This is mainly from the desire to disallow > -fconvert=big-endian,little-endian or -Wbidi-chars=bidirectional,any > etc. where it would be confusing to users what exactly it means. > But it is the only from these options that actually acts as an Enum > bit set, each enumerator can be specified with all the others. > So one option would be stop requiring the EnumSet implies Set properties > must be specified and just require that either they are specified on all > EnumValues, or on none of them; the latter case would be for > -fsanitize-coverage= and the non-Set case would mean that all the > EnumValues need to have disjoint Value bitmasks and that they can > be all specified and unlike the Set case also repeated. > Thoughts on this?
Here is an incremental patch to the first two patches of the series that implements EnumBitSet that fully restores the -fsanitize-coverage GCC 11 behavior. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2022-01-24 Jakub Jelinek <ja...@redhat.com> PR sanitizer/104158 * opt-functions.awk (var_set): Handle EnumBitSet property. * optc-gen.awk: Don't disallow RejectNegative if EnumBitSet is specified. * opts.h (enum cl_enum_var_value): New type. * opts-common.cc (decode_cmdline_option): Use CLEV_* values. Handle CLEV_BITSET. (cmdline_handle_error): Handle CLEV_BITSET. * opts.cc (test_enum_sets): Also test EnumBitSet requirements. * doc/options.texi (EnumBitSet): Document. * common.opt (fsanitize-coverage=): Use EnumBitSet instead of EnumSet. (trace-pc, trace-cmp): Drop Set properties. * gcc.dg/sancov/pr104158-7.c: Adjust for repeating of arguments being allowed. --- gcc/opt-functions.awk.jj 2022-01-23 17:25:21.166588518 +0100 +++ gcc/opt-functions.awk 2022-01-23 17:30:17.989443241 +0100 @@ -298,9 +298,11 @@ function var_set(flags) if (flag_set_p("Enum.*", flags)) { en = opt_args("Enum", flags); if (flag_set_p("EnumSet", flags)) - return enum_index[en] ", CLVC_ENUM, 1" + return enum_index[en] ", CLVC_ENUM, CLEV_SET" + else if (flag_set_p("EnumBitSet", flags)) + return enum_index[en] ", CLVC_ENUM, CLEV_BITSET" else - return enum_index[en] ", CLVC_ENUM, 0" + return enum_index[en] ", CLVC_ENUM, CLEV_NORMAL" } if (var_type(flags) == "const char *") return "0, CLVC_STRING, 0" --- gcc/optc-gen.awk.jj 2022-01-23 17:25:21.000000000 +0100 +++ gcc/optc-gen.awk 2022-01-23 17:26:38.920502407 +0100 @@ -349,6 +349,7 @@ for (i = 0; i < n_opts; i++) { if (flag_set_p("Enum.*", flags[i])) { if (!flag_set_p("RejectNegative", flags[i]) \ && !flag_set_p("EnumSet", flags[i]) \ + && !flag_set_p("EnumBitSet", flags[i]) \ && opts[i] ~ "^[Wfgm]") print "#error Enum allowing negative form" } --- gcc/opts.h.jj 2022-01-23 17:25:21.167588504 +0100 +++ gcc/opts.h 2022-01-23 17:30:00.469687787 +0100 @@ -52,6 +52,18 @@ enum cl_var_type { CLVC_DEFER }; +/* Values for var_value member of CLVC_ENUM. */ +enum cl_enum_var_value { + /* Enum without EnumSet or EnumBitSet. */ + CLEV_NORMAL, + + /* EnumSet. */ + CLEV_SET, + + /* EnumBitSet. */ + CLEV_BITSET +}; + struct cl_option { /* Text of the option, including initial '-'. */ --- gcc/opts-common.cc.jj 2022-01-23 17:25:21.169588477 +0100 +++ gcc/opts-common.cc 2022-01-23 17:38:00.508987332 +0100 @@ -811,8 +811,8 @@ decode_cmdline_option (const char *const { const struct cl_enum *e = &cl_enums[option->var_enum]; - gcc_assert (option->var_value || value == 1); - if (option->var_value) + gcc_assert (option->var_value != CLEV_NORMAL || value == 1); + if (option->var_value != CLEV_NORMAL) { const char *p = arg; HOST_WIDE_INT sum_value = 0; @@ -834,19 +834,30 @@ decode_cmdline_option (const char *const break; } - unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT; - gcc_checking_assert (set >= 1 && set <= HOST_BITS_PER_WIDE_INT); - if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0) + HOST_WIDE_INT this_mask = 0; + if (option->var_value == CLEV_SET) { - errors |= CL_ERR_ENUM_SET_ARG; - break; + unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT; + gcc_checking_assert (set >= 1 + && set <= HOST_BITS_PER_WIDE_INT); + if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0) + { + errors |= CL_ERR_ENUM_SET_ARG; + break; + } + used_sets |= HOST_WIDE_INT_1U << (set - 1); + + for (int i = 0; e->values[i].arg != NULL; i++) + if (set == (e->values[i].flags >> CL_ENUM_SET_SHIFT)) + this_mask |= e->values[i].value; + } + else + { + gcc_assert (option->var_value == CLEV_BITSET + && ((e->values[idx].flags >> CL_ENUM_SET_SHIFT) + == 0)); + this_mask = this_value; } - used_sets |= HOST_WIDE_INT_1U << (set - 1); - - HOST_WIDE_INT this_mask = 0; - for (int i = 0; e->values[i].arg != NULL; i++) - if (set == (e->values[i].flags >> CL_ENUM_SET_SHIFT)) - this_mask |= e->values[i].value; sum_value |= this_value; mask |= this_mask; @@ -1430,6 +1441,14 @@ cmdline_handle_error (location_t loc, co break; } + if (option->var_value == CLEV_BITSET) + { + if (q == NULL) + break; + p = q + 1; + continue; + } + unsigned set = e->values[idx].flags >> CL_ENUM_SET_SHIFT; gcc_checking_assert (set >= 1 && set <= HOST_BITS_PER_WIDE_INT); if ((used_sets & (HOST_WIDE_INT_1U << (set - 1))) != 0) --- gcc/opts.cc.jj 2022-01-23 17:25:25.554527225 +0100 +++ gcc/opts.cc 2022-01-23 17:48:55.505842425 +0100 @@ -3705,13 +3705,14 @@ test_get_option_html_page () #endif } -/* Verify EnumSet requirements. */ +/* Verify EnumSet and EnumBitSet requirements. */ static void test_enum_sets () { for (unsigned i = 0; i < cl_options_count; ++i) - if (cl_options[i].var_type == CLVC_ENUM && cl_options[i].var_value) + if (cl_options[i].var_type == CLVC_ENUM + && cl_options[i].var_value != CLEV_NORMAL) { const struct cl_enum *e = &cl_enums[cl_options[i].var_enum]; unsigned HOST_WIDE_INT used_sets = 0; @@ -3720,12 +3721,22 @@ test_enum_sets () for (unsigned j = 0; e->values[j].arg; ++j) { unsigned set = e->values[j].flags >> CL_ENUM_SET_SHIFT; + if (cl_options[i].var_value == CLEV_BITSET) + { + /* For EnumBitSet Set shouldn't be used and Value should + be a power of two. */ + ASSERT_TRUE (set == 0); + ASSERT_TRUE (pow2p_hwi (e->values[j].value)); + continue; + } /* Test that enumerators referenced in EnumSet have all Set(n) on them within the valid range. */ ASSERT_TRUE (set >= 1 && set <= HOST_BITS_PER_WIDE_INT); highest_set = MAX (set, highest_set); used_sets |= HOST_WIDE_INT_1U << (set - 1); } + if (cl_options[i].var_value == CLEV_BITSET) + continue; /* If there is just one set, no point to using EnumSet. */ ASSERT_TRUE (highest_set >= 2); /* Test that there are no gaps in between the sets. */ --- gcc/doc/options.texi.jj 2022-01-23 17:25:21.169588477 +0100 +++ gcc/doc/options.texi 2022-01-23 17:52:19.005999122 +0100 @@ -421,6 +421,14 @@ enumeration values with the same set bit Or option's argument can be a comma separated list of strings where each string is from a different @code{Set(@var{number})}. +@item EnumBitSet +Must be used together with the @code{Enum(@var{name})} property. +Similar to @samp{EnumBitSet}, but corresponding @samp{Enum} record must +not use @code{Set} properties, each @code{EnumValue} should have +@code{Value} that is a power of 2, each value is treated as its own +set and its value as the set's mask, so there are no mutually +exclusive arguments. + @item Defer The option should be stored in a vector, specified with @code{Var}, for later processing. --- gcc/common.opt.jj 2022-01-23 17:25:25.553527239 +0100 +++ gcc/common.opt 2022-01-23 17:26:11.640883463 +0100 @@ -1072,17 +1072,17 @@ Common Driver Joined Select what to sanitize. fsanitize-coverage= -Common Joined Enum(sanitize_coverage) Var(flag_sanitize_coverage) EnumSet +Common Joined Enum(sanitize_coverage) Var(flag_sanitize_coverage) EnumBitSet Select type of coverage sanitization. Enum Name(sanitize_coverage) Type(int) EnumValue -Enum(sanitize_coverage) String(trace-pc) Value(SANITIZE_COV_TRACE_PC) Set(1) +Enum(sanitize_coverage) String(trace-pc) Value(SANITIZE_COV_TRACE_PC) EnumValue -Enum(sanitize_coverage) String(trace-cmp) Value(SANITIZE_COV_TRACE_CMP) Set(2) +Enum(sanitize_coverage) String(trace-cmp) Value(SANITIZE_COV_TRACE_CMP) fasan-shadow-offset= Common Joined RejectNegative Var(common_deferred_options) Defer --- gcc/testsuite/gcc.dg/sancov/pr104158-7.c.jj 2022-01-23 17:56:44.179294117 +0100 +++ gcc/testsuite/gcc.dg/sancov/pr104158-7.c 2022-01-23 17:55:58.659930113 +0100 @@ -1,5 +1,11 @@ /* PR sanitizer/104158 */ /* { dg-do compile } */ /* { dg-options "-fsanitize-coverage=trace-cmp,trace-cmp -fdump-tree-optimized" } */ -/* { dg-error "invalid argument in option '-fsanitize-coverage=trace-cmp,trace-cmp'" "" { target *-*-* } 0 } */ -/* { dg-message "'trace-cmp' specified multiple times in the same option" "" { target *-*-* } 0 } */ +/* { dg-final { scan-tree-dump "__sanitizer_cov_trace_cmp" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "__sanitizer_cov_trace_pc" "optimized" } } */ + +int +foo (int a, int b) +{ + return a == b; +} Jakub