comparison gcc/sort.cc @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
comparison
equal deleted inserted replaced
131:84e7813d76e9 145:1830386684a0
1 /* Platform-independent deterministic sort function. 1 /* Platform-independent deterministic sort function.
2 Copyright (C) 2018 Free Software Foundation, Inc. 2 Copyright (C) 2018-2020 Free Software Foundation, Inc.
3 Contributed by Alexander Monakov. 3 Contributed by Alexander Monakov.
4 4
5 This file is part of GCC. 5 This file is part of GCC.
6 6
7 GCC is free software; you can redistribute it and/or modify it 7 GCC is free software; you can redistribute it and/or modify it
56 size_t n; // number of elements 56 size_t n; // number of elements
57 size_t size; // element size 57 size_t size; // element size
58 size_t nlim; // limit for network sort 58 size_t nlim; // limit for network sort
59 }; 59 };
60 60
61 /* Like sort_ctx, but for use with qsort_r-style comparators. Several
62 functions in this file are templates that work with either context type. */
63 struct sort_r_ctx
64 {
65 void *data;
66 sort_r_cmp_fn *cmp_;
67 char *out;
68 size_t n;
69 size_t size;
70 size_t nlim;
71 int cmp (const void *a, const void *b)
72 {
73 return cmp_ (a, b, data);
74 }
75 };
76
61 /* Helper for netsort. Permute, possibly in-place, 2 or 3 elements, 77 /* Helper for netsort. Permute, possibly in-place, 2 or 3 elements,
62 placing E0 to C->OUT, E1 to C->OUT + C->SIZE, and so on. */ 78 placing E0 to C->OUT, E1 to C->OUT + C->SIZE, and so on. */
79 template<typename sort_ctx>
63 static void 80 static void
64 reorder23 (sort_ctx *c, char *e0, char *e1, char *e2) 81 reorder23 (sort_ctx *c, char *e0, char *e1, char *e2)
65 { 82 {
66 #define REORDER_23(TYPE, STRIDE, OFFSET) \ 83 #define REORDER_23(TYPE, STRIDE, OFFSET) \
67 do { \ 84 do { \
88 REORDER_23 (char, c->size, offset); 105 REORDER_23 (char, c->size, offset);
89 } 106 }
90 } 107 }
91 108
92 /* Like reorder23, but permute 4 or 5 elements. */ 109 /* Like reorder23, but permute 4 or 5 elements. */
110 template<typename sort_ctx>
93 static void 111 static void
94 reorder45 (sort_ctx *c, char *e0, char *e1, char *e2, char *e3, char *e4) 112 reorder45 (sort_ctx *c, char *e0, char *e1, char *e2, char *e3, char *e4)
95 { 113 {
96 #define REORDER_45(TYPE, STRIDE, OFFSET) \ 114 #define REORDER_45(TYPE, STRIDE, OFFSET) \
97 do { \ 115 do { \
125 143
126 /* Helper for netsort. Invoke comparator CMP on E0 and E1. 144 /* Helper for netsort. Invoke comparator CMP on E0 and E1.
127 Return E0^E1 if E0 compares less than E1, zero otherwise. 145 Return E0^E1 if E0 compares less than E1, zero otherwise.
128 This is noinline to avoid code growth and confine invocation 146 This is noinline to avoid code growth and confine invocation
129 to a single call site, assisting indirect branch prediction. */ 147 to a single call site, assisting indirect branch prediction. */
148 template<typename sort_ctx>
130 noinline static intptr_t 149 noinline static intptr_t
131 cmp1 (char *e0, char *e1, cmp_fn *cmp) 150 cmp1 (char *e0, char *e1, sort_ctx *c)
132 { 151 {
133 intptr_t x = (intptr_t)e0 ^ (intptr_t)e1; 152 intptr_t x = (intptr_t)e0 ^ (intptr_t)e1;
134 return x & (cmp (e0, e1) >> 31); 153 return x & (c->cmp (e0, e1) >> 31);
135 } 154 }
136 155
137 /* Execute network sort on 2 to 5 elements from IN, placing them into C->OUT. 156 /* Execute network sort on 2 to 5 elements from IN, placing them into C->OUT.
138 IN may be equal to C->OUT, in which case elements are sorted in place. */ 157 IN may be equal to C->OUT, in which case elements are sorted in place. */
158 template<typename sort_ctx>
139 static void 159 static void
140 netsort (char *in, sort_ctx *c) 160 netsort (char *in, sort_ctx *c)
141 { 161 {
142 #define CMP(e0, e1) \ 162 #define CMP(e0, e1) \
143 do { \ 163 do { \
144 intptr_t x = cmp1 (e1, e0, c->cmp); \ 164 intptr_t x = cmp1 (e1, e0, c); \
145 e0 = (char *)((intptr_t)e0 ^ x); \ 165 e0 = (char *)((intptr_t)e0 ^ x); \
146 e1 = (char *)((intptr_t)e1 ^ x); \ 166 e1 = (char *)((intptr_t)e1 ^ x); \
147 } while (0) 167 } while (0)
148 168
149 char *e0 = in, *e1 = e0 + c->size, *e2 = e1 + c->size; 169 char *e0 = in, *e1 = e0 + c->size, *e2 = e1 + c->size;
174 } 194 }
175 195
176 /* Execute merge sort on N elements from IN, placing them into OUT, 196 /* Execute merge sort on N elements from IN, placing them into OUT,
177 using TMP as temporary storage if IN is equal to OUT. 197 using TMP as temporary storage if IN is equal to OUT.
178 This is a stable sort if netsort is used only for 2 or 3 elements. */ 198 This is a stable sort if netsort is used only for 2 or 3 elements. */
199 template<typename sort_ctx>
179 static void 200 static void
180 mergesort (char *in, sort_ctx *c, size_t n, char *out, char *tmp) 201 mergesort (char *in, sort_ctx *c, size_t n, char *out, char *tmp)
181 { 202 {
182 if (likely (n <= c->nlim)) 203 if (likely (n <= c->nlim))
183 { 204 {
215 MERGE_ELTSIZE (c->size); 236 MERGE_ELTSIZE (c->size);
216 } 237 }
217 memcpy (out, l, r - out); 238 memcpy (out, l, r - out);
218 } 239 }
219 240
241 #if CHECKING_P
242 /* Adapter for using two-argument comparators in functions expecting the
243 three-argument sort_r_cmp_fn type. */
244 static int
245 cmp2to3 (const void *a, const void *b, void *c)
246 {
247 return ((cmp_fn *)c) (a, b);
248 }
249 #endif
250
251 /* Replacement for C qsort. */
220 void 252 void
221 gcc_qsort (void *vbase, size_t n, size_t size, cmp_fn *cmp) 253 gcc_qsort (void *vbase, size_t n, size_t size, cmp_fn *cmp)
222 { 254 {
223 if (n < 2) 255 if (n < 2)
224 return; 256 return;
233 void *buf = bufsz <= sizeof scratch ? scratch : xmalloc (bufsz); 265 void *buf = bufsz <= sizeof scratch ? scratch : xmalloc (bufsz);
234 mergesort (base, &c, n, base, (char *)buf); 266 mergesort (base, &c, n, base, (char *)buf);
235 if (buf != scratch) 267 if (buf != scratch)
236 free (buf); 268 free (buf);
237 #if CHECKING_P 269 #if CHECKING_P
238 qsort_chk (vbase, n, size, cmp); 270 qsort_chk (vbase, n, size, cmp2to3, (void*)cmp);
239 #endif 271 #endif
240 } 272 }
241 273
274 /* Substitute for Glibc qsort_r. */
275 void
276 gcc_sort_r (void *vbase, size_t n, size_t size, sort_r_cmp_fn *cmp, void *data)
277 {
278 if (n < 2)
279 return;
280 char *base = (char *)vbase;
281 sort_r_ctx c = {data, cmp, base, n, size, 5};
282 long long scratch[32];
283 size_t bufsz = (n / 2) * size;
284 void *buf = bufsz <= sizeof scratch ? scratch : xmalloc (bufsz);
285 mergesort (base, &c, n, base, (char *)buf);
286 if (buf != scratch)
287 free (buf);
288 #if CHECKING_P
289 qsort_chk (vbase, n, size, cmp, data);
290 #endif
291 }
292
293 /* Stable sort, signature-compatible to C qsort. */
242 void 294 void
243 gcc_stablesort (void *vbase, size_t n, size_t size, cmp_fn *cmp) 295 gcc_stablesort (void *vbase, size_t n, size_t size, cmp_fn *cmp)
244 { 296 {
245 gcc_qsort (vbase, n, ~size, cmp); 297 gcc_qsort (vbase, n, ~size, cmp);
246 } 298 }