Commit ce0454d9 by Alexander Monakov Committed by Alexander Monakov

sort.cc: introduce gcc_sort_r

	* sort.cc (sort_r_ctx): New struct.
	(reorder23): Make templated on context type.
	(reorder45): Ditto.
	(cmp1): Ditto.  Adjust signature.
	(netsort): Ditto.
	(mergesort): Ditto.
	[CHECKING_P] (cmp2to3): New static function.  Use it...
	(gcc_qsort) [CHECKING_P]: ...here.
	(gcc_sort_r): New function.
	* system.h (sort_r_cmp_fn): New function typedef.
	(qsort_chk): Adjust signature.
	(gcc_sort_r): Declare.
	* vec.c (qsort_chk_error): Adjust.
	(qsort_chk): Adjust.

From-SVN: r273977
parent f339eb66
2019-08-01 Alexander Monakov <amonakov@ispras.ru>
* sort.cc (sort_r_ctx): New struct.
(reorder23): Make templated on context type.
(reorder45): Ditto.
(cmp1): Ditto. Adjust signature.
(netsort): Ditto.
(mergesort): Ditto.
[CHECKING_P] (cmp2to3): New static function. Use it...
(gcc_qsort) [CHECKING_P]: ...here.
(gcc_sort_r): New function.
* system.h (sort_r_cmp_fn): New function typedef.
(qsort_chk): Adjust signature.
(gcc_sort_r): Declare.
* vec.c (qsort_chk_error): Adjust.
(qsort_chk): Adjust.
2019-08-01 Richard Biener <rguenther@suse.de> 2019-08-01 Richard Biener <rguenther@suse.de>
* tree-ssa-pre.c (has_abnormal_preds): Remove global var. * tree-ssa-pre.c (has_abnormal_preds): Remove global var.
......
...@@ -58,8 +58,25 @@ struct sort_ctx ...@@ -58,8 +58,25 @@ struct sort_ctx
size_t nlim; // limit for network sort size_t nlim; // limit for network sort
}; };
/* Like sort_ctx, but for use with qsort_r-style comparators. Several
functions in this file are templates that work with either context type. */
struct sort_r_ctx
{
void *data;
sort_r_cmp_fn *cmp_;
char *out;
size_t n;
size_t size;
size_t nlim;
int cmp (const void *a, const void *b)
{
return cmp_ (a, b, data);
}
};
/* Helper for netsort. Permute, possibly in-place, 2 or 3 elements, /* Helper for netsort. Permute, possibly in-place, 2 or 3 elements,
placing E0 to C->OUT, E1 to C->OUT + C->SIZE, and so on. */ placing E0 to C->OUT, E1 to C->OUT + C->SIZE, and so on. */
template<typename sort_ctx>
static void static void
reorder23 (sort_ctx *c, char *e0, char *e1, char *e2) reorder23 (sort_ctx *c, char *e0, char *e1, char *e2)
{ {
...@@ -90,6 +107,7 @@ do { \ ...@@ -90,6 +107,7 @@ do { \
} }
/* Like reorder23, but permute 4 or 5 elements. */ /* Like reorder23, but permute 4 or 5 elements. */
template<typename sort_ctx>
static void static void
reorder45 (sort_ctx *c, char *e0, char *e1, char *e2, char *e3, char *e4) reorder45 (sort_ctx *c, char *e0, char *e1, char *e2, char *e3, char *e4)
{ {
...@@ -127,21 +145,23 @@ do { \ ...@@ -127,21 +145,23 @@ do { \
Return E0^E1 if E0 compares less than E1, zero otherwise. Return E0^E1 if E0 compares less than E1, zero otherwise.
This is noinline to avoid code growth and confine invocation This is noinline to avoid code growth and confine invocation
to a single call site, assisting indirect branch prediction. */ to a single call site, assisting indirect branch prediction. */
template<typename sort_ctx>
noinline static intptr_t noinline static intptr_t
cmp1 (char *e0, char *e1, cmp_fn *cmp) cmp1 (char *e0, char *e1, sort_ctx *c)
{ {
intptr_t x = (intptr_t)e0 ^ (intptr_t)e1; intptr_t x = (intptr_t)e0 ^ (intptr_t)e1;
return x & (cmp (e0, e1) >> 31); return x & (c->cmp (e0, e1) >> 31);
} }
/* Execute network sort on 2 to 5 elements from IN, placing them into C->OUT. /* Execute network sort on 2 to 5 elements from IN, placing them into C->OUT.
IN may be equal to C->OUT, in which case elements are sorted in place. */ IN may be equal to C->OUT, in which case elements are sorted in place. */
template<typename sort_ctx>
static void static void
netsort (char *in, sort_ctx *c) netsort (char *in, sort_ctx *c)
{ {
#define CMP(e0, e1) \ #define CMP(e0, e1) \
do { \ do { \
intptr_t x = cmp1 (e1, e0, c->cmp); \ intptr_t x = cmp1 (e1, e0, c); \
e0 = (char *)((intptr_t)e0 ^ x); \ e0 = (char *)((intptr_t)e0 ^ x); \
e1 = (char *)((intptr_t)e1 ^ x); \ e1 = (char *)((intptr_t)e1 ^ x); \
} while (0) } while (0)
...@@ -176,6 +196,7 @@ do { \ ...@@ -176,6 +196,7 @@ do { \
/* Execute merge sort on N elements from IN, placing them into OUT, /* Execute merge sort on N elements from IN, placing them into OUT,
using TMP as temporary storage if IN is equal to OUT. using TMP as temporary storage if IN is equal to OUT.
This is a stable sort if netsort is used only for 2 or 3 elements. */ This is a stable sort if netsort is used only for 2 or 3 elements. */
template<typename sort_ctx>
static void static void
mergesort (char *in, sort_ctx *c, size_t n, char *out, char *tmp) mergesort (char *in, sort_ctx *c, size_t n, char *out, char *tmp)
{ {
...@@ -217,6 +238,17 @@ do { \ ...@@ -217,6 +238,17 @@ do { \
memcpy (out, l, r - out); memcpy (out, l, r - out);
} }
#if CHECKING_P
/* Adapter for using two-argument comparators in functions expecting the
three-argument sort_r_cmp_fn type. */
static int
cmp2to3 (const void *a, const void *b, void *c)
{
return ((cmp_fn *)c) (a, b);
}
#endif
/* Replacement for C qsort. */
void void
gcc_qsort (void *vbase, size_t n, size_t size, cmp_fn *cmp) gcc_qsort (void *vbase, size_t n, size_t size, cmp_fn *cmp)
{ {
...@@ -235,10 +267,30 @@ gcc_qsort (void *vbase, size_t n, size_t size, cmp_fn *cmp) ...@@ -235,10 +267,30 @@ gcc_qsort (void *vbase, size_t n, size_t size, cmp_fn *cmp)
if (buf != scratch) if (buf != scratch)
free (buf); free (buf);
#if CHECKING_P #if CHECKING_P
qsort_chk (vbase, n, size, cmp); qsort_chk (vbase, n, size, cmp2to3, (void*)cmp);
#endif
}
/* Substitute for Glibc qsort_r. */
void
gcc_sort_r (void *vbase, size_t n, size_t size, sort_r_cmp_fn *cmp, void *data)
{
if (n < 2)
return;
char *base = (char *)vbase;
sort_r_ctx c = {data, cmp, base, n, size, 5};
long long scratch[32];
size_t bufsz = (n / 2) * size;
void *buf = bufsz <= sizeof scratch ? scratch : xmalloc (bufsz);
mergesort (base, &c, n, base, (char *)buf);
if (buf != scratch)
free (buf);
#if CHECKING_P
qsort_chk (vbase, n, size, cmp, data);
#endif #endif
} }
/* Stable sort, signature-compatible to C qsort. */
void void
gcc_stablesort (void *vbase, size_t n, size_t size, cmp_fn *cmp) gcc_stablesort (void *vbase, size_t n, size_t size, cmp_fn *cmp)
{ {
......
...@@ -1197,13 +1197,14 @@ helper_const_non_const_cast (const char *p) ...@@ -1197,13 +1197,14 @@ helper_const_non_const_cast (const char *p)
/* Get definitions of HOST_WIDE_INT. */ /* Get definitions of HOST_WIDE_INT. */
#include "hwint.h" #include "hwint.h"
/* GCC qsort API-compatible functions: except in release-checking compilers, typedef int sort_r_cmp_fn (const void *, const void *, void *);
redirect 4-argument qsort calls to gcc_qsort; keep 1-argument invocations void qsort_chk (void *, size_t, size_t, sort_r_cmp_fn *, void *);
corresponding to vec::qsort (cmp): they use C qsort internally anyway. */ void gcc_sort_r (void *, size_t, size_t, sort_r_cmp_fn *, void *);
void qsort_chk (void *, size_t, size_t, int (*)(const void *, const void *));
void gcc_qsort (void *, size_t, size_t, int (*)(const void *, const void *)); void gcc_qsort (void *, size_t, size_t, int (*)(const void *, const void *));
void gcc_stablesort (void *, size_t, size_t, void gcc_stablesort (void *, size_t, size_t,
int (*)(const void *, const void *)); int (*)(const void *, const void *));
/* Redirect four-argument qsort calls to gcc_qsort; one-argument invocations
correspond to vec::qsort, and use C qsort internally. */
#define PP_5th(a1, a2, a3, a4, a5, ...) a5 #define PP_5th(a1, a2, a3, a4, a5, ...) a5
#undef qsort #undef qsort
#define qsort(...) PP_5th (__VA_ARGS__, gcc_qsort, 3, 2, qsort, 0) (__VA_ARGS__) #define qsort(...) PP_5th (__VA_ARGS__, gcc_qsort, 3, 2, qsort, 0) (__VA_ARGS__)
......
...@@ -192,21 +192,23 @@ dump_vec_loc_statistics (void) ...@@ -192,21 +192,23 @@ dump_vec_loc_statistics (void)
ATTRIBUTE_NORETURN ATTRIBUTE_COLD ATTRIBUTE_NORETURN ATTRIBUTE_COLD
static void static void
qsort_chk_error (const void *p1, const void *p2, const void *p3, qsort_chk_error (const void *p1, const void *p2, const void *p3,
int (*cmp) (const void *, const void *)) sort_r_cmp_fn *cmp, void *data)
{ {
if (!p3) if (!p3)
{ {
int r1 = cmp (p1, p2), r2 = cmp (p2, p1); int r1 = cmp (p1, p2, data), r2 = cmp (p2, p1, data);
error ("qsort comparator not anti-commutative: %d, %d", r1, r2); error ("qsort comparator not anti-symmetric: %d, %d", r1, r2);
} }
else if (p1 == p2) else if (p1 == p2)
{ {
int r = cmp (p1, p3); int r = cmp (p1, p3, data);
error ("qsort comparator non-negative on sorted output: %d", r); error ("qsort comparator non-negative on sorted output: %d", r);
} }
else else
{ {
int r1 = cmp (p1, p2), r2 = cmp (p2, p3), r3 = cmp (p1, p3); int r1 = cmp (p1, p2, data);
int r2 = cmp (p2, p3, data);
int r3 = cmp (p1, p3, data);
error ("qsort comparator not transitive: %d, %d, %d", r1, r2, r3); error ("qsort comparator not transitive: %d, %d, %d", r1, r2, r3);
} }
internal_error ("qsort checking failed"); internal_error ("qsort checking failed");
...@@ -215,8 +217,7 @@ qsort_chk_error (const void *p1, const void *p2, const void *p3, ...@@ -215,8 +217,7 @@ qsort_chk_error (const void *p1, const void *p2, const void *p3,
/* Verify anti-symmetry and transitivity for comparator CMP on sorted array /* Verify anti-symmetry and transitivity for comparator CMP on sorted array
of N SIZE-sized elements pointed to by BASE. */ of N SIZE-sized elements pointed to by BASE. */
void void
qsort_chk (void *base, size_t n, size_t size, qsort_chk (void *base, size_t n, size_t size, sort_r_cmp_fn *cmp, void *data)
int (*cmp)(const void *, const void *))
{ {
#if 0 #if 0
#define LIM(n) (n) #define LIM(n) (n)
...@@ -225,9 +226,9 @@ qsort_chk (void *base, size_t n, size_t size, ...@@ -225,9 +226,9 @@ qsort_chk (void *base, size_t n, size_t size,
#define LIM(n) ((n) <= 16 ? (n) : 12 + floor_log2 (n)) #define LIM(n) ((n) <= 16 ? (n) : 12 + floor_log2 (n))
#endif #endif
#define ELT(i) ((const char *) base + (i) * size) #define ELT(i) ((const char *) base + (i) * size)
#define CMP(i, j) cmp (ELT (i), ELT (j)) #define CMP(i, j) cmp (ELT (i), ELT (j), data)
#define ERR2(i, j) qsort_chk_error (ELT (i), ELT (j), NULL, cmp) #define ERR2(i, j) qsort_chk_error (ELT (i), ELT (j), NULL, cmp, data)
#define ERR3(i, j, k) qsort_chk_error (ELT (i), ELT (j), ELT (k), cmp) #define ERR3(i, j, k) qsort_chk_error (ELT (i), ELT (j), ELT (k), cmp, data)
size_t i1, i2, i, j; size_t i1, i2, i, j;
/* This outer loop iterates over maximum spans [i1, i2) such that /* This outer loop iterates over maximum spans [i1, i2) such that
elements within each span compare equal to each other. */ elements within each span compare equal to each other. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment