11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * Copyright (C) 2012 Oracle.
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * This program is free software; you can redistribute it and/or
51f5207b7SJohn Levon  * modify it under the terms of the GNU General Public License
61f5207b7SJohn Levon  * as published by the Free Software Foundation; either version 2
71f5207b7SJohn Levon  * of the License, or (at your option) any later version.
81f5207b7SJohn Levon  *
91f5207b7SJohn Levon  * This program is distributed in the hope that it will be useful,
101f5207b7SJohn Levon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
111f5207b7SJohn Levon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
121f5207b7SJohn Levon  * GNU General Public License for more details.
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * You should have received a copy of the GNU General Public License
151f5207b7SJohn Levon  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
161f5207b7SJohn Levon  */
171f5207b7SJohn Levon 
181f5207b7SJohn Levon #include "smatch.h"
19*efe51d0cSJohn Levon #include "smatch_extra.h"
201f5207b7SJohn Levon 
211f5207b7SJohn Levon static int my_id;
221f5207b7SJohn Levon 
match_shift_mask(struct expression * expr)23*efe51d0cSJohn Levon static void match_shift_mask(struct expression *expr)
24*efe51d0cSJohn Levon {
25*efe51d0cSJohn Levon 	struct expression *right, *shifter;
26*efe51d0cSJohn Levon 	struct range_list *rl;
27*efe51d0cSJohn Levon 	char *str;
28*efe51d0cSJohn Levon 
29*efe51d0cSJohn Levon 	expr = strip_expr(expr);
30*efe51d0cSJohn Levon 	if (expr->type != EXPR_BINOP || expr->op != '&')
31*efe51d0cSJohn Levon 		return;
32*efe51d0cSJohn Levon 
33*efe51d0cSJohn Levon 	if (get_type(expr->left) != &ullong_ctype)
34*efe51d0cSJohn Levon 		return;
35*efe51d0cSJohn Levon 
36*efe51d0cSJohn Levon 	if (type_bits(get_type(expr->right)) == 64)
37*efe51d0cSJohn Levon 		return;
38*efe51d0cSJohn Levon 
39*efe51d0cSJohn Levon 	right = strip_expr(expr->right);
40*efe51d0cSJohn Levon 	if (right->type != EXPR_BINOP || right->op != SPECIAL_LEFTSHIFT)
41*efe51d0cSJohn Levon 		return;
42*efe51d0cSJohn Levon 
43*efe51d0cSJohn Levon 	shifter = strip_expr(right->right);
44*efe51d0cSJohn Levon 	get_real_absolute_rl(shifter, &rl);
45*efe51d0cSJohn Levon 	if (rl_max(rl).uvalue < 32)
46*efe51d0cSJohn Levon 		return;
47*efe51d0cSJohn Levon 
48*efe51d0cSJohn Levon 	str = expr_to_str(expr->right);
49*efe51d0cSJohn Levon 	sm_warning("should '%s' be a 64 bit type?", str);
50*efe51d0cSJohn Levon 	free_string(str);
51*efe51d0cSJohn Levon }
52*efe51d0cSJohn Levon 
match_shift_assignment(struct expression * expr)531f5207b7SJohn Levon static void match_shift_assignment(struct expression *expr)
541f5207b7SJohn Levon {
551f5207b7SJohn Levon 	struct symbol *left_type, *right_type;
561f5207b7SJohn Levon 	struct expression *right;
571f5207b7SJohn Levon 	sval_t sval;
581f5207b7SJohn Levon 	sval_t bits, shifter;
591f5207b7SJohn Levon 	char *name;
601f5207b7SJohn Levon 
611f5207b7SJohn Levon 	right = strip_expr(expr->right);
621f5207b7SJohn Levon 	if (right->type != EXPR_BINOP || right->op != SPECIAL_LEFTSHIFT)
631f5207b7SJohn Levon 		return;
641f5207b7SJohn Levon 
651f5207b7SJohn Levon 	left_type = get_type(expr->left);
661f5207b7SJohn Levon 	if (left_type != &llong_ctype && left_type != &ullong_ctype)
671f5207b7SJohn Levon 		return;
681f5207b7SJohn Levon 
691f5207b7SJohn Levon 	right_type = get_type(expr->right);
701f5207b7SJohn Levon 
711f5207b7SJohn Levon 	if (type_bits(right_type) == 64)
721f5207b7SJohn Levon 		return;
731f5207b7SJohn Levon 
741f5207b7SJohn Levon 	if (get_value(right, &sval))
751f5207b7SJohn Levon 		return;
761f5207b7SJohn Levon 
771f5207b7SJohn Levon 	get_absolute_max(right->left, &bits);
781f5207b7SJohn Levon 	get_absolute_max(right->right, &shifter);
791f5207b7SJohn Levon 
801f5207b7SJohn Levon 	bits = sval_cast(&ullong_ctype, bits);
811f5207b7SJohn Levon 	if (sval_cmp_val(shifter, 32) < 0) {
821f5207b7SJohn Levon 		sval = sval_binop(bits, SPECIAL_LEFTSHIFT, shifter);
831f5207b7SJohn Levon 		if (sval_cmp_val(sval, UINT_MAX) < 0)
841f5207b7SJohn Levon 			return;
851f5207b7SJohn Levon 	}
861f5207b7SJohn Levon 
871f5207b7SJohn Levon 	name = expr_to_str_sym(right, NULL);
881f5207b7SJohn Levon 	sm_warning("should '%s' be a 64 bit type?", name);
891f5207b7SJohn Levon 	free_string(name);
901f5207b7SJohn Levon }
911f5207b7SJohn Levon 
check_64bit_shift(int id)921f5207b7SJohn Levon void check_64bit_shift(int id)
931f5207b7SJohn Levon {
941f5207b7SJohn Levon 	my_id = id;
951f5207b7SJohn Levon 
961f5207b7SJohn Levon 	add_hook(&match_shift_assignment, ASSIGNMENT_HOOK);
97*efe51d0cSJohn Levon 	add_hook(&match_shift_mask, BINOP_HOOK);
981f5207b7SJohn Levon }
99