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:16:26 +0100 |
commit | c60237251a55984b1fcf6302d25650d35533dc2a (patch) | |
tree | bc676ac80d7b0716b95fb63d7d8ea06f351cc182 | |
parent | cae6fa2f2d5a99927c26f063d10b6ecfeb81b403 (diff) | |
download | sparse-c60237251a55984b1fcf6302d25650d35533dc2a.tar.gz |
cmp: simplify compares and sign/zero extend
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@gmail.com>
-rw-r--r-- | simplify.c | 52 | ||||
-rw-r--r-- | validation/optim/cmp-sext-sext.c | 1 | ||||
-rw-r--r-- | validation/optim/cmp-zext-zext.c | 1 |
3 files changed, 42 insertions, 12 deletions
@@ -423,6 +423,22 @@ static inline bool is_signed_constant(long long val, unsigned osize, unsigned ns } /// +// 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 // @pp: the address of the instruction's operand @@ -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 ba6ed54e..3bd22fb7 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 9f188297..88f9078f 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 |