diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2017-08-07 00:53:06 +0200 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-07-23 13:11:20 +0200 |
| commit | 5da4e09b47011d11c3ed8e1915a316ec8cf8897f (patch) | |
| tree | fb29fb9bb7eb0420038ee034e382919bce78c5df /simplify.c | |
| parent | 780d796a478f686379489fc2e02f932e7dcd67e9 (diff) | |
| download | sparse-dev-5da4e09b47011d11c3ed8e1915a316ec8cf8897f.tar.gz | |
cast: simplify AND(ZEXT(x,M),N)
An OP_AND with a constant value following a OP_ZEXT can often
be simplified:
* the constant mask can be made smaller
* the whole masking is redundant and can be removed.
Do these two simplifications depending on the initial mask
and the sizes of the instructions.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'simplify.c')
| -rw-r--r-- | simplify.c | 35 |
1 files changed, 34 insertions, 1 deletions
@@ -378,6 +378,13 @@ static inline int def_opcode(pseudo_t p) return p->def->opcode; } +// +// return the opcode of the instruction defining ``SRC`` if existing +// and OP_BADOP if not. It also assigns the defining instruction +// to ``DEF``. +#define DEF_OPCODE(DEF, SRC) \ + (((SRC)->type == PSEUDO_REG && (DEF = (SRC)->def)) ? DEF->opcode : OP_BADOP) + static unsigned int value_size(long long value) { value >>= 8; @@ -644,6 +651,32 @@ static int simplify_seteq_setne(struct instruction *insn, long long value) return 0; } +static int simplify_constant_mask(struct instruction *insn, unsigned long long mask) +{ + pseudo_t old = insn->src1; + unsigned long long omask; + unsigned long long nmask; + struct instruction *def; + int osize; + + switch (DEF_OPCODE(def, old)) { + case OP_ZEXT: + osize = def->orig_type->bit_size; + omask = (1ULL << osize) - 1; + nmask = mask & omask; + if (nmask == omask) + // the AND mask is redundant + return replace_with_pseudo(insn, old); + if (nmask != mask) { + // can use a smaller mask + insn->src2 = value_pseudo(nmask); + return REPEAT_CSE; + } + break; + } + return 0; +} + static int simplify_constant_rightside(struct instruction *insn) { long long value = insn->src2->value; @@ -694,7 +727,7 @@ static int simplify_constant_rightside(struct instruction *insn) return replace_with_pseudo(insn, insn->src2); if ((value & bits) == bits) return replace_with_pseudo(insn, insn->src1); - return 0; + return simplify_constant_mask(insn, value); case OP_SET_NE: case OP_SET_EQ: |
