aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-08-07 00:53:06 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-07-23 13:11:20 +0200
commit5da4e09b47011d11c3ed8e1915a316ec8cf8897f (patch)
treefb29fb9bb7eb0420038ee034e382919bce78c5df
parent780d796a478f686379489fc2e02f932e7dcd67e9 (diff)
downloadsparse-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.c35
-rw-r--r--validation/optim/zext-and.c1
-rw-r--r--validation/optim/zext-and1.c1
3 files changed, 34 insertions, 3 deletions
diff --git a/simplify.c b/simplify.c
index a0f7aa32..b0512402 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 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