diff mbox series

[1/2] simplify unsigned compares against 0

Message ID 20201023155832.57237-2-luc.vanoostenryck@gmail.com (mailing list archive)
State Mainlined, archived
Headers show
Series simplify and canonicalize unsigned compares | expand

Commit Message

Luc Van Oostenryck Oct. 23, 2020, 3:58 p.m. UTC
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

Comments

Linus Torvalds Oct. 23, 2020, 4:13 p.m. UTC | #1
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
Luc Van Oostenryck Oct. 23, 2020, 7:08 p.m. UTC | #2
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 mbox series

Patch

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
+ */