aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-22 18:34:14 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-07 21:06:16 -0700
commit378908b588e2266f3751165d28218607beaec2eb (patch)
tree3bc6b24e19d2ce28e97e416ba57ac183f4ff161c /simplify.c
parentSplit the binops where signedness matters into unsigned and signed. (diff)
downloadsparse-378908b588e2266f3751165d28218607beaec2eb.tar.gz
sparse-378908b588e2266f3751165d28218607beaec2eb.tar.bz2
sparse-378908b588e2266f3751165d28218607beaec2eb.zip
Make constant instruction simplification take the sign of the
instruction into account now that we have it.
Diffstat (limited to 'simplify.c')
-rw-r--r--simplify.c49
1 files changed, 29 insertions, 20 deletions
diff --git a/simplify.c b/simplify.c
index 87c467d..0d0f1b1 100644
--- a/simplify.c
+++ b/simplify.c
@@ -280,7 +280,18 @@ static int simplify_constant_binop(struct instruction *insn)
/* FIXME! Verify signs and sizes!! */
long long left = insn->src1->value;
long long right = insn->src2->value;
- long long res, mask;
+ unsigned long long ul, ur;
+ long long res, mask, bits;
+
+ mask = 1ULL << (insn->size-1);
+ bits = mask | (mask-1);
+
+ if (left & mask)
+ left |= ~bits;
+ if (right & mask)
+ right |= ~bits;
+ ul = left & bits;
+ ur = right & bits;
switch (insn->opcode) {
case OP_ADD:
@@ -290,30 +301,38 @@ static int simplify_constant_binop(struct instruction *insn)
res = left - right;
break;
case OP_MULU:
+ res = ul * ur;
+ break;
case OP_MULS:
- /* FIXME! Check sign! */
res = left * right;
break;
case OP_DIVU:
+ if (!ur)
+ return 0;
+ res = ul / ur;
+ break;
case OP_DIVS:
if (!right)
return 0;
- /* FIXME! Check sign! */
res = left / right;
break;
case OP_MODU:
+ if (!ur)
+ return 0;
+ res = ul % ur;
+ break;
case OP_MODS:
if (!right)
return 0;
- /* FIXME! Check sign! */
res = left % right;
break;
case OP_SHL:
res = left << right;
break;
case OP_LSR:
+ res = ul >> ur;
+ break;
case OP_ASR:
- /* FIXME! Check sign! */
res = left >> right;
break;
/* Logical */
@@ -341,44 +360,34 @@ static int simplify_constant_binop(struct instruction *insn)
res = left != right;
break;
case OP_SET_LE:
- /* FIXME! Check sign! */
res = left <= right;
break;
case OP_SET_GE:
- /* FIXME! Check sign! */
res = left >= right;
break;
case OP_SET_LT:
- /* FIXME! Check sign! */
res = left < right;
break;
case OP_SET_GT:
- /* FIXME! Check sign! */
res = left > right;
break;
case OP_SET_B:
- /* FIXME! Check sign! */
- res = (unsigned long long) left < (unsigned long long) right;
+ res = ul < ur;
break;
case OP_SET_A:
- /* FIXME! Check sign! */
- res = (unsigned long long) left > (unsigned long long) right;
+ res = ul > ur;
break;
case OP_SET_BE:
- /* FIXME! Check sign! */
- res = (unsigned long long) left <= (unsigned long long) right;
+ res = ul <= ur;
break;
case OP_SET_AE:
- /* FIXME! Check sign! */
- res = (unsigned long long) left >= (unsigned long long) right;
+ res = ul >= ur;
break;
default:
return 0;
}
- mask = 1ULL << (insn->size-1);
- res &= mask | (mask-1);
+ res &= bits;
- /* FIXME!! Sign??? */
replace_with_pseudo(insn, value_pseudo(res));
return REPEAT_CSE;
}