Message ID | 20201023155832.57237-2-luc.vanoostenryck@gmail.com (mailing list archive) |
---|---|
State | Mainlined, archived |
Headers | show |
Series | simplify and canonicalize unsigned compares | expand |
On Fri, Oct 23, 2020 at 8:58 AM Luc Van Oostenryck <luc.vanoostenryck@gmail.com> wrote: > > Some unsigned compares against 0 are always true or always false > (x < 0 or x >= 0). Simplify them. Fair enough, but if you're simplifying compares, one of the more important simplifications is to make the compare unsigned in the first place. IOW, simplifying (signed >= 0 && signed < X) into (unsigned < X) if you can show that X is positive (most trivially a constant). Example: int cmp(int i) { return i >= 0 && i < 4; } which currently generates setge.1 %r3 <- %arg1, $0 setlt.1 %r6 <- %arg1, $4 and.1 %r7 <- %r3, %r6 zext.32 %r8 <- (1) %r7 ret.32 %r8 which is obviously not great. Another comparison simplification often worth doing is to do cast simplification, ie ((cast) X cmpop Y) where 'Y' already fits in the original type of 'X', and the cast is unnecessary. Test-case: int cmp(int i) { return i < sizeof(i); } and notice how sparse generates sext.64 %r2 <- (32) %arg1 setb.32 %r3 <- %r2, $4 ret.32 %r3 with that entirely unnecessary sign extension that doesn't really help.. The related simplification is then (signed >= 0 && unsigned < X) and just removing the "signed > 0" case. These happen when you have code that checks for sizes: int cmp(int i) { return i >= 0 && i < sizeof(i); } where that "i < sizeof(i)" ended up being not just extended to 64-bit, but an unsigned compare due to the 'sizeof()' being unsigned. Linus
On Fri, Oct 23, 2020 at 09:13:22AM -0700, Linus Torvalds wrote: > On Fri, Oct 23, 2020 at 8:58 AM Luc Van Oostenryck > <luc.vanoostenryck@gmail.com> wrote: > > > > Some unsigned compares against 0 are always true or always false > > (x < 0 or x >= 0). Simplify them. > > Fair enough, but if you're simplifying compares, one of the more > important simplifications is to make the compare unsigned in the first > place. > > ... > > Another comparison simplification often worth doing is to do cast > simplification, ie > > ((cast) X cmpop Y) Yes, these seem quite easy with a nice return rate. I've a lot of pending, uncompleted topic branches (which I'm currently trying to polish and upstream, hence the apparent lack of a direction line) but I don't think I've anything for these. I'll look at them soon. -- Luc
diff --git a/simplify.c b/simplify.c index 6caf6cbcf918..4441b27c7546 100644 --- a/simplify.c +++ b/simplify.c @@ -1173,6 +1173,16 @@ static int simplify_constant_rightside(struct instruction *insn) case OP_SET_NE: case OP_SET_EQ: return simplify_seteq_setne(insn, value); + case OP_SET_B: + if (!value) { // (x < 0) --> 0 + return replace_with_pseudo(insn, value_pseudo(0)); + } + break; + case OP_SET_AE: + if (!value) { // (x >= 0) --> 1 + return replace_with_pseudo(insn, value_pseudo(1)); + } + break; } return 0; } diff --git a/validation/optim/set-uimm0.c b/validation/optim/set-uimm0.c new file mode 100644 index 000000000000..1f62358ff0fb --- /dev/null +++ b/validation/optim/set-uimm0.c @@ -0,0 +1,10 @@ +static _Bool setlt0(unsigned int a) { return (a < 0u) == 0; } +static _Bool setge0(unsigned int a) { return (a >= 0u) == 1; } + +/* + * check-name: set-uimm0 + * check-command: test-linearize $file + * + * check-output-ignore + * check-output-pattern(2): ret\\.1 *\\$1 + */
Some unsigned compares against 0 are always true or always false (x < 0 or x >= 0). Simplify them. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com> --- simplify.c | 10 ++++++++++ validation/optim/set-uimm0.c | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 validation/optim/set-uimm0.c