--- /dev/null	Fri Dec 21 15:00:37 2018
+++ new/usr/src/tools/smatch/src/sort.c	Fri Dec 21 15:00:37 2018
@@ -0,0 +1,290 @@
+/*
+ * sort_list: a stable sort for lists.
+ *
+ * Time complexity: O(n*log n)
+ *   [assuming limited zero-element fragments]
+ *
+ * Space complexity: O(1).
+ *
+ * Stable: yes.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib.h"
+#include "allocate.h"
+
+#undef PARANOIA
+#undef COVERAGE
+
+#ifdef PARANOIA
+#include <assert.h>
+#else
+#define assert(x)
+#endif
+
+#ifdef COVERAGE
+static unsigned char been_there[256];
+#define BEEN_THERE(_c)					\
+  do {							\
+	if (!been_there[_c]) {				\
+		been_there[_c] = 1;			\
+		printf ("Been there: %c\n", _c);	\
+	}						\
+  } while (0)
+#else
+#define BEEN_THERE(_c) do { } while (0)
+#endif
+
+// Sort one fragment.  LIST_NODE_NR (==29) is a bit too high for my
+// taste for something this simple.  But, hey, it's O(1).
+//
+// I would use libc qsort for this, but its comparison function
+// gets a pointer indirection extra.
+static void array_sort(void **ptr, int nr, int (*cmp)(const void *, const void *))
+{
+	int i;
+	for (i = 1; i < nr; i++) {
+		void *p = ptr[i];
+		if (cmp(ptr[i-1],p) > 0) {
+			int j = i;
+			do {
+				ptr[j] = ptr[j-1];
+				if (!--j)
+					break;
+			} while (cmp(ptr[j-1], p) > 0);
+			ptr[j] = p;
+		}
+	}
+}
+
+#ifdef PARANOIA
+static void verify_seq_sorted (struct ptr_list *l, int n,
+			       int (*cmp)(const void *, const void *))
+{
+	int i = 0;
+	const void *a;
+	struct ptr_list *head = l;
+
+	while (l->nr == 0) {
+		l = l->next;
+		if (--n == 0)
+			return;
+		assert (l != head);
+	}
+
+	a = l->list[0];
+	while (n > 0) {
+		const void *b;
+		if (++i >= l->nr) {
+			i = 0;
+			l = l->next;
+			n--;
+			assert (l != head || n == 0);
+			continue;
+		}
+		b = l->list[i];
+		assert (cmp (a, b) <= 0);
+		a = b;
+	}
+}
+#endif
+
+
+#define FLUSH_TO(b)						\
+  do {								\
+	int nr = (b)->nr;					\
+	assert (nbuf >= nr);					\
+	memcpy ((b)->list, buffer, nr * sizeof (void *));	\
+	nbuf -= nr;						\
+	memmove (buffer, buffer + nr, nbuf * sizeof (void *));	\
+  } while (0)
+
+#define DUMP_TO(b)						\
+  do {								\
+        assert (nbuf <= (b)->nr);				\
+	memcpy ((b)->list, buffer, nbuf * sizeof (void *));	\
+  } while (0)
+
+
+// Merge two already-sorted sequences of blocks:
+//   (b1_1, ..., b1_n)  and  (b2_1, ..., b2_m)
+// Since we may be moving blocks around, we return the new head
+// of the merged list.
+static struct ptr_list *
+merge_block_seqs (struct ptr_list *b1, int n,
+		  struct ptr_list *b2, int m,
+		  int (*cmp)(const void *, const void *))
+{
+	int i1 = 0, i2 = 0;
+	const void *buffer[2 * LIST_NODE_NR];
+	int nbuf = 0;
+	struct ptr_list *newhead = b1;
+
+	// printf ("Merging %d blocks at %p with %d blocks at %p\n", n, b1, m, b2);
+
+	// Skip empty blocks in b2.
+	while (b2->nr == 0) {
+		BEEN_THERE('F');
+		b2 = b2->next;
+		if (--m == 0) {
+			BEEN_THERE('G');
+			return newhead;
+		}
+	}
+
+	// Do a quick skip in case entire blocks from b1 are
+	// already less than smallest element in b2.
+	while (b1->nr == 0 ||
+	       cmp (PTR_ENTRY(b1, b1->nr - 1), PTR_ENTRY(b2,0)) < 0) {
+		// printf ("Skipping whole block.\n");
+		BEEN_THERE('H');
+		b1 = b1->next;
+		if (--n == 0) {
+			BEEN_THERE('I');
+			return newhead;	
+		}
+	}
+
+	while (1) {
+		const void *d1 = PTR_ENTRY(b1,i1);
+		const void *d2 = PTR_ENTRY(b2,i2);
+
+		assert (i1 >= 0 && i1 < b1->nr);
+		assert (i2 >= 0 && i2 < b2->nr);
+		assert (b1 != b2);
+		assert (n > 0);
+		assert (m > 0);
+
+		if (cmp (d1, d2) <= 0) {
+			BEEN_THERE('J');
+			buffer[nbuf++] = d1;
+			// Element from b1 is smaller
+			if (++i1 >= b1->nr) {
+				BEEN_THERE('L');
+				FLUSH_TO(b1);
+				do {
+					b1 = b1->next;
+					if (--n == 0) {
+						BEEN_THERE('O');
+						while (b1 != b2) {
+							BEEN_THERE('P');
+							FLUSH_TO(b1);
+							b1 = b1->next;
+						}
+						assert (nbuf == i2);
+						DUMP_TO(b2);
+						return newhead;
+					}
+				} while (b1->nr == 0);
+				i1 = 0;
+			}
+		} else {
+			BEEN_THERE('K');
+			// Element from b2 is smaller
+			buffer[nbuf++] = d2;
+			if (++i2 >= b2->nr) {
+				struct ptr_list *l = b2;
+				BEEN_THERE('M');
+				// OK, we finished with b2.  Pull it out
+				// and plug it in before b1.
+
+				b2 = b2->next;
+				b2->prev = l->prev;
+				b2->prev->next = b2;
+				l->next = b1;
+				l->prev = b1->prev;
+				l->next->prev = l;
+				l->prev->next = l;
+
+				if (b1 == newhead) {
+					BEEN_THERE('N');
+					newhead = l;
+				}
+
+				FLUSH_TO(l);
+				b2 = b2->prev;
+				do {
+					b2 = b2->next;
+					if (--m == 0) {
+						BEEN_THERE('Q');
+						assert (nbuf == i1);
+						DUMP_TO(b1);
+						return newhead;
+					}
+				} while (b2->nr == 0);
+				i2 = 0;
+			}
+		}
+	}
+}
+
+
+void sort_list(struct ptr_list **plist, int (*cmp)(const void *, const void *))
+{
+	struct ptr_list *head = *plist, *list = head;
+	int blocks = 1;
+
+	if (!head)
+		return;
+
+	// Sort all the sub-lists
+	do {
+		array_sort(list->list, list->nr, cmp);
+#ifdef PARANOIA
+		verify_seq_sorted (list, 1, cmp);
+#endif
+		list = list->next;
+	} while (list != head);
+
+	// Merge the damn things together
+	while (1) {
+		struct ptr_list *block1 = head;
+
+		do {
+			struct ptr_list *block2 = block1;
+			struct ptr_list *next, *newhead;
+			int i;
+
+			for (i = 0; i < blocks; i++) {
+				block2 = block2->next;
+				if (block2 == head) {
+					if (block1 == head) {
+						BEEN_THERE('A');
+						*plist = head;
+						return;
+					}
+					BEEN_THERE('B');
+					goto next_pass;
+				}						
+			}
+
+			next = block2;
+			for (i = 0; i < blocks; ) {
+				next = next->next;
+				i++;
+				if (next == head) {
+					BEEN_THERE('C');
+					break;
+				}
+				BEEN_THERE('D');
+			}
+
+			newhead = merge_block_seqs (block1, blocks,
+						    block2, i,
+						    cmp);
+#ifdef PARANOIA
+			verify_seq_sorted (newhead, blocks + i, cmp);
+#endif
+			if (block1 == head) {
+				BEEN_THERE('E');
+				head = newhead;
+			}
+			block1 = next;
+		} while (block1 != head);
+	next_pass:
+		blocks <<= 1;
+	}
+}
