diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2019-10-03 01:31:41 +0200 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2019-10-03 20:44:06 +0200 |
commit | 3df9233e87de6ced200732c24f0783b409f9602e (patch) | |
tree | b2d4cd39cd56fdbbfc3ccc7670d8e8a0884e56b7 | |
parent | d466a02815b8109ea007736590bdd97f5d0aeb2f (diff) | |
download | sparse-3df9233e87de6ced200732c24f0783b409f9602e.tar.gz |
expand more builtins like __builtin_ffs()
GCC expands at compile time builtins like __builtin_ffs()
when their argument is constant.
A driver in the kernel uses such a builtin in a case statement,
causing sparse to report:
error: Expected constant expression in case statement
So, let sparse also expand such builtins, somehow like it was
done for bswap16/32/64 but now for ffs/ffsl/ffsll, clz, ctz,
clrsb, popcount & parity.
Reported-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Tested-by: Randy Dunlap <rdunlap@infradead.org>
-rw-r--r-- | builtin.c | 56 |
1 files changed, 56 insertions, 0 deletions
@@ -230,6 +230,44 @@ static struct symbol_op bswap_op = { }; +#define EXPAND_FINDBIT(name) \ +static int expand_##name(struct expression *expr, int cost) \ +{ \ + struct expression *arg; \ + long long val; \ + \ + if (cost) \ + return cost; \ + \ + arg = first_expression(expr->args); \ + val = get_expression_value_silent(arg); \ + switch (arg->ctype->bit_size) { \ + case sizeof(int) * 8: \ + val = __builtin_##name(val); break; \ + case sizeof(long long) * 8: \ + val = __builtin_##name##ll(val); break; \ + default: /* impossible error */ \ + return SIDE_EFFECTS; \ + } \ + \ + expr->value = val; \ + expr->type = EXPR_VALUE; \ + expr->taint = 0; \ + return 0; \ +} \ + \ +static struct symbol_op name##_op = { \ + .evaluate = evaluate_pure_unop, \ + .expand = expand_##name, \ +} + +EXPAND_FINDBIT(clz); +EXPAND_FINDBIT(ctz); +EXPAND_FINDBIT(clrsb); +EXPAND_FINDBIT(ffs); +EXPAND_FINDBIT(parity); +EXPAND_FINDBIT(popcount); + static int evaluate_fp_unop(struct expression *expr) { struct expression *arg; @@ -334,11 +372,29 @@ static struct sym_init { { "__builtin_bswap16", &builtin_fn_type, MOD_TOPLEVEL, &bswap_op }, { "__builtin_bswap32", &builtin_fn_type, MOD_TOPLEVEL, &bswap_op }, { "__builtin_bswap64", &builtin_fn_type, MOD_TOPLEVEL, &bswap_op }, + { "__builtin_clrsb", &builtin_fn_type, MOD_TOPLEVEL, &clrsb_op }, + { "__builtin_clrsbl", &builtin_fn_type, MOD_TOPLEVEL, &clrsb_op }, + { "__builtin_clrsbll", &builtin_fn_type, MOD_TOPLEVEL, &clrsb_op }, + { "__builtin_clz", &builtin_fn_type, MOD_TOPLEVEL, &clz_op }, + { "__builtin_clzl", &builtin_fn_type, MOD_TOPLEVEL, &clz_op }, + { "__builtin_clzll", &builtin_fn_type, MOD_TOPLEVEL, &clz_op }, + { "__builtin_ctz", &builtin_fn_type, MOD_TOPLEVEL, &ctz_op }, + { "__builtin_ctzl", &builtin_fn_type, MOD_TOPLEVEL, &ctz_op }, + { "__builtin_ctzll", &builtin_fn_type, MOD_TOPLEVEL, &ctz_op }, + { "__builtin_ffs", &builtin_fn_type, MOD_TOPLEVEL, &ffs_op }, + { "__builtin_ffsl", &builtin_fn_type, MOD_TOPLEVEL, &ffs_op }, + { "__builtin_ffsll", &builtin_fn_type, MOD_TOPLEVEL, &ffs_op }, { "__builtin_isfinite", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_isinf", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_isinf_sign", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_isnan", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_isnormal", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, + { "__builtin_parity", &builtin_fn_type, MOD_TOPLEVEL, &parity_op }, + { "__builtin_parityl", &builtin_fn_type, MOD_TOPLEVEL, &parity_op }, + { "__builtin_parityll", &builtin_fn_type, MOD_TOPLEVEL, &parity_op }, + { "__builtin_popcount", &builtin_fn_type, MOD_TOPLEVEL, &popcount_op }, + { "__builtin_popcountl", &builtin_fn_type, MOD_TOPLEVEL, &popcount_op }, + { "__builtin_popcountll", &builtin_fn_type, MOD_TOPLEVEL, &popcount_op }, { "__builtin_signbit", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_add_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, { "__builtin_sub_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, |