--- /dev/null	Mon Nov 18 13:18:58 2019
+++ new/usr/src/tools/smatch/src/ir.c	Mon Nov 18 13:18:58 2019
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: MIT
+
+#include "ir.h"
+#include "linearize.h"
+#include <stdlib.h>
+#include <assert.h>
+
+
+static int nbr_phi_operands(struct instruction *insn)
+{
+	pseudo_t p;
+	int nbr = 0;
+
+	if (!insn->phi_list)
+		return 0;
+
+	FOR_EACH_PTR(insn->phi_list, p) {
+		if (p == VOID)
+			continue;
+		nbr++;
+	} END_FOR_EACH_PTR(p);
+
+	return nbr;
+}
+
+static int check_phi_node(struct instruction *insn)
+{
+	struct basic_block *par;
+	pseudo_t phi;
+	int err = 0;
+
+	if (!has_users(insn->target))
+		return err;
+
+	if (bb_list_size(insn->bb->parents) != nbr_phi_operands(insn)) {
+		sparse_error(insn->pos, "bad number of phi operands in:\n\t%s",
+			show_instruction(insn));
+		info(insn->pos, "parents: %d", bb_list_size(insn->bb->parents));
+		info(insn->pos, "phisrcs: %d", nbr_phi_operands(insn));
+		return 1;
+	}
+
+	PREPARE_PTR_LIST(insn->bb->parents, par);
+	FOR_EACH_PTR(insn->phi_list, phi) {
+		struct instruction *src;
+		if (phi == VOID)
+			continue;
+		assert(phi->type == PSEUDO_PHI);
+		src = phi->def;
+		if (src->bb != par) {
+			sparse_error(src->pos, "wrong BB for %s:", show_instruction(src));
+			info(src->pos, "expected: %s", show_label(par));
+			info(src->pos, "     got: %s", show_label(src->bb));
+			err++;
+		}
+		NEXT_PTR_LIST(par);
+	} END_FOR_EACH_PTR(phi);
+	FINISH_PTR_LIST(par);
+	return err;
+}
+
+static int check_user(struct instruction *insn, pseudo_t pseudo)
+{
+	struct instruction *def;
+
+	if (!pseudo) {
+		show_entry(insn->bb->ep);
+		sparse_error(insn->pos, "null pseudo in %s", show_instruction(insn));
+		return 1;
+	}
+	switch (pseudo->type) {
+	case PSEUDO_PHI:
+	case PSEUDO_REG:
+		def = pseudo->def;
+		if (def && def->bb)
+			break;
+		show_entry(insn->bb->ep);
+		sparse_error(insn->pos, "wrong usage for %s in %s", show_pseudo(pseudo),
+			show_instruction(insn));
+		return 1;
+
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int check_branch(struct entrypoint *ep, struct instruction *insn, struct basic_block *bb)
+{
+	if (bb->ep && lookup_bb(ep->bbs, bb))
+		return 0;
+	sparse_error(insn->pos, "branch to dead BB: %s", show_instruction(insn));
+	return 1;
+}
+
+static int check_switch(struct entrypoint *ep, struct instruction *insn)
+{
+	struct multijmp *jmp;
+	int err = 0;
+
+	FOR_EACH_PTR(insn->multijmp_list, jmp) {
+		err = check_branch(ep, insn, jmp->target);
+		if (err)
+			return err;
+	} END_FOR_EACH_PTR(jmp);
+
+	return err;
+}
+
+static int check_return(struct instruction *insn)
+{
+	struct symbol *ctype = insn->type;
+
+	if (ctype && ctype->bit_size > 0 && insn->src == VOID) {
+		sparse_error(insn->pos, "return without value");
+		return 1;
+	}
+	return 0;
+}
+
+static int validate_insn(struct entrypoint *ep, struct instruction *insn)
+{
+	int err = 0;
+
+	switch (insn->opcode) {
+	case OP_SEL:
+	case OP_RANGE:
+		err += check_user(insn, insn->src3);
+		/* fall through */
+
+	case OP_BINARY ... OP_BINCMP_END:
+		err += check_user(insn, insn->src2);
+		/* fall through */
+
+	case OP_UNOP ... OP_UNOP_END:
+	case OP_SLICE:
+	case OP_SYMADDR:
+	case OP_PHISOURCE:
+		err += check_user(insn, insn->src1);
+		break;
+
+	case OP_CBR:
+		err += check_branch(ep, insn, insn->bb_true);
+		err += check_branch(ep, insn, insn->bb_false);
+		/* fall through */
+	case OP_COMPUTEDGOTO:
+		err += check_user(insn, insn->cond);
+		break;
+
+	case OP_PHI:
+		err += check_phi_node(insn);
+		break;
+
+	case OP_CALL:
+		// FIXME: ignore for now
+		break;
+
+	case OP_STORE:
+		err += check_user(insn, insn->target);
+		/* fall through */
+
+	case OP_LOAD:
+		err += check_user(insn, insn->src);
+		break;
+
+	case OP_RET:
+		err += check_return(insn);
+		break;
+
+	case OP_BR:
+		err += check_branch(ep, insn, insn->bb_true);
+		break;
+	case OP_SWITCH:
+		err += check_switch(ep, insn);
+		break;
+
+	case OP_ENTRY:
+	case OP_SETVAL:
+	default:
+		break;
+	}
+
+	return err;
+}
+
+int ir_validate(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+	int err = 0;
+
+	if (!dbg_ir || has_error)
+		return 0;
+
+	FOR_EACH_PTR(ep->bbs, bb) {
+		struct instruction *insn;
+		FOR_EACH_PTR(bb->insns, insn) {
+			if (!insn->bb)
+				continue;
+			err += validate_insn(ep, insn);
+		} END_FOR_EACH_PTR(insn);
+	} END_FOR_EACH_PTR(bb);
+
+	if (err)
+		abort();
+	return err;
+}
