aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/simplify.c
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-03-12 01:06:54 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-03-12 01:09:54 +0100
commitc089cd2dc771e5bf175a390966e454df3334955d (patch)
tree826abdf09752fd0c2bcbb7f9b2c2b26010e8656d /simplify.c
parentd549d4d55eecb394e3f69314287f91e85b19e3e3 (diff)
parenteb4cdd21b7d0cedbbeff7f70e24473706ccce5a6 (diff)
downloadsparse-dev-c089cd2dc771e5bf175a390966e454df3334955d.tar.gz
Merge branches 'fix-ssa' and 'cmp-and-or' into next
* fix SSA conversion of mismatched memops * simplify CMP(AND(x,M), C) and CMP(OR(x,M), C)
Diffstat (limited to 'simplify.c')
-rw-r--r--simplify.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/simplify.c b/simplify.c
index 207af8ed..9e3514d8 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1258,6 +1258,104 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
src2 = insn->src2;
value = src2->value;
switch (DEF_OPCODE(def, src1)) {
+ case OP_AND:
+ if (!constant(def->src2))
+ break;
+ bits = def->src2->value;
+ switch (insn->opcode) {
+ case OP_SET_EQ:
+ if ((value & bits) != value)
+ return replace_with_value(insn, 0);
+ break;
+ case OP_SET_NE:
+ if ((value & bits) != value)
+ return replace_with_value(insn, 1);
+ break;
+ case OP_SET_LE:
+ value = sign_extend(value, def->size);
+ if (bits & sign_bit(def->size))
+ break;
+ if (value < 0)
+ return replace_with_value(insn, 0);
+ if (value >= (long long)bits)
+ return replace_with_value(insn, 1);
+ if (value == 0)
+ return replace_opcode(insn, OP_SET_EQ);
+ break;
+ case OP_SET_GT:
+ value = sign_extend(value, def->size);
+ if (bits & sign_bit(def->size))
+ break;
+ if (value < 0)
+ return replace_with_value(insn, 1);
+ if (value >= (long long)bits)
+ return replace_with_value(insn, 0);
+ if (value == 0)
+ return replace_opcode(insn, OP_SET_NE);
+ break;
+ case OP_SET_B:
+ if (value > bits)
+ return replace_with_value(insn, 1);
+ break;
+ case OP_SET_BE:
+ if (value >= bits)
+ return replace_with_value(insn, 1);
+ break;
+ case OP_SET_AE:
+ if (value > bits)
+ return replace_with_value(insn, 0);
+ break;
+ case OP_SET_A:
+ if (value >= bits)
+ return replace_with_value(insn, 0);
+ break;
+ }
+ break;
+ case OP_OR:
+ if (!constant(def->src2))
+ break;
+ bits = def->src2->value;
+ switch (insn->opcode) {
+ case OP_SET_EQ:
+ if ((value & bits) != bits)
+ return replace_with_value(insn, 0);
+ break;
+ case OP_SET_NE:
+ if ((value & bits) != bits)
+ return replace_with_value(insn, 1);
+ break;
+ case OP_SET_B:
+ if (bits >= value)
+ return replace_with_value(insn, 0);
+ break;
+ case OP_SET_BE:
+ if (bits > value)
+ return replace_with_value(insn, 0);
+ break;
+ case OP_SET_AE:
+ if (bits > value)
+ return replace_with_value(insn, 1);
+ break;
+ case OP_SET_A:
+ if (bits >= value)
+ return replace_with_value(insn, 1);
+ break;
+ case OP_SET_LE:
+ value = sign_extend(value, def->size);
+ if (bits & sign_bit(def->size)) {
+ if (value >= -1)
+ return replace_with_value(insn, 1);
+ }
+ break;
+ case OP_SET_GT:
+ value = sign_extend(value, def->size);
+ if (bits & sign_bit(def->size)) {
+ if (value >= -1)
+ return replace_with_value(insn, 0);
+ }
+ break;
+ }
+ break;
case OP_SEXT: // sext(x) cmp C --> x cmp trunc(C)
osize = def->orig_type->bit_size;
if (is_signed_constant(value, osize, size)) {