diff mbox series

expand more builtins like __builtin_ffs()

Message ID 20191003001437.76038-1-luc.vanoostenryck@gmail.com (mailing list archive)
State Mainlined, archived
Headers show
Series expand more builtins like __builtin_ffs() | expand

Commit Message

Luc Van Oostenryck Oct. 3, 2019, 12:14 a.m. UTC
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>
---
 builtin.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

Comments

Randy Dunlap Oct. 3, 2019, 1:38 a.m. UTC | #1
On 10/2/19 5:14 PM, Luc Van Oostenryck wrote:
> 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>

Thanks.

> ---
>  builtin.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
> 
> diff --git a/builtin.c b/builtin.c
> index 221c98991..3e2d77e75 100644
> --- a/builtin.c
> +++ b/builtin.c
> @@ -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 (expr->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 },
>
diff mbox series

Patch

diff --git a/builtin.c b/builtin.c
index 221c98991..3e2d77e75 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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 (expr->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 },