4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
26 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
28 struct smatch_state
*state
;
31 state
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
34 if (!estate_get_single_value(state
, &sval
))
37 if (!(sval
.uvalue
& (sval
.uvalue
- 1)))
42 static bool implied_power_of_two(struct expression
*expr
)
46 if (!get_implied_value(expr
, &sval
))
48 if (!(sval
.uvalue
& (sval
.uvalue
- 1)))
53 bool is_power_of_two(struct expression
*expr
)
55 expr
= strip_expr(expr
);
57 if (expr
->type
== EXPR_BINOP
&&
58 expr
->op
== SPECIAL_LEFTSHIFT
&&
59 is_power_of_two(expr
->left
))
62 if (implied_power_of_two(expr
))
65 if (get_state_expr(my_id
, expr
) == &power_of_two
)
71 static void set_power_of_two(struct expression
*expr
)
75 type
= get_type(expr
);
76 if (type_bits(type
) == 1)
79 set_state_expr(my_id
, expr
->left
, &power_of_two
);
82 static bool is_sign_expansion(struct expression
*expr
)
84 struct range_list
*rl
;
85 struct symbol
*type_left
;
86 struct symbol
*type_right
;
88 type_left
= get_type(expr
->left
);
89 type_right
= get_type(expr
->right
);
90 if (!type_left
|| !type_right
)
92 if (type_bits(type_left
) <= type_bits(type_right
))
95 get_absolute_rl(expr
->right
, &rl
);
96 if (sval_is_negative(rl_min(rl
)))
102 static void match_assign(struct expression
*expr
)
107 if (implied_power_of_two(expr
->right
)) {
108 if (get_state_expr(my_id
, expr
->left
))
109 set_state_expr(my_id
, expr
->left
, &power_of_two
);
113 if (is_sign_expansion(expr
))
116 if (is_power_of_two(expr
->right
))
117 set_power_of_two(expr
->left
);
120 static bool is_minus_mask(struct expression
*left
, struct expression
*right
)
122 if (right
->type
!= EXPR_BINOP
||
126 if (right
->right
->value
!= 1)
129 if (expr_equiv(left
, right
->left
))
135 static void match_condition(struct expression
*expr
)
137 expr
= strip_expr(expr
);
138 if (expr
->type
!= EXPR_BINOP
||
142 if (is_minus_mask(strip_expr(expr
->left
), strip_expr(expr
->right
))) {
143 set_true_false_states_expr(my_id
, expr
->left
, NULL
, &power_of_two
);
147 if (is_minus_mask(strip_expr(expr
->right
), strip_expr(expr
->left
))) {
148 set_true_false_states_expr(my_id
, expr
->right
, NULL
, &power_of_two
);
153 static void caller_info_callback(struct expression
*call
, int param
, char *printed_name
, struct sm_state
*sm
)
155 if (sm
->state
!= &power_of_two
)
158 sql_insert_caller_info(call
, POWER_OF_TWO
, param
, printed_name
, "");
161 static void set_power_of_two_name_sym(const char *name
, struct symbol
*sym
, char *value
)
163 set_state(my_id
, name
, sym
, &power_of_two
);
166 static void return_info_callback(int return_id
, char *return_ranges
,
167 struct expression
*returned_expr
,
169 const char *printed_name
,
172 struct smatch_state
*estate
;
175 if (sm
->state
!= &power_of_two
)
178 if (param
!= -1 && !param_was_set_var_sym(sm
->name
, sm
->sym
))
181 estate
= get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
182 if (estate_get_single_value(estate
, &sval
))
185 sql_insert_return_states(return_id
, return_ranges
, POWER_OF_TWO_SET
, param
, printed_name
, "");
188 static void returns_power_of_two_set(struct expression
*expr
, int param
, char *key
, char *value
)
193 name
= get_name_sym_from_param_key(expr
, param
, key
, &sym
);
196 set_state(my_id
, name
, sym
, &power_of_two
);
199 void register_power_of_two(int id
)
203 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
204 add_hook(&match_condition
, CONDITION_HOOK
);
205 add_unmatched_state_hook(my_id
, &unmatched_state
);
206 add_caller_info_callback(my_id
, caller_info_callback
);
207 select_caller_name_sym(set_power_of_two_name_sym
, POWER_OF_TWO
);
208 add_return_info_callback(my_id
, return_info_callback
);
209 select_return_states_hook(POWER_OF_TWO_SET
, &returns_power_of_two_set
);