mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-03 12:30:39 +08:00
options: Add EnumBitSet property support [PR104158]
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. 2022-01-24 Jakub Jelinek <jakub@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.
This commit is contained in:
parent
9acd5a0117
commit
0ebb09f5e4
@ -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
|
||||
|
@ -421,6 +421,14 @@ enumeration values with the same set bitwise ored together.
|
||||
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{EnumSet}, 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.
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -811,8 +811,8 @@ decode_cmdline_option (const char *const *argv, unsigned int lang_mask,
|
||||
{
|
||||
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 *argv, unsigned int lang_mask,
|
||||
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);
|
||||
|
||||
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;
|
||||
if (option->var_value == CLEV_SET)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
sum_value |= this_value;
|
||||
mask |= this_mask;
|
||||
@ -1430,6 +1441,14 @@ cmdline_handle_error (location_t loc, const struct cl_option *option,
|
||||
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)
|
||||
|
15
gcc/opts.cc
15
gcc/opts.cc
@ -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. */
|
||||
|
12
gcc/opts.h
12
gcc/opts.h
@ -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 '-'. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user