* [PATCH 00/10] simplify and canonicalize signed compares
@ 2021-01-26 22:04 Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 01/10] cmps: make clearer we're using the operands' size Luc Van Oostenryck
` (10 more replies)
0 siblings, 11 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
This series fixes and improves the simplification and the
canonicalization of signed compares.
Luc Van Oostenryck (10):
cmps: make clearer we're using the operands' size
cmps: fix simplification of sext(x) + signed compare of {SMAX,SMIN}
cmpu: fix canonicalization of unsigned (x {<,>=} C) --> (x {<=,>} C-1)
cmps: add testcases for simplification of signed compares
cmps: simplify signed compares with SMIN or SMAX
cmps: canonicalize signed compares with SMIN/SMAX
cmps: canonicalize SMIN/SMAX +- 1 --> EQ/NE
cmps: canonicalize signed compares with constant
cmps: canonicalize SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a)
cmps: canonicalize SEL(x > 0, a, -a) --> SEL(x >= 0, a, -a)
simplify.c | 73 +++++++++++++++++++++---
validation/optim/canonical-abs.c | 11 ++++
validation/optim/canonical-cmpe-minmax.c | 16 ++++++
validation/optim/canonical-cmps-minmax.c | 16 ++++++
validation/optim/canonical-cmps-sel.c | 25 ++++++++
validation/optim/canonical-cmps.c | 16 ++++++
validation/optim/cmp-sext-simm.c | 46 +++++++++++----
validation/optim/cmps-minmax.c | 16 ++++++
8 files changed, 200 insertions(+), 19 deletions(-)
create mode 100644 validation/optim/canonical-abs.c
create mode 100644 validation/optim/canonical-cmpe-minmax.c
create mode 100644 validation/optim/canonical-cmps-minmax.c
create mode 100644 validation/optim/canonical-cmps-sel.c
create mode 100644 validation/optim/canonical-cmps.c
create mode 100644 validation/optim/cmps-minmax.c
base-commit: 0fb77bb6e5429575f52b5e26f06db031f93de057
--
2.30.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 01/10] cmps: make clearer we're using the operands' size
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 02/10] cmps: fix simplification of sext(x) + signed compare of {SMAX,SMIN} Luc Van Oostenryck
` (9 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
When handling compares of an {zero,sign}-extended value, the
size of these extended values are used but this size is just
the operands' size of the compares.
Make this clearer by using a single variable 'size' for it.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/simplify.c b/simplify.c
index bf6397dfd582..2f6f41c249dc 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1162,7 +1162,8 @@ static int simplify_seteq_setne(struct instruction *insn, long long value)
static int simplify_compare_constant(struct instruction *insn, long long value)
{
- unsigned long long bits = bits_mask(insn->itype->bit_size);
+ unsigned size = insn->itype->bit_size;
+ unsigned long long bits = bits_mask(size);
struct instruction *def;
pseudo_t src1, src2;
unsigned int osize;
@@ -1217,7 +1218,7 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
switch (DEF_OPCODE(def, src1)) {
case OP_SEXT: // sext(x) cmp C --> x cmp trunc(C)
osize = def->orig_type->bit_size;
- if (is_signed_constant(value, osize, def->size)) {
+ if (is_signed_constant(value, osize, size)) {
insn->itype = def->orig_type;
insn->src2 = value_pseudo(zero_extend(value, osize));
return replace_pseudo(insn, &insn->src1, def->src);
@@ -1263,13 +1264,13 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
}
switch (insn->opcode) {
case OP_SET_LT: case OP_SET_LE:
- if (sign_extend(value, def->size) > (long long)bits)
+ if (sign_extend(value, size) > (long long)bits)
return replace_with_value(insn, 1);
else
return replace_with_value(insn, 0);
break;
case OP_SET_GE: case OP_SET_GT:
- if (sign_extend(value, def->size) > (long long)bits)
+ if (sign_extend(value, size) > (long long)bits)
return replace_with_value(insn, 0);
else
return replace_with_value(insn, 1);
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 02/10] cmps: fix simplification of sext(x) + signed compare of {SMAX,SMIN}
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 01/10] cmps: make clearer we're using the operands' size Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 03/10] cmpu: fix canonicalization of unsigned (x {<,>=} C) --> (x {<=,>} C-1) Luc Van Oostenryck
` (8 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
Commit a1c1b9236d5d ("cmp: simplify sext(x) cmps {SMAX,SMIN}")
had a double error (wrong size and wrong compare direction) which
was hidden because of too narrow testcases.
So, fix the simplification and extend the testcases.
Fixes: a1c1b9236d5d4af1681a45ced26f8350bd7721c2
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 4 +--
validation/optim/cmp-sext-simm.c | 46 ++++++++++++++++++++++++--------
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/simplify.c b/simplify.c
index 2f6f41c249dc..9a24058f6e55 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1239,13 +1239,13 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
}
break;
case OP_SET_LT: case OP_SET_LE:
- if (value >= sign_bit(osize))
+ if (value < sign_bit(size))
return replace_with_value(insn, 1);
else
return replace_with_value(insn, 0);
break;
case OP_SET_GE: case OP_SET_GT:
- if (value >= sign_bit(osize))
+ if (value < sign_bit(size))
return replace_with_value(insn, 0);
else
return replace_with_value(insn, 1);
diff --git a/validation/optim/cmp-sext-simm.c b/validation/optim/cmp-sext-simm.c
index a8b2a8f9feff..57a4df1d57b1 100644
--- a/validation/optim/cmp-sext-simm.c
+++ b/validation/optim/cmp-sext-simm.c
@@ -4,21 +4,45 @@
static int lt_ge0(int x) { return (sext(x) < (POS + 0)) == 1; }
static int lt_ge1(int x) { return (sext(x) < (POS + 1)) == 1; }
+static int lt_ge2(int x) { return (sext(x) < (POS + 2)) == 1; }
+static int lt_gex(int x) { return (sext(x) < (POS<< 1)) == 1; }
+static int lt_gey(int x) { return (sext(x) < (POS<< 3)) == 1; }
static int le_ge0(int x) { return (sext(x) <= (POS + 0)) == 1; }
static int le_ge1(int x) { return (sext(x) <= (POS + 1)) == 1; }
-static int lt_lt0(int x) { return (sext(x) < (NEG - 0)) == 1; }
-static int lt_lt1(int x) { return (sext(x) < (NEG - 1)) == 1; }
-static int le_lt0(int x) { return (sext(x) <= (NEG - 0)) == 1; }
-static int le_lt1(int x) { return (sext(x) <= (NEG - 1)) == 1; }
-
-static int gt_ge0(int x) { return (sext(x) > (POS + 0)) == 0; }
-static int gt_ge1(int x) { return (sext(x) > (POS + 1)) == 0; }
+static int le_ge2(int x) { return (sext(x) <= (POS + 2)) == 1; }
+static int le_gex(int x) { return (sext(x) <= (POS<< 1)) == 1; }
+static int le_gey(int x) { return (sext(x) <= (POS<< 3)) == 1; }
static int ge_ge0(int x) { return (sext(x) >= (POS + 0)) == 0; }
static int ge_ge1(int x) { return (sext(x) >= (POS + 1)) == 0; }
-static int gt_lt0(int x) { return (sext(x) > (NEG - 0)) == 0; }
-static int gt_lt1(int x) { return (sext(x) > (NEG - 1)) == 0; }
-static int ge_lt0(int x) { return (sext(x) >= (NEG - 0)) == 0; }
-static int ge_lt1(int x) { return (sext(x) >= (NEG - 1)) == 0; }
+static int ge_ge2(int x) { return (sext(x) >= (POS + 2)) == 0; }
+static int ge_gex(int x) { return (sext(x) >= (POS<< 1)) == 0; }
+static int ge_gey(int x) { return (sext(x) >= (POS<< 3)) == 0; }
+static int gt_ge0(int x) { return (sext(x) > (POS + 0)) == 0; }
+static int gt_ge1(int x) { return (sext(x) > (POS + 1)) == 0; }
+static int gt_ge2(int x) { return (sext(x) > (POS + 2)) == 0; }
+static int gt_gex(int x) { return (sext(x) > (POS<< 1)) == 0; }
+static int gt_gey(int x) { return (sext(x) > (POS<< 3)) == 0; }
+
+static int lt_lt0(int x) { return (sext(x) < (NEG - 0)) == 0; }
+static int lt_lt1(int x) { return (sext(x) < (NEG - 1)) == 0; }
+static int lt_lt2(int x) { return (sext(x) < (NEG - 2)) == 0; }
+static int lt_ltx(int x) { return (sext(x) < (NEG<< 1)) == 0; }
+static int lt_lty(int x) { return (sext(x) < (NEG<< 3)) == 0; }
+static int le_lt0(int x) { return (sext(x) <= (NEG - 0)) == 0; }
+static int le_lt1(int x) { return (sext(x) <= (NEG - 1)) == 0; }
+static int le_lt2(int x) { return (sext(x) <= (NEG - 2)) == 0; }
+static int le_ltx(int x) { return (sext(x) <= (NEG<< 1)) == 0; }
+static int le_lty(int x) { return (sext(x) <= (NEG<< 3)) == 0; }
+static int ge_lt0(int x) { return (sext(x) >= (NEG - 0)) == 1; }
+static int ge_lt1(int x) { return (sext(x) >= (NEG - 1)) == 1; }
+static int ge_lt2(int x) { return (sext(x) >= (NEG - 2)) == 1; }
+static int ge_ltx(int x) { return (sext(x) >= (NEG<< 1)) == 1; }
+static int ge_lty(int x) { return (sext(x) >= (NEG<< 3)) == 1; }
+static int gt_lt0(int x) { return (sext(x) > (NEG - 0)) == 1; }
+static int gt_lt1(int x) { return (sext(x) > (NEG - 1)) == 1; }
+static int gt_lt2(int x) { return (sext(x) > (NEG - 2)) == 1; }
+static int gt_ltx(int x) { return (sext(x) > (NEG<< 1)) == 1; }
+static int gt_lty(int x) { return (sext(x) > (NEG<< 3)) == 1; }
/*
* check-name: cmp-sext-simm
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 03/10] cmpu: fix canonicalization of unsigned (x {<,>=} C) --> (x {<=,>} C-1)
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 01/10] cmps: make clearer we're using the operands' size Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 02/10] cmps: fix simplification of sext(x) + signed compare of {SMAX,SMIN} Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 04/10] cmps: add testcases for simplification of signed compares Luc Van Oostenryck
` (7 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
In Sparse, the PSEUDO_VALUEs are required to be truncated at their
effective size. For example, for a 32-bit instruction and Sparse using
64-bit integers, a pseudo of -1 must contain the value 0x00000000ffffffff,
not 0xffffffffffffffff.
Add the missing truncation in the canonicalization here.
Fixes: c355e5ac5dce35f3d95c30cd5e2e9a5074c38437
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/simplify.c b/simplify.c
index 9a24058f6e55..a306828c1c4b 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1178,7 +1178,7 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
else if (value == bits) // (x < ~0) --> (x != ~0)
return replace_binop_value(insn, OP_SET_NE, value);
else // (x < y) --> (x <= (y-1))
- changed |= replace_binop_value(insn, OP_SET_BE, value - 1);
+ changed |= replace_binop_value(insn, OP_SET_BE, (value - 1) & bits);
break;
case OP_SET_AE:
if (!value) // (x >= 0) --> 1
@@ -1188,7 +1188,7 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
else if (value == bits) // (x >= ~0) --> (x == ~0)
return replace_binop_value(insn, OP_SET_EQ, value);
else // (x >= y) --> (x > (y-1)
- changed |= replace_binop_value(insn, OP_SET_A, value - 1);
+ changed |= replace_binop_value(insn, OP_SET_A, (value - 1) & bits);
break;
case OP_SET_BE:
if (!value) // (x <= 0) --> (x == 0)
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 04/10] cmps: add testcases for simplification of signed compares
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (2 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 03/10] cmpu: fix canonicalization of unsigned (x {<,>=} C) --> (x {<=,>} C-1) Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 05/10] cmps: simplify signed compares with SMIN or SMAX Luc Van Oostenryck
` (6 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
Signed compares miss some simplifications/canonicalizations.
Add some testcases for them.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
validation/optim/canonical-abs.c | 12 +++++++++++
validation/optim/canonical-cmpe-minmax.c | 17 ++++++++++++++++
validation/optim/canonical-cmps-minmax.c | 17 ++++++++++++++++
validation/optim/canonical-cmps-sel.c | 26 ++++++++++++++++++++++++
validation/optim/canonical-cmps.c | 17 ++++++++++++++++
validation/optim/cmps-minmax.c | 17 ++++++++++++++++
6 files changed, 106 insertions(+)
create mode 100644 validation/optim/canonical-abs.c
create mode 100644 validation/optim/canonical-cmpe-minmax.c
create mode 100644 validation/optim/canonical-cmps-minmax.c
create mode 100644 validation/optim/canonical-cmps-sel.c
create mode 100644 validation/optim/canonical-cmps.c
create mode 100644 validation/optim/cmps-minmax.c
diff --git a/validation/optim/canonical-abs.c b/validation/optim/canonical-abs.c
new file mode 100644
index 000000000000..0809a52d445b
--- /dev/null
+++ b/validation/optim/canonical-abs.c
@@ -0,0 +1,12 @@
+_Bool abs0(int a) { return (a < 0 ? -a : a) == (a >= 0 ? a : -a); }
+_Bool abs1(int a) { return (a < 0 ? -a : a) == (a > 0 ? a : -a); }
+_Bool abs2(int a) { return (a < 0 ? -a : a) == (a <= 0 ? -a : a); }
+
+/*
+ * check-name: canonical-abs1
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/optim/canonical-cmpe-minmax.c b/validation/optim/canonical-cmpe-minmax.c
new file mode 100644
index 000000000000..c72819244b95
--- /dev/null
+++ b/validation/optim/canonical-cmpe-minmax.c
@@ -0,0 +1,17 @@
+#define SMAX __INT_MAX__
+#define SMIN (-__INT_MAX__-1)
+
+int le_smax(int a) { return (a <= (SMAX - 1)) == (a != SMAX); }
+int gt_smax(int a) { return (a > (SMAX - 1)) == (a == SMAX); }
+
+int lt_smin(int a) { return (a < (SMIN + 1)) == (a == SMIN); }
+int ge_smin(int a) { return (a >= (SMIN + 1)) == (a != SMIN); }
+
+/*
+ * check-name: canonical-cmpe-minmax
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/optim/canonical-cmps-minmax.c b/validation/optim/canonical-cmps-minmax.c
new file mode 100644
index 000000000000..bab09282d241
--- /dev/null
+++ b/validation/optim/canonical-cmps-minmax.c
@@ -0,0 +1,17 @@
+#define SMAX __INT_MAX__
+#define SMIN (-__INT_MAX__-1)
+
+int lt_smax(int a) { return (a < SMAX) == (a != SMAX); }
+int ge_smax(int a) { return (a >= SMAX) == (a == SMAX); }
+
+int le_smin(int a) { return (a <= SMIN) == (a == SMIN); }
+int gt_smin(int a) { return (a > SMIN) == (a != SMIN); }
+
+/*
+ * check-name: canonical-cmps-minmax
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/optim/canonical-cmps-sel.c b/validation/optim/canonical-cmps-sel.c
new file mode 100644
index 000000000000..f0a0effc7954
--- /dev/null
+++ b/validation/optim/canonical-cmps-sel.c
@@ -0,0 +1,26 @@
+_Bool sel_lts(int a, int b, int x, int y)
+{
+ return ((a < b) ? x : y) == ((a >= b) ? y : x);
+}
+_Bool sel_les(int a, int b, int x, int y)
+{
+ return ((a <= b) ? x : y) == ((a > b) ? y : x);
+}
+
+_Bool sel_ltu(unsigned int a, unsigned int b, int x, int y)
+{
+ return ((a < b) ? x : y) == ((a >= b) ? y : x);
+}
+_Bool sel_leu(unsigned int a, unsigned int b, int x, int y)
+{
+ return ((a <= b) ? x : y) == ((a > b) ? y : x);
+}
+
+/*
+ * check-name: canonical-cmps-sel
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/optim/canonical-cmps.c b/validation/optim/canonical-cmps.c
new file mode 100644
index 000000000000..f42664b21e04
--- /dev/null
+++ b/validation/optim/canonical-cmps.c
@@ -0,0 +1,17 @@
+_Bool lt_p(int a) { return (a > 0) == (a >= 1); }
+_Bool ge_p(int a) { return (a <= 0) == (a < 1); }
+
+_Bool lt_m(int a) { return (a < 0) == (a <= -1); }
+_Bool ge_m(int a) { return (a >= 0) == (a > -1); }
+
+_Bool lt_x(int a) { return (a <= 1234) == (a < 1235); }
+_Bool ge_x(int a) { return (a >= 1234) == (a > 1233); }
+
+/*
+ * check-name: canonical-cmps
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
diff --git a/validation/optim/cmps-minmax.c b/validation/optim/cmps-minmax.c
new file mode 100644
index 000000000000..ded3286cf752
--- /dev/null
+++ b/validation/optim/cmps-minmax.c
@@ -0,0 +1,17 @@
+#define SMAX __INT_MAX__
+#define SMIN (-__INT_MAX__-1)
+
+int lt_smin(int a) { return (a < SMIN) == 0; }
+int le_smax(int a) { return (a <= SMAX) == 1; }
+
+int ge_smin(int a) { return (a >= SMIN) == 1; }
+int gt_smax(int a) { return (a > SMAX) == 0; }
+
+/*
+ * check-name: cmps-minmax
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-returns: 1
+ */
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 05/10] cmps: simplify signed compares with SMIN or SMAX
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (3 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 04/10] cmps: add testcases for simplification of signed compares Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 06/10] cmps: canonicalize signed compares with SMIN/SMAX Luc Van Oostenryck
` (5 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
Simplify away signed compares with SMIN or SMAX which can be
statically be determined to be always true or always false.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 17 +++++++++++++++++
validation/optim/cmps-minmax.c | 1 -
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/simplify.c b/simplify.c
index a306828c1c4b..096742d51a16 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1170,6 +1170,23 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
int changed = 0;
switch (insn->opcode) {
+ case OP_SET_LT:
+ if (value == sign_bit(size)) // (x < SMIN) --> 0
+ return replace_with_pseudo(insn, value_pseudo(0));
+ break;
+ case OP_SET_LE:
+ if (value == sign_mask(size)) // (x <= SMAX) --> 1
+ return replace_with_pseudo(insn, value_pseudo(1));
+ break;
+ case OP_SET_GE:
+ if (value == sign_bit(size)) // (x >= SMIN) --> 1
+ return replace_with_pseudo(insn, value_pseudo(1));
+ break;
+ case OP_SET_GT:
+ if (value == sign_mask(size)) // (x > SMAX) --> 0
+ return replace_with_pseudo(insn, value_pseudo(0));
+ break;
+
case OP_SET_B:
if (!value) // (x < 0) --> 0
return replace_with_pseudo(insn, value_pseudo(0));
diff --git a/validation/optim/cmps-minmax.c b/validation/optim/cmps-minmax.c
index ded3286cf752..5802cdbcafd1 100644
--- a/validation/optim/cmps-minmax.c
+++ b/validation/optim/cmps-minmax.c
@@ -10,7 +10,6 @@ int gt_smax(int a) { return (a > SMAX) == 0; }
/*
* check-name: cmps-minmax
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-returns: 1
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 06/10] cmps: canonicalize signed compares with SMIN/SMAX
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (4 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 05/10] cmps: simplify signed compares with SMIN or SMAX Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 07/10] cmps: canonicalize SMIN/SMAX +- 1 --> EQ/NE Luc Van Oostenryck
` (4 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
The remaining compares with SMIN or SMAX are equivalent to an
equality testing. For example, (x < SMAX) is the same as (x != SMAX).
Canonicalize these to the equality testing since these are usually
simpler to handle.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 8 ++++++++
validation/optim/canonical-cmps-minmax.c | 1 -
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/simplify.c b/simplify.c
index 096742d51a16..f7c6c68d4ce9 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1173,18 +1173,26 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
case OP_SET_LT:
if (value == sign_bit(size)) // (x < SMIN) --> 0
return replace_with_pseudo(insn, value_pseudo(0));
+ if (value == sign_mask(size)) // (x < SMAX) --> (x != SMAX)
+ return replace_opcode(insn, OP_SET_NE);
break;
case OP_SET_LE:
if (value == sign_mask(size)) // (x <= SMAX) --> 1
return replace_with_pseudo(insn, value_pseudo(1));
+ if (value == sign_bit(size)) // (x <= SMIN) --> (x == SMIN)
+ return replace_opcode(insn, OP_SET_EQ);
break;
case OP_SET_GE:
if (value == sign_bit(size)) // (x >= SMIN) --> 1
return replace_with_pseudo(insn, value_pseudo(1));
+ if (value == sign_mask(size)) // (x >= SMAX) --> (x == SMAX)
+ return replace_opcode(insn, OP_SET_EQ);
break;
case OP_SET_GT:
if (value == sign_mask(size)) // (x > SMAX) --> 0
return replace_with_pseudo(insn, value_pseudo(0));
+ if (value == sign_bit(size)) // (x > SMIN) --> (x != SMIN)
+ return replace_opcode(insn, OP_SET_NE);
break;
case OP_SET_B:
diff --git a/validation/optim/canonical-cmps-minmax.c b/validation/optim/canonical-cmps-minmax.c
index bab09282d241..48927f49db6e 100644
--- a/validation/optim/canonical-cmps-minmax.c
+++ b/validation/optim/canonical-cmps-minmax.c
@@ -10,7 +10,6 @@ int gt_smin(int a) { return (a > SMIN) == (a != SMIN); }
/*
* check-name: canonical-cmps-minmax
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-returns: 1
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 07/10] cmps: canonicalize SMIN/SMAX +- 1 --> EQ/NE
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (5 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 06/10] cmps: canonicalize signed compares with SMIN/SMAX Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 08/10] cmps: canonicalize signed compares with constant Luc Van Oostenryck
` (3 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
Compares with SMIN + 1 or SMAX - 1 are equivalent to an equality
testing. For example, (x < SMIN + 1) is the same as (x == SMIN).
Canonicalize these to the equality testing since these are usually
simpler to handle.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 8 ++++++++
validation/optim/canonical-cmpe-minmax.c | 1 -
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/simplify.c b/simplify.c
index f7c6c68d4ce9..ad3adb11595e 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1175,24 +1175,32 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
return replace_with_pseudo(insn, value_pseudo(0));
if (value == sign_mask(size)) // (x < SMAX) --> (x != SMAX)
return replace_opcode(insn, OP_SET_NE);
+ if (value == sign_bit(size) + 1)// (x < SMIN + 1) --> (x == SMIN)
+ return replace_binop_value(insn, OP_SET_EQ, sign_bit(size));
break;
case OP_SET_LE:
if (value == sign_mask(size)) // (x <= SMAX) --> 1
return replace_with_pseudo(insn, value_pseudo(1));
if (value == sign_bit(size)) // (x <= SMIN) --> (x == SMIN)
return replace_opcode(insn, OP_SET_EQ);
+ if (value == sign_mask(size) - 1) // (x <= SMAX - 1) --> (x != SMAX)
+ return replace_binop_value(insn, OP_SET_NE, sign_mask(size));
break;
case OP_SET_GE:
if (value == sign_bit(size)) // (x >= SMIN) --> 1
return replace_with_pseudo(insn, value_pseudo(1));
if (value == sign_mask(size)) // (x >= SMAX) --> (x == SMAX)
return replace_opcode(insn, OP_SET_EQ);
+ if (value == sign_bit(size) + 1)// (x >= SMIN + 1) --> (x != SMIN)
+ return replace_binop_value(insn, OP_SET_NE, sign_bit(size));
break;
case OP_SET_GT:
if (value == sign_mask(size)) // (x > SMAX) --> 0
return replace_with_pseudo(insn, value_pseudo(0));
if (value == sign_bit(size)) // (x > SMIN) --> (x != SMIN)
return replace_opcode(insn, OP_SET_NE);
+ if (value == sign_mask(size) - 1) // (x > SMAX - 1) --> (x == SMAX)
+ return replace_binop_value(insn, OP_SET_EQ, sign_mask(size));
break;
case OP_SET_B:
diff --git a/validation/optim/canonical-cmpe-minmax.c b/validation/optim/canonical-cmpe-minmax.c
index c72819244b95..32b272435fa2 100644
--- a/validation/optim/canonical-cmpe-minmax.c
+++ b/validation/optim/canonical-cmpe-minmax.c
@@ -10,7 +10,6 @@ int ge_smin(int a) { return (a >= (SMIN + 1)) == (a != SMIN); }
/*
* check-name: canonical-cmpe-minmax
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-returns: 1
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 08/10] cmps: canonicalize signed compares with constant
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (6 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 07/10] cmps: canonicalize SMIN/SMAX +- 1 --> EQ/NE Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 09/10] cmps: canonicalize SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a) Luc Van Oostenryck
` (2 subsequent siblings)
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
Modify the constants to canonicalize (x < C) to (x <= (C-1)) and
(x <= C) to (x > (C-1)). This choice is partially arbitrary but
1) it's the one with the smallest positive constants,
2) it eliminates all OP_SET_LT & OP_SET_GE with a constant.
A disadvantage of this choice is that we lost some compares with 0:
(x < 0) is now canonicalized into (x <= -1).
Note: Another good choice would be to canonicalize using the
smallest absolute constants. This would keep compares with 0
but would also keep the 4 kinds of comparison.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 2 ++
validation/optim/canonical-cmps.c | 1 -
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/simplify.c b/simplify.c
index ad3adb11595e..b29f5d5b2444 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1177,6 +1177,7 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
return replace_opcode(insn, OP_SET_NE);
if (value == sign_bit(size) + 1)// (x < SMIN + 1) --> (x == SMIN)
return replace_binop_value(insn, OP_SET_EQ, sign_bit(size));
+ changed |= replace_binop_value(insn, OP_SET_LE, (value - 1) & bits);
break;
case OP_SET_LE:
if (value == sign_mask(size)) // (x <= SMAX) --> 1
@@ -1193,6 +1194,7 @@ static int simplify_compare_constant(struct instruction *insn, long long value)
return replace_opcode(insn, OP_SET_EQ);
if (value == sign_bit(size) + 1)// (x >= SMIN + 1) --> (x != SMIN)
return replace_binop_value(insn, OP_SET_NE, sign_bit(size));
+ changed |= replace_binop_value(insn, OP_SET_GT, (value - 1) & bits);
break;
case OP_SET_GT:
if (value == sign_mask(size)) // (x > SMAX) --> 0
diff --git a/validation/optim/canonical-cmps.c b/validation/optim/canonical-cmps.c
index f42664b21e04..42801cdce520 100644
--- a/validation/optim/canonical-cmps.c
+++ b/validation/optim/canonical-cmps.c
@@ -10,7 +10,6 @@ _Bool ge_x(int a) { return (a >= 1234) == (a > 1233); }
/*
* check-name: canonical-cmps
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-returns: 1
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 09/10] cmps: canonicalize SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a)
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (7 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 08/10] cmps: canonicalize signed compares with constant Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 10/10] cmps: canonicalize SEL(x > 0, a, -a) --> SEL(x >= 0, a, -a) Luc Van Oostenryck
2021-04-17 17:16 ` [PATCH 00/10] simplify and canonicalize signed compares Linus Torvalds
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
Both compares and OP_SELECT are anti-symmetrical: swapping
the arguments is equivalent to inversing the condition.
As consequence, when combined, they're symmetrical:
swapping the arguments of the compare (or equivalently reversing
the direction of the compare) and swapping the operand of the
OP_SELECT is a no-op, both forms are equivalent.
So, canonicalize these to always use OP_GT or OP_GE.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 7 +++++++
validation/optim/canonical-cmps-sel.c | 1 -
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/simplify.c b/simplify.c
index b29f5d5b2444..10cdf50dcbf1 100644
--- a/simplify.c
+++ b/simplify.c
@@ -2301,6 +2301,13 @@ static int simplify_select(struct instruction *insn)
if (src2 == def->src1 && src1 == def->src2)
return replace_with_pseudo(insn, src1); // SEL(y!=x,x,y) --> x
break;
+ case OP_SET_LE: case OP_SET_LT:
+ case OP_SET_BE: case OP_SET_B:
+ if (!one_use(cond))
+ break;
+ // SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a)
+ def->opcode = opcode_negate(def->opcode);
+ return switch_pseudo(insn, &insn->src2, insn, &insn->src3);
case OP_SEL:
if (constant(def->src2) && constant(def->src3)) {
// Is the def of the conditional another select?
diff --git a/validation/optim/canonical-cmps-sel.c b/validation/optim/canonical-cmps-sel.c
index f0a0effc7954..bba5e5c894f8 100644
--- a/validation/optim/canonical-cmps-sel.c
+++ b/validation/optim/canonical-cmps-sel.c
@@ -19,7 +19,6 @@ _Bool sel_leu(unsigned int a, unsigned int b, int x, int y)
/*
* check-name: canonical-cmps-sel
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-returns: 1
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 10/10] cmps: canonicalize SEL(x > 0, a, -a) --> SEL(x >= 0, a, -a)
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (8 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 09/10] cmps: canonicalize SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a) Luc Van Oostenryck
@ 2021-01-26 22:04 ` Luc Van Oostenryck
2021-04-17 17:16 ` [PATCH 00/10] simplify and canonicalize signed compares Linus Torvalds
10 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-01-26 22:04 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
When computing the absolute value using an expression like:
(a > 0) ? a : -a
it's irrelevant to use '>' or '>=', both will give the same
result since 0 is its own negation.
Canonicalize these equivalent expressions, such that OP_GE
is always used.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
simplify.c | 14 ++++++++++++++
validation/optim/canonical-abs.c | 1 -
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/simplify.c b/simplify.c
index 10cdf50dcbf1..584078ddca89 100644
--- a/simplify.c
+++ b/simplify.c
@@ -454,6 +454,13 @@ static inline pseudo_t is_same_op(pseudo_t src, int op, unsigned osize)
return def->src;
}
+static bool is_negate_of(pseudo_t p, pseudo_t ref)
+{
+ struct instruction *def;
+
+ return (DEF_OPCODE(def, p) == OP_NEG) && (def->src == ref);
+}
+
///
// replace the operand of an instruction
// @insn: the instruction
@@ -2308,6 +2315,13 @@ static int simplify_select(struct instruction *insn)
// SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a)
def->opcode = opcode_negate(def->opcode);
return switch_pseudo(insn, &insn->src2, insn, &insn->src3);
+ case OP_SET_GT:
+ if (one_use(cond) && is_zero(def->src2)) {
+ if (is_negate_of(src2, src1))
+ // SEL(x > 0, a, -a) --> SEL(x >= 0, a, -a)
+ return replace_opcode(def, OP_SET_GE);
+ }
+ break;
case OP_SEL:
if (constant(def->src2) && constant(def->src3)) {
// Is the def of the conditional another select?
diff --git a/validation/optim/canonical-abs.c b/validation/optim/canonical-abs.c
index 0809a52d445b..1bd6d89a3ad5 100644
--- a/validation/optim/canonical-abs.c
+++ b/validation/optim/canonical-abs.c
@@ -5,7 +5,6 @@ _Bool abs2(int a) { return (a < 0 ? -a : a) == (a <= 0 ? -a : a); }
/*
* check-name: canonical-abs1
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-returns: 1
--
2.30.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 00/10] simplify and canonicalize signed compares
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
` (9 preceding siblings ...)
2021-01-26 22:04 ` [PATCH 10/10] cmps: canonicalize SEL(x > 0, a, -a) --> SEL(x >= 0, a, -a) Luc Van Oostenryck
@ 2021-04-17 17:16 ` Linus Torvalds
2021-04-17 18:20 ` Luc Van Oostenryck
10 siblings, 1 reply; 13+ messages in thread
From: Linus Torvalds @ 2021-04-17 17:16 UTC (permalink / raw)
To: Luc Van Oostenryck; +Cc: Sparse Mailing-list
On Tue, Jan 26, 2021 at 7:45 PM Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
>
> This series fixes and improves the simplification and the
> canonicalization of signed compares.
Hmm. Sorry for not replying earlier, but I just checked the most
common simplification of signed compares, and it didn't work.
This:
_Bool test(int a)
{
return a >=0 && a < 16;
}
should simplify to be the same as
_Bool test(int a)
{
return (unsigned)a < 16;
}
but it doesn't. It generates the silly - but straightforward - "two
comparisons and a 'and' of the result".
In fact, the recent canonicalizations means that the compare against
zero is actually pessimised, and ">= 0" becomes "> 0xffffffff", which
is often a much more expensive operation.
This came up because I was looking at some kernel code that did
exactly that "check that a signed value is within proper bounds", and
the zero check is a very common bound.
Linus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 00/10] simplify and canonicalize signed compares
2021-04-17 17:16 ` [PATCH 00/10] simplify and canonicalize signed compares Linus Torvalds
@ 2021-04-17 18:20 ` Luc Van Oostenryck
0 siblings, 0 replies; 13+ messages in thread
From: Luc Van Oostenryck @ 2021-04-17 18:20 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Sparse Mailing-list
On Sat, Apr 17, 2021 at 10:16:31AM -0700, Linus Torvalds wrote:
> On Tue, Jan 26, 2021 at 7:45 PM Luc Van Oostenryck
> <luc.vanoostenryck@gmail.com> wrote:
> >
> > This series fixes and improves the simplification and the
> > canonicalization of signed compares.
>
> Hmm. Sorry for not replying earlier, but I just checked the most
> common simplification of signed compares, and it didn't work.
>
> This:
>
> _Bool test(int a)
> {
> return a >=0 && a < 16;
> }
>
> should simplify to be the same as
>
> _Bool test(int a)
> {
> return (unsigned)a < 16;
> }
>
> but it doesn't. It generates the silly - but straightforward - "two
> comparisons and a 'and' of the result".
Yes, I've a draft for this but I still needs to add some tests and such.
> In fact, the recent canonicalizations means that the compare against
> zero is actually pessimised, and ">= 0" becomes "> 0xffffffff", which
> is often a much more expensive operation.
Yes, I'm aware of the problem, more or less.
When I did the canonicalization, I wondered what was better:
* canonicalize toward 0
* canonicalize toward the smallest
I choose the later because at the moment it was somehow advantageous
because it reduced by 2 some patterns (it allows to eliminate all >=
and all <; when doing it toward 0 you can eliminate one set for positive
and the other one for negatives values so you need both sets). The
compare with -1 instead of with 0 didn't looked much problematic and
relatively rare. But in the following days I realized it was in fact
quite annoying.
So, yes, it's something I'll change very soon.
-- Luc
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2021-04-17 18:21 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-26 22:04 [PATCH 00/10] simplify and canonicalize signed compares Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 01/10] cmps: make clearer we're using the operands' size Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 02/10] cmps: fix simplification of sext(x) + signed compare of {SMAX,SMIN} Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 03/10] cmpu: fix canonicalization of unsigned (x {<,>=} C) --> (x {<=,>} C-1) Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 04/10] cmps: add testcases for simplification of signed compares Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 05/10] cmps: simplify signed compares with SMIN or SMAX Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 06/10] cmps: canonicalize signed compares with SMIN/SMAX Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 07/10] cmps: canonicalize SMIN/SMAX +- 1 --> EQ/NE Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 08/10] cmps: canonicalize signed compares with constant Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 09/10] cmps: canonicalize SEL(x {<,<=} y, a, b) --> SEL(x {>=,>} y, b, a) Luc Van Oostenryck
2021-01-26 22:04 ` [PATCH 10/10] cmps: canonicalize SEL(x > 0, a, -a) --> SEL(x >= 0, a, -a) Luc Van Oostenryck
2021-04-17 17:16 ` [PATCH 00/10] simplify and canonicalize signed compares Linus Torvalds
2021-04-17 18:20 ` Luc Van Oostenryck
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).