--- old/usr/src/tools/smatch/src/linearize.h	Mon Nov 18 13:19:00 2019
+++ new/usr/src/tools/smatch/src/linearize.h	Mon Nov 18 13:19:00 2019
@@ -4,11 +4,12 @@
 #include "lib.h"
 #include "allocate.h"
 #include "token.h"
+#include "opcode.h"
 #include "parse.h"
 #include "symbol.h"
+#include "ptrmap.h"
 
 struct instruction;
-DECLARE_PTR_LIST(pseudo_ptr_list, pseudo_t);
 
 struct pseudo_user {
 	struct instruction *insn;
@@ -17,10 +18,12 @@
 
 DECLARE_ALLOCATOR(pseudo_user);
 DECLARE_PTR_LIST(pseudo_user_list, struct pseudo_user);
+DECLARE_PTRMAP(phi_map, struct symbol *, pseudo_t);
 
 
 enum pseudo_type {
 	PSEUDO_VOID,
+	PSEUDO_UNDEF,
 	PSEUDO_REG,
 	PSEUDO_SYM,
 	PSEUDO_VAL,
@@ -30,8 +33,7 @@
 
 struct pseudo {
 	int nr;
-	int size:16;	/* OP_SETVAL only */
-	enum pseudo_type type:8;
+	enum pseudo_type type;
 	struct pseudo_user_list *users;
 	struct ident *ident;
 	union {
@@ -46,9 +48,20 @@
 
 #define VOID (&void_pseudo)
 
+static inline bool is_zero(pseudo_t pseudo)
+{
+	return pseudo->type == PSEUDO_VAL && pseudo->value == 0;
+}
+
+static inline bool is_nonzero(pseudo_t pseudo)
+{
+	return pseudo->type == PSEUDO_VAL && pseudo->value != 0;
+}
+
+
 struct multijmp {
 	struct basic_block *target;
-	int begin, end;
+	long long begin, end;
 };
 
 struct asm_constraint {
@@ -69,27 +82,29 @@
 DECLARE_ALLOCATOR(asm_rules);
 
 struct instruction {
-	unsigned opcode:8,
+	unsigned opcode:7,
+		 tainted:1,
 		 size:24;
 	struct basic_block *bb;
 	struct position pos;
 	struct symbol *type;
+	pseudo_t target;
 	union {
-		pseudo_t target;
-		pseudo_t cond;		/* for branch and switch */
-	};
-	union {
 		struct /* entrypoint */ {
 			struct pseudo_list *arg_list;
 		};
 		struct /* branch */ {
+			pseudo_t cond;
 			struct basic_block *bb_true, *bb_false;
 		};
 		struct /* switch */ {
+			pseudo_t _cond;
 			struct multijmp_list *multijmp_list;
 		};
 		struct /* phi_node */ {
+			pseudo_t phi_var;		// used for SSA conversion
 			struct pseudo_list *phi_list;
+			unsigned int used:1;
 		};
 		struct /* phi source */ {
 			pseudo_t phi_src;
@@ -98,8 +113,12 @@
 		struct /* unops */ {
 			pseudo_t src;
 			struct symbol *orig_type;	/* casts */
-			unsigned int offset;		/* memops */
 		};
+		struct /* memops */ {
+			pseudo_t addr;			/* alias .src */
+			unsigned int offset;
+			unsigned int is_volatile:1;
+		};
 		struct /* binops and sel */ {
 			pseudo_t src1, src2, src3;
 		};
@@ -108,13 +127,15 @@
 			unsigned from, len;
 		};
 		struct /* setval */ {
-			pseudo_t symbol;		/* Subtle: same offset as "src" !! */
 			struct expression *val;
 		};
+		struct /* setfval */ {
+			long double fvalue;
+		};
 		struct /* call */ {
 			pseudo_t func;
 			struct pseudo_list *arguments;
-			struct symbol *fntype;
+			struct symbol_list *fntypes;
 		};
 		struct /* context */ {
 			int increment;
@@ -128,98 +149,6 @@
 	};
 };
 
-enum opcode {
-	OP_BADOP,
-
-	/* Entry */
-	OP_ENTRY,
-
-	/* Terminator */
-	OP_TERMINATOR,
-	OP_RET = OP_TERMINATOR,
-	OP_BR,
-	OP_CBR,
-	OP_SWITCH,
-	OP_INVOKE,
-	OP_COMPUTEDGOTO,
-	OP_UNWIND,
-	OP_TERMINATOR_END = OP_UNWIND,
-	
-	/* Binary */
-	OP_BINARY,
-	OP_ADD = OP_BINARY,
-	OP_SUB,
-	OP_MULU, OP_MULS,
-	OP_DIVU, OP_DIVS,
-	OP_MODU, OP_MODS,
-	OP_SHL,
-	OP_LSR, OP_ASR,
-	
-	/* Logical */
-	OP_AND,
-	OP_OR,
-	OP_XOR,
-	OP_AND_BOOL,
-	OP_OR_BOOL,
-	OP_BINARY_END = OP_OR_BOOL,
-
-	/* Binary comparison */
-	OP_BINCMP,
-	OP_SET_EQ = OP_BINCMP,
-	OP_SET_NE,
-	OP_SET_LE,
-	OP_SET_GE,
-	OP_SET_LT,
-	OP_SET_GT,
-	OP_SET_B,
-	OP_SET_A,
-	OP_SET_BE,
-	OP_SET_AE,
-	OP_BINCMP_END = OP_SET_AE,
-
-	/* Uni */
-	OP_NOT,
-	OP_NEG,
-
-	/* Select - three input values */
-	OP_SEL,
-	
-	/* Memory */
-	OP_MALLOC,
-	OP_FREE,
-	OP_ALLOCA,
-	OP_LOAD,
-	OP_STORE,
-	OP_SETVAL,
-	OP_SYMADDR,
-	OP_GET_ELEMENT_PTR,
-
-	/* Other */
-	OP_PHI,
-	OP_PHISOURCE,
-	OP_CAST,
-	OP_SCAST,
-	OP_FPCAST,
-	OP_PTRCAST,
-	OP_INLINED_CALL,
-	OP_CALL,
-	OP_VANEXT,
-	OP_VAARG,
-	OP_SLICE,
-	OP_SNOP,
-	OP_LNOP,
-	OP_NOP,
-	OP_DEATHNOTE,
-	OP_ASM,
-
-	/* Sparse tagging (line numbers, context, whatever) */
-	OP_CONTEXT,
-	OP_RANGE,
-
-	/* Needed to translate SSA back to normal form */
-	OP_COPY,
-};
-
 struct basic_block_list;
 struct instruction_list;
 
@@ -226,11 +155,18 @@
 struct basic_block {
 	struct position pos;
 	unsigned long generation;
-	int context;
+	union {
+		int context;
+		int postorder_nr;	/* postorder number */
+		int dom_level;		/* level in the dominance tree */
+	};
 	struct entrypoint *ep;
 	struct basic_block_list *parents; /* sources */
 	struct basic_block_list *children; /* destinations */
 	struct instruction_list *insns;	/* Linear list of instructions */
+	struct basic_block *idom;	/* link to the immediate dominator */
+	struct basic_block_list *doms;	/* list of BB idominated by this one */
+	struct phi_map *phi_map;
 	struct pseudo_list *needs, *defines;
 	union {
 		unsigned int nr;	/* unique id for label's names */
@@ -239,6 +175,14 @@
 };
 
 
+//
+// return the opcode of the instruction defining ``SRC`` if existing
+// and OP_BADOP if not. It also assigns the defining instruction
+// to ``DEF``.
+#define DEF_OPCODE(DEF, SRC)	\
+	(((SRC)->type == PSEUDO_REG && (DEF = (SRC)->def)) ? DEF->opcode : OP_BADOP)
+
+
 static inline void add_bb(struct basic_block_list **list, struct basic_block *bb)
 {
 	add_ptr_list(list, bb);
@@ -264,6 +208,11 @@
 	return delete_ptr_list_entry((struct ptr_list **)list, pseudo, 0) != 0;
 }
 
+static inline int pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo)
+{
+	return lookup_ptr_list_entry((struct ptr_list *)list, pseudo);
+}
+
 static inline int bb_terminated(struct basic_block *bb)
 {
 	struct instruction *insn;
@@ -279,11 +228,12 @@
 	return bb != NULL;
 }
 
-static inline void add_pseudo_ptr(pseudo_t *ptr, struct pseudo_ptr_list **list)
+static inline int lookup_bb(struct basic_block_list *list, struct basic_block *bb)
 {
-	add_ptr_list(list, ptr);
+	return lookup_ptr_list_entry((struct ptr_list *)list, bb);
 }
 
+
 static inline void add_pseudo_user_ptr(struct pseudo_user *user, struct pseudo_user_list **list)
 {
 	add_ptr_list(list, user);
@@ -291,9 +241,34 @@
 
 static inline int has_use_list(pseudo_t p)
 {
-	return (p && p->type != PSEUDO_VOID && p->type != PSEUDO_VAL);
+	return (p && p->type != PSEUDO_VOID && p->type != PSEUDO_UNDEF && p->type != PSEUDO_VAL);
 }
 
+static inline int pseudo_user_list_size(struct pseudo_user_list *list)
+{
+	return ptr_list_size((struct ptr_list *)list);
+}
+
+static inline bool pseudo_user_list_empty(struct pseudo_user_list *list)
+{
+	return ptr_list_empty((struct ptr_list *)list);
+}
+
+static inline int has_users(pseudo_t p)
+{
+	return !pseudo_user_list_empty(p->users);
+}
+
+static inline bool multi_users(pseudo_t p)
+{
+	return ptr_list_multiple((struct ptr_list *)(p->users));
+}
+
+static inline int nbr_users(pseudo_t p)
+{
+	return pseudo_user_list_size(p->users);
+}
+
 static inline struct pseudo_user *alloc_pseudo_user(struct instruction *insn, pseudo_t *pp)
 {
 	struct pseudo_user *user = __alloc_pseudo_user(0);
@@ -327,15 +302,21 @@
 	struct basic_block_list *bbs;
 	struct basic_block *active;
 	struct instruction *entry;
+	unsigned int dom_levels;	/* max levels in the dom tree */
 };
 
 extern void insert_select(struct basic_block *bb, struct instruction *br, struct instruction *phi, pseudo_t if_true, pseudo_t if_false);
 extern void insert_branch(struct basic_block *bb, struct instruction *br, struct basic_block *target);
 
-pseudo_t alloc_phi(struct basic_block *source, pseudo_t pseudo, int size);
+struct instruction *alloc_phisrc(pseudo_t pseudo, struct symbol *type);
+struct instruction *alloc_phi_node(struct basic_block *bb, struct symbol *type, struct ident *ident);
+struct instruction *insert_phi_node(struct basic_block *bb, struct symbol *var);
+void add_phi_node(struct basic_block *bb, struct instruction *phi_node);
+
+pseudo_t alloc_phi(struct basic_block *source, pseudo_t pseudo, struct symbol *type);
 pseudo_t alloc_pseudo(struct instruction *def);
-pseudo_t value_pseudo(struct symbol *type, long long val);
-unsigned int value_size(long long value);
+pseudo_t value_pseudo(long long val);
+pseudo_t undef_pseudo(void);
 
 struct entrypoint *linearize_symbol(struct symbol *sym);
 int unssa(struct entrypoint *ep);
@@ -343,6 +324,7 @@
 const char *show_pseudo(pseudo_t pseudo);
 void show_bb(struct basic_block *bb);
 const char *show_instruction(struct instruction *insn);
+const char *show_label(struct basic_block *bb);
 
 #endif /* LINEARIZE_H */
 
