aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-04-24 14:47:04 -0700
committerJosh Triplett <josh@freedesktop.org>2008-04-24 19:27:57 -0700
commitf43b0e9a874c86eeeb9ea6af89e39bae20d96be2 (patch)
treeaf2b0c15f92c2de6d2a51e396cfc2b01956c0b7a /simplify.c
parentFix cast instruction generation (diff)
downloadsparse-f43b0e9a874c86eeeb9ea6af89e39bae20d96be2.tar.gz
sparse-f43b0e9a874c86eeeb9ea6af89e39bae20d96be2.tar.bz2
sparse-f43b0e9a874c86eeeb9ea6af89e39bae20d96be2.zip
Simplify (and warn about) right shifts that result in zero
..due to limited source sizes. Yeah, should do this for left shifts too. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'simplify.c')
-rw-r--r--simplify.c57
1 files changed, 56 insertions, 1 deletions
diff --git a/simplify.c b/simplify.c
index 94e14d2..8200584 100644
--- a/simplify.c
+++ b/simplify.c
@@ -256,6 +256,59 @@ static int replace_with_pseudo(struct instruction *insn, pseudo_t pseudo)
return REPEAT_CSE;
}
+static unsigned int value_size(long long value)
+{
+ value >>= 8;
+ if (!value)
+ return 8;
+ value >>= 8;
+ if (!value)
+ return 16;
+ value >>= 16;
+ if (!value)
+ return 32;
+ return 64;
+}
+
+/*
+ * Try to determine the maximum size of bits in a pseudo.
+ *
+ * Right now this only follow casts and constant values, but we
+ * could look at things like logical 'and' instructions etc.
+ */
+static unsigned int operand_size(struct instruction *insn, pseudo_t pseudo)
+{
+ unsigned int size = insn->size;
+
+ if (pseudo->type == PSEUDO_REG) {
+ struct instruction *src = pseudo->def;
+ if (src && src->opcode == OP_CAST && src->orig_type) {
+ unsigned int orig_size = src->orig_type->bit_size;
+ if (orig_size < size)
+ size = orig_size;
+ }
+ }
+ if (pseudo->type == PSEUDO_VAL) {
+ unsigned int orig_size = value_size(pseudo->value);
+ if (orig_size < size)
+ size = orig_size;
+ }
+ return size;
+}
+
+static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long value)
+{
+ unsigned int size = operand_size(insn, pseudo);
+
+ if (value >= size) {
+ warning(insn->pos, "right shift by bigger than source value");
+ return replace_with_pseudo(insn, value_pseudo(0));
+ }
+ if (!value)
+ return replace_with_pseudo(insn, pseudo);
+ return 0;
+}
+
static int simplify_constant_rightside(struct instruction *insn)
{
long long value = insn->src2->value;
@@ -272,10 +325,12 @@ static int simplify_constant_rightside(struct instruction *insn)
case OP_OR: case OP_XOR:
case OP_OR_BOOL:
case OP_SHL:
- case OP_LSR: case OP_ASR:
+ case OP_LSR:
if (!value)
return replace_with_pseudo(insn, insn->src1);
return 0;
+ case OP_ASR:
+ return simplify_asr(insn, insn->src1, value);
case OP_MULU: case OP_MULS:
case OP_AND_BOOL: