From c0e7c6a56be633bd4f9b3ccbc69a956260c8505d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Apr 2018 12:26:34 +0300 Subject: [PATCH] flow/math: handle __builtin_choose_expr() The new kernel min/max() macros use __builtin_choose_expr() so this is necessary if we don't want to say that min/max just always returns unknown values. Signed-off-by: Dan Carpenter --- smatch_flow.c | 23 +++++++++++++++++++++++ smatch_math.c | 19 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/smatch_flow.c b/smatch_flow.c index 840e12fd..0611a6df 100644 --- a/smatch_flow.c +++ b/smatch_flow.c @@ -286,6 +286,27 @@ next: } while (1); } +static int handle__builtin_choose_expr(struct expression *expr) +{ + struct expression *const_expr, *expr1, *expr2; + sval_t sval; + + if (!sym_name_is("__builtin_choose_expr", expr->fn)) + return 0; + + const_expr = get_argument_from_call_expr(expr->args, 0); + expr1 = get_argument_from_call_expr(expr->args, 1); + expr2 = get_argument_from_call_expr(expr->args, 2); + + if (!get_value(const_expr, &sval) || !expr1 || !expr2) + return 0; + if (sval.value) + __split_expr(expr1); + else + __split_expr(expr2); + return 1; +} + void __split_expr(struct expression *expr) { if (!expr) @@ -449,6 +470,8 @@ void __split_expr(struct expression *expr) if (sym_name_is("__builtin_constant_p", expr->fn)) break; + if (handle__builtin_choose_expr(expr)) + break; split_expr_list(expr->args, expr); __split_expr(expr->fn); if (is_inline_func(expr->fn)) diff --git a/smatch_math.c b/smatch_math.c index 6aec0100..bedc3377 100644 --- a/smatch_math.c +++ b/smatch_math.c @@ -1044,6 +1044,22 @@ static struct range_list *handle_builtin_constant_p(struct expression *expr, int return rl_zero(); } +static struct range_list *handle__builtin_choose_expr(struct expression *expr, int implied, int *recurse_cnt) +{ + struct expression *const_expr, *expr1, *expr2; + sval_t sval; + + const_expr = get_argument_from_call_expr(expr->args, 0); + expr1 = get_argument_from_call_expr(expr->args, 1); + expr2 = get_argument_from_call_expr(expr->args, 2); + + if (!get_value(const_expr, &sval) || !expr1 || !expr2) + return NULL; + if (sval.value) + return _get_rl(expr1, implied, recurse_cnt); + return _get_rl(expr2, implied, recurse_cnt); +} + static struct range_list *handle_call_rl(struct expression *expr, int implied, int *recurse_cnt) { struct range_list *rl; @@ -1051,6 +1067,9 @@ static struct range_list *handle_call_rl(struct expression *expr, int implied, i if (sym_name_is("__builtin_constant_p", expr->fn)) return handle_builtin_constant_p(expr, implied, recurse_cnt); + if (sym_name_is("__builtin_choose_expr", expr->fn)) + return handle__builtin_choose_expr(expr, implied, recurse_cnt); + if (sym_name_is("__builtin_expect", expr->fn) || sym_name_is("__builtin_bswap16", expr->fn) || sym_name_is("__builtin_bswap32", expr->fn) || -- 2.11.4.GIT