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@xxxxxxxxx> --- simplify.c | 35 ++++++++++++++++++++++++++++++++++- validation/optim/zext-and.c | 1 - validation/optim/zext-and1.c | 1 - 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/simplify.c b/simplify.c index a0f7aa327..b05124027 100644 --- a/simplify.c +++ b/simplify.c @@ -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 2f4f3c805..a3153bf78 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 2ad011034..c99a0e624 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 -- 2.18.0 -- To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html