aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-07-02 15:34:38 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-07-23 13:11:20 +0200
commit780d796a478f686379489fc2e02f932e7dcd67e9 (patch)
treeb929c5c53cb2cb309166cda96eb4f5f56e1bc0fd
parent45e70ebf4685004ad3cf31c8acf5b8c834933379 (diff)
downloadsparse-dev-780d796a478f686379489fc2e02f932e7dcd67e9.tar.gz
cast: simplify [ZS]EXT(AND(x,M),N)
A OP_AND with a constant value followed by a sign or zero-extension can often be moved after the extension. This is good because it can trigger the cancellation of the OP[ZS]EXT with a preceding OP_TRUNC, a common situation with bitfields. Note: This 'simplification' is less desirable if there is no preceding OP_TRUNC, for example, in a sequence like: and.32 %t <- %a, $mask *ext.64 %r <- %t If needed, this can be filtered out at some later stage. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--simplify.c24
-rw-r--r--validation/optim/and-extend.c1
-rw-r--r--validation/optim/and-extendx.c1
-rw-r--r--validation/optim/trunc-mask-zext.c1
4 files changed, 24 insertions, 3 deletions
diff --git a/simplify.c b/simplify.c
index 336339fa..a0f7aa32 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1011,6 +1011,30 @@ static int simplify_cast(struct instruction *insn)
mask &= (1ULL << size) - 1;
insn->src2 = value_pseudo(mask);
return REPEAT_CSE;
+
+ case OP_SEXT:
+ if (val->value & (1 << (def->size - 1)))
+ break;
+ // OK, sign bit is 0
+ case OP_ZEXT:
+ if (nbr_users(src) > 1)
+ break;
+ // transform:
+ // and.n %b <- %a, M
+ // *ext.m %c <- (n) %b
+ // into:
+ // zext.m %b <- %a
+ // and.m %c <- %b, M
+ // For ZEXT, the mask will always be small
+ // enough. For SEXT, it can only be done if
+ // the mask force the sign bit to 0.
+ def->opcode = OP_ZEXT;
+ def->orig_type = insn->orig_type;
+ def->type = insn->type;
+ def->size = insn->size;
+ insn->opcode = OP_AND;
+ insn->src2 = val;
+ return REPEAT_CSE;
}
break;
case OP_TRUNC:
diff --git a/validation/optim/and-extend.c b/validation/optim/and-extend.c
index fdcf470f..eb589236 100644
--- a/validation/optim/and-extend.c
+++ b/validation/optim/and-extend.c
@@ -18,7 +18,6 @@ u32 sfoo(u32 x)
/*
* check-name: and-extend
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-excludes: trunc\\.
diff --git a/validation/optim/and-extendx.c b/validation/optim/and-extendx.c
index a580bd0d..5c181c93 100644
--- a/validation/optim/and-extendx.c
+++ b/validation/optim/and-extendx.c
@@ -18,7 +18,6 @@ u64 sfoo(int x)
/*
* check-name: and-extend
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-contains: and\\.64.*0x7fff
diff --git a/validation/optim/trunc-mask-zext.c b/validation/optim/trunc-mask-zext.c
index 30ae5aee..9b604174 100644
--- a/validation/optim/trunc-mask-zext.c
+++ b/validation/optim/trunc-mask-zext.c
@@ -6,7 +6,6 @@ unsigned long long foo(unsigned long long x)
/*
* check-name: trunc-mask-zext
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-excludes: trunc\\.