Compare instructions with both operands sign or zero-extended from the same original size are equivalent to a compare of the original values. If the values were zero-extended, a signed compare becomes an unsigned one. Simplify away the sign/zero-extensions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> --- simplify.c | 52 ++++++++++++++++++++++++++------ validation/optim/cmp-sext-sext.c | 1 - validation/optim/cmp-zext-zext.c | 1 - 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/simplify.c b/simplify.c index 7538c9393b41..d56d4c89a078 100644 --- a/simplify.c +++ b/simplify.c @@ -422,6 +422,22 @@ static inline bool is_signed_constant(long long val, unsigned osize, unsigned ns return bits_extend(val, osize, 1) == bits_extend(val, nsize, 1); } +/// +// is @src generated by an instruction with the given opcode and size? +static inline pseudo_t is_same_op(pseudo_t src, int op, unsigned osize) +{ + struct instruction *def; + + if (src->type != PSEUDO_REG) + return NULL; + def = src->def; + if (def->opcode != op) + return NULL; + if (def->orig_type->bit_size != osize) + return NULL; + return def->src; +} + /// // replace the operand of an instruction // @insn: the instruction @@ -1570,6 +1586,30 @@ static int simplify_sub(struct instruction *insn) return 0; } +static int simplify_compare(struct instruction *insn) +{ + pseudo_t src1 = insn->src1; + pseudo_t src2 = insn->src2; + struct instruction *def; + unsigned int osize; + pseudo_t src; + + switch (DEF_OPCODE(def, src1)) { + case OP_SEXT: case OP_ZEXT: + osize = def->orig_type->bit_size; + if ((src = is_same_op(src2, def->opcode, osize))) { + const struct opcode_table *op = &opcode_table[insn->opcode]; + if ((def->opcode == OP_ZEXT) && (op->flags & OPF_SIGNED)) + insn->opcode = op->sign; + insn->itype = def->orig_type; + replace_pseudo(insn, &insn->src1, def->src); + return replace_pseudo(insn, &insn->src2, src); + } + break; + } + return 0; +} + static int simplify_constant_unop(struct instruction *insn) { long long val = insn->src1->value; @@ -2083,17 +2123,9 @@ int simplify_instruction(struct instruction *insn) case OP_DIVS: case OP_MODU: case OP_MODS: - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: break; + case OP_BINCMP ... OP_BINCMP_END: + return simplify_compare(insn); case OP_LOAD: case OP_STORE: return simplify_memop(insn); diff --git a/validation/optim/cmp-sext-sext.c b/validation/optim/cmp-sext-sext.c index ba6ed54e940c..3bd22fb738ca 100644 --- a/validation/optim/cmp-sext-sext.c +++ b/validation/optim/cmp-sext-sext.c @@ -11,7 +11,6 @@ _Bool cmpu_sext_sext(ARGS(INT32)) { return TEST(UINT64, UINT32, a, < , b); } /* * check-name: cmp-sext-sext * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-ignore * check-output-returns: 1 diff --git a/validation/optim/cmp-zext-zext.c b/validation/optim/cmp-zext-zext.c index 9f188297e214..88f9078f9480 100644 --- a/validation/optim/cmp-zext-zext.c +++ b/validation/optim/cmp-zext-zext.c @@ -11,7 +11,6 @@ _Bool cmpu_zext_zext(ARGS(UINT32)) { return TEST(UINT64, UINT32, a, < , b); } /* * check-name: cmp-zext-zext * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-ignore * check-output-returns: 1 -- 2.29.2