--- /dev/null	Fri Dec 21 15:00:38 2018
+++ new/usr/src/tools/smatch/src/storage.c	Fri Dec 21 15:00:38 2018
@@ -0,0 +1,307 @@
+/*
+ * Storage - associate pseudos with "storage" that keeps them alive
+ * between basic blocks.  The aim is to be able to turn as much of
+ * the global storage allocation problem as possible into a local
+ * per-basic-block one.
+ *
+ * Copyright (C) 2004 Linus Torvalds
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "symbol.h"
+#include "expression.h"
+#include "linearize.h"
+#include "storage.h"
+
+ALLOCATOR(storage, "storages");
+ALLOCATOR(storage_hash, "storage hash");
+
+#define MAX_STORAGE_HASH 64
+static struct storage_hash_list *storage_hash_table[MAX_STORAGE_HASH];
+
+static inline unsigned int storage_hash(struct basic_block *bb, pseudo_t pseudo, enum inout_enum inout)
+{
+	unsigned hash = hashval(bb) + hashval(pseudo) + hashval(inout);
+	hash += hash / MAX_STORAGE_HASH;
+	return hash & (MAX_STORAGE_HASH-1);
+}
+
+static int hash_list_cmp(const void *_a, const void *_b)
+{
+	const struct storage_hash *a = _a;
+	const struct storage_hash *b = _b;
+	if (a->pseudo != b->pseudo)
+		return a->pseudo < b->pseudo ? -1 : 1;
+	return 0;
+}
+
+static void sort_hash_list(struct storage_hash_list **listp)
+{
+	sort_list((struct ptr_list **)listp, hash_list_cmp);
+}
+
+struct storage_hash_list *gather_storage(struct basic_block *bb, enum inout_enum inout)
+{
+	int i;
+	struct storage_hash *entry, *prev;
+	struct storage_hash_list *list = NULL;
+
+	for (i = 0; i < MAX_STORAGE_HASH; i++) {
+		struct storage_hash *hash;
+		FOR_EACH_PTR(storage_hash_table[i], hash) {
+			if (hash->bb == bb && hash->inout == inout)
+				add_ptr_list(&list, hash);
+		} END_FOR_EACH_PTR(hash);
+	}
+	sort_hash_list(&list);
+
+	prev = NULL;
+	FOR_EACH_PTR(list, entry) {
+		if (prev && entry->pseudo == prev->pseudo) {
+			assert(entry == prev);
+			DELETE_CURRENT_PTR(entry);
+		}
+		prev = entry;
+	} END_FOR_EACH_PTR(entry);
+	PACK_PTR_LIST(&list);
+	return list;
+}
+
+static void name_storage(void)
+{
+	int i;
+	int name = 0;
+
+	for (i = 0; i < MAX_STORAGE_HASH; i++) {
+		struct storage_hash *hash;
+		FOR_EACH_PTR(storage_hash_table[i], hash) {
+			struct storage *storage = hash->storage;
+			if (storage->name)
+				continue;
+			storage->name = ++name;
+		} END_FOR_EACH_PTR(hash);
+	}
+}
+
+struct storage *lookup_storage(struct basic_block *bb, pseudo_t pseudo, enum inout_enum inout)
+{
+	struct storage_hash_list *list = storage_hash_table[storage_hash(bb,pseudo,inout)];
+	struct storage_hash *hash;
+
+	FOR_EACH_PTR(list, hash) {
+		if (hash->bb == bb && hash->pseudo == pseudo && hash->inout == inout)
+			return hash->storage;
+	} END_FOR_EACH_PTR(hash);
+	return NULL;
+}
+
+void add_storage(struct storage *storage, struct basic_block *bb, pseudo_t pseudo, enum inout_enum inout)
+{
+	struct storage_hash_list **listp = storage_hash_table + storage_hash(bb,pseudo,inout);
+	struct storage_hash *hash = alloc_storage_hash(storage);
+
+	hash->bb = bb;
+	hash->pseudo = pseudo;
+	hash->inout = inout;
+
+	add_ptr_list(listp, hash);
+}
+
+
+static int storage_hash_cmp(const void *_a, const void *_b)
+{
+	const struct storage_hash *a = _a;
+	const struct storage_hash *b = _b;
+	struct storage *aa = a->storage;
+	struct storage *bb = b->storage;
+
+	if (a->bb != b->bb)
+		return a->bb < b->bb ? -1 : 1;
+	if (a->inout != b->inout)
+		return a->inout < b->inout ? -1 : 1;
+	if (aa->type != bb->type)
+		return aa->type < bb->type ? -1 : 1;
+	if (aa->regno != bb->regno)
+		return aa->regno < bb->regno ? -1 : 1;
+	return 0;
+}
+
+static void vrfy_storage(struct storage_hash_list **listp)
+{
+	struct storage_hash *entry, *last;
+
+	sort_list((struct ptr_list **)listp, storage_hash_cmp);
+	last = NULL;
+	FOR_EACH_PTR(*listp, entry) {
+		if (last) {
+			struct storage *a = last->storage;
+			struct storage *b = entry->storage;
+			if (a == b)
+				continue;
+			if (last->bb == entry->bb
+			    && last->inout == entry->inout
+			    && a->type != REG_UDEF
+			    && a->type == b->type
+			    && a->regno == b->regno) {
+				printf("\t BAD: same storage as %s in %p: %s (%s and %s)\n",
+					last->inout == STOR_IN ? "input" : "output",
+					last->bb,
+					show_storage(a),
+					show_pseudo(last->pseudo),
+					show_pseudo(entry->pseudo));
+			}
+		}
+		last = entry;
+	} END_FOR_EACH_PTR(entry);
+}
+
+void free_storage(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_STORAGE_HASH; i++) {
+		vrfy_storage(storage_hash_table + i);
+		free_ptr_list(storage_hash_table + i);
+	}
+}
+
+const char *show_storage(struct storage *s)
+{
+	static char buffer[1024];
+	if (!s)
+		return "none";
+	switch (s->type) {
+	case REG_REG:
+		sprintf(buffer, "reg%d (%d)", s->regno, s->name);
+		break;
+	case REG_STACK:
+		sprintf(buffer, "%d(SP) (%d)", s->offset, s->name);
+		break;
+	case REG_ARG:
+		sprintf(buffer, "ARG%d (%d)", s->regno, s->name);
+		break;
+	default:
+		sprintf(buffer, "%d:%d (%d)", s->type, s->regno, s->name);
+		break;
+	}
+	return buffer;
+}
+
+/*
+ * Combine two storage allocations into one.
+ *
+ * We just randomly pick one over the other, and replace
+ * the other uses.
+ */
+static struct storage * combine_storage(struct storage *src, struct storage *dst)
+{
+	struct storage **usep;
+
+	/* Remove uses of "src_storage", replace with "dst" */
+	FOR_EACH_PTR(src->users, usep) {
+		assert(*usep == src);
+		*usep = dst;
+		add_ptr_list(&dst->users, usep);
+	} END_FOR_EACH_PTR(usep);
+
+	/* Mark it unused */
+	src->type = REG_BAD;
+	src->users = NULL;
+	return dst;
+}
+
+static void set_up_bb_storage(struct basic_block *bb)
+{
+	struct basic_block *child;
+
+	FOR_EACH_PTR(bb->children, child) {
+		pseudo_t pseudo;
+		FOR_EACH_PTR(child->needs, pseudo) {
+			struct storage *child_in, *parent_out;
+
+			parent_out = lookup_storage(bb, pseudo, STOR_OUT);
+			child_in = lookup_storage(child, pseudo, STOR_IN);
+
+			if (parent_out) {
+				if (!child_in) {
+					add_storage(parent_out, child, pseudo, STOR_IN);
+					continue;
+				}
+				if (parent_out == child_in)
+					continue;
+				combine_storage(parent_out, child_in);
+				continue;
+			}
+			if (child_in) {
+				add_storage(child_in, bb, pseudo, STOR_OUT);
+				continue;
+			}
+			parent_out = alloc_storage();
+			add_storage(parent_out, bb, pseudo, STOR_OUT);
+			add_storage(parent_out, child, pseudo, STOR_IN);
+		} END_FOR_EACH_PTR(pseudo);
+	} END_FOR_EACH_PTR(child);
+}
+
+static void set_up_argument_storage(struct entrypoint *ep, struct basic_block *bb)
+{
+	pseudo_t arg;
+
+	FOR_EACH_PTR(bb->needs, arg) {
+		struct storage *storage = alloc_storage();
+
+		/* FIXME! Totally made-up argument passing conventions */
+		if (arg->type == PSEUDO_ARG) {
+			storage->type = REG_ARG;
+			storage->regno = arg->nr;
+		}
+		add_storage(storage, bb, arg, STOR_IN);
+	} END_FOR_EACH_PTR(arg);
+}
+
+/*
+ * One phi-source may feed multiple phi nodes. If so, combine
+ * the storage output for this bb into one entry to reduce
+ * storage pressure.
+ */
+static void combine_phi_storage(struct basic_block *bb)
+{
+	struct instruction *insn;
+	FOR_EACH_PTR(bb->insns, insn) {
+		struct instruction *phi;
+		struct storage *last;
+
+		if (!insn->bb || insn->opcode != OP_PHISOURCE)
+			continue;
+		last = NULL;
+		FOR_EACH_PTR(insn->phi_users, phi) {
+			struct storage *storage = lookup_storage(bb, phi->target, STOR_OUT);
+			if (!storage) {
+				DELETE_CURRENT_PTR(phi);
+				continue;
+			}
+			if (last && storage != last)
+				storage = combine_storage(storage, last);
+			last = storage;
+		} END_FOR_EACH_PTR(phi);
+		PACK_PTR_LIST(&insn->phi_users);
+	} END_FOR_EACH_PTR(insn);
+}
+
+void set_up_storage(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+
+	/* First set up storage for the incoming arguments */
+	set_up_argument_storage(ep, ep->entry->bb);
+
+	/* Then do a list of all the inter-bb storage */
+	FOR_EACH_PTR(ep->bbs, bb) {
+		set_up_bb_storage(bb);
+		combine_phi_storage(bb);
+	} END_FOR_EACH_PTR(bb);
+
+	name_storage();
+}
