aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-10-26 07:07:06 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-11-08 02:14:10 +0100
commit36329f5318dc9a7017207e93445ac9100904183f (patch)
treeefbe4931961ea1b3dd238f03d9e56628883f8fd9
parent983964c2ff72392fb7a373990f55cfcb2ba832a0 (diff)
downloadsparse-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.c24
-rw-r--r--validation/optim/cmp-sext.c1
2 files changed, 24 insertions, 1 deletions
diff --git a/simplify.c b/simplify.c
index 2176f90d..eb2c724f 100644
--- a/simplify.c
+++ b/simplify.c
@@ -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