diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-10-26 07:07:06 +0100 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-11-08 02:14:10 +0100 |
commit | 36329f5318dc9a7017207e93445ac9100904183f (patch) | |
tree | efbe4931961ea1b3dd238f03d9e56628883f8fd9 | |
parent | 983964c2ff72392fb7a373990f55cfcb2ba832a0 (diff) | |
download | sparse-36329f5318dc9a7017207e93445ac9100904183f.tar.gz |
cmp: simplify sext(x) cmp C --> x cmp C
When doing a compare of a sign-extended value against a constant
the, sign-extension can be dropped and the comparison done on the
original type if the constant is within the original range.
Simplify away these sign-extensions.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r-- | simplify.c | 24 | ||||
-rw-r--r-- | validation/optim/cmp-sext.c | 1 |
2 files changed, 24 insertions, 1 deletions
@@ -416,6 +416,13 @@ static inline int constant(pseudo_t pseudo) } /// +// is this same signed value when interpreted with both size? +static inline bool is_signed_constant(long long val, unsigned osize, unsigned nsize) +{ + return bits_extend(val, osize, 1) == bits_extend(val, nsize, 1); +} + +/// // replace the operand of an instruction // @insn: the instruction // @pp: the address of the instruction's operand @@ -1082,6 +1089,9 @@ static int simplify_seteq_setne(struct instruction *insn, long long value) static int simplify_compare_constant(struct instruction *insn, long long value) { unsigned long long bits = bits_mask(insn->itype->bit_size); + struct instruction *def; + pseudo_t src1, src2; + unsigned int osize; int changed = 0; switch (insn->opcode) { @@ -1126,6 +1136,20 @@ static int simplify_compare_constant(struct instruction *insn, long long value) changed |= replace_binop_value(insn, OP_SET_LT, 0); break; } + + src1 = insn->src1; + src2 = insn->src2; + value = src2->value; + switch (DEF_OPCODE(def, src1)) { + case OP_SEXT: // sext(x) cmp C --> x cmp trunc(C) + osize = def->orig_type->bit_size; + if (is_signed_constant(value, osize, def->size)) { + insn->itype = def->orig_type; + insn->src2 = value_pseudo(zero_extend(value, osize)); + return replace_pseudo(insn, &insn->src1, def->src); + } + break; + } return changed; } diff --git a/validation/optim/cmp-sext.c b/validation/optim/cmp-sext.c index 2dd60fff..13f4fbdf 100644 --- a/validation/optim/cmp-sext.c +++ b/validation/optim/cmp-sext.c @@ -17,7 +17,6 @@ _Bool cmpgtu_sext(int a) { return (a >= 0x80000000ULL) == (a < 0); } /* * check-name: cmp-sext * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-ignore * check-output-returns: 1 |