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 | |
| 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>
| -rw-r--r-- | simplify.c | 35 | ||||
| -rw-r--r-- | validation/optim/zext-and.c | 1 | ||||
| -rw-r--r-- | validation/optim/zext-and1.c | 1 |
3 files changed, 34 insertions, 3 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: diff --git a/validation/optim/zext-and.c b/validation/optim/zext-and.c index 2f4f3c80..a3153bf7 100644 --- a/validation/optim/zext-and.c +++ b/validation/optim/zext-and.c @@ -6,7 +6,6 @@ unsigned int foo(unsigned char x) /* * check-name: zext-and * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-ignore * check-output-excludes: and\\. diff --git a/validation/optim/zext-and1.c b/validation/optim/zext-and1.c index 2ad01103..c99a0e62 100644 --- a/validation/optim/zext-and1.c +++ b/validation/optim/zext-and1.c @@ -6,7 +6,6 @@ unsigned int bar(unsigned char x) /* * check-name: zext-and1 * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-ignore * check-output-contains: and\\..*\\$1 |
