--- old/usr/src/cmd/auditreduce/Makefile	Mon Nov 18 13:18:33 2019
+++ new/usr/src/cmd/auditreduce/Makefile	Mon Nov 18 13:18:33 2019
@@ -24,7 +24,7 @@
 # Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
 
 TABLEDIR = ../praudit
 
@@ -44,8 +44,8 @@
 CERRWARN += $(CNOWARN_UNINIT)
 CERRWARN += -_gcc=-Wno-parentheses
 
-# false positives / need cleanup
-SMOFF += indenting,no_if_block,strcpy_overflow
+# false positive
+SMOFF += strcpy_overflow
 
 .KEEP_STATE:
 
--- old/usr/src/cmd/auditreduce/main.c	Mon Nov 18 13:18:34 2019
+++ new/usr/src/cmd/auditreduce/main.c	Mon Nov 18 13:18:34 2019
@@ -25,6 +25,10 @@
  */
 
 /*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
  * The Secure SunOS audit reduction tool - auditreduce.
  * Document SM0071 is the primary source of information on auditreduce.
  *
@@ -247,11 +251,13 @@
 			 * Convert descriptors to streams.
 			 */
 			if ((pcbn->pcb_fpr = fdopen(fildes[0], "r")) == NULL) {
-	perror(gettext("auditreduce: couldn't get read stream for pipe"));
+				perror(gettext("auditreduce: couldn't get read "
+				    "stream for pipe"));
 				return (-1);
 			}
 			if ((pcbn->pcb_fpw = fdopen(fildes[1], "w")) == NULL) {
-	perror(gettext("auditreduce: couldn't get write stream for pipe"));
+				perror(gettext("auditreduce: couldn't get "
+				    "write stream for pipe"));
 				return (-1);
 			}
 			if ((procno = fork()) == -1) {
@@ -400,8 +406,10 @@
 	for (j = 0; j <= i; j++) {
 		pcbt = &pcb->pcb_below[j];
 		if (fclose(pcbt->pcb_fpr) == EOF) {
-			if (!f_quiet)
-		perror(gettext("auditreduce: initial close on pipe failed"));
+			if (!f_quiet) {
+				perror(gettext("auditreduce: initial close "
+				    "on pipe failed"));
+			}
 		}
 		/*
 		 * Free the buffer allocated to hold incoming records.
@@ -426,8 +434,10 @@
 p_close(audit_pcb_t *pcbn)
 {
 	if (fclose(pcbn->pcb_fpw) == EOF) {
-		if (!f_quiet)
-		perror(gettext("auditreduce: close for write pipe failed"));
+		if (!f_quiet) {
+			perror(gettext("auditreduce: close for write "
+			    "pipe failed"));
+		}
 	}
 }
 
--- old/usr/src/lib/udapl/libdat/Makefile.com	Mon Nov 18 13:18:34 2019
+++ new/usr/src/lib/udapl/libdat/Makefile.com	Mon Nov 18 13:18:34 2019
@@ -22,6 +22,8 @@
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+# Copyright 2019 Joyent, Inc.
+#
 
 LIBRARY=	libdat.a
 VERS=		.1
@@ -40,7 +42,7 @@
 
 include ../../../Makefile.lib
 
-LIBS =	$(DYNLIB) $(LINTLIB)
+LIBS =	$(DYNLIB)
 LDLIBS += -lc
 
 SRCDIR =	../common
@@ -47,12 +49,12 @@
 
 CPPFLAGS +=     -I../include
 CFLAGS +=	$(CCVERBOSE)
-LINTFLAGS +=	-DDEBUG
-LINTFLAGS64 +=	-DDEBUG
-$(LINTLIB):=	SRCS = $(SRCDIR)/$(LINTSRC)
 
 CERRWARN +=	-_gcc=-Wno-type-limits
 
+# false positive
+SMOFF += signed
+
 $(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
 
 .KEEP_STATE:
@@ -61,6 +63,4 @@
 
 debug: all
 
-lint: lintcheck
-
 include ../../../Makefile.targ
--- old/usr/src/tools/smatch/Makefile	Mon Nov 18 13:18:35 2019
+++ new/usr/src/tools/smatch/Makefile	Mon Nov 18 13:18:35 2019
@@ -13,7 +13,7 @@
 
 #
 # The src/ sub-directory is un-modified copy of
-# https://github.com/illumos/smatch/tree/0.5.1-il-6
+# https://github.com/illumos/smatch/tree/$SPARSE_VERSION
 #
 # This Makefile installs just enough for us to be able to run smatch
 # locally.
@@ -20,7 +20,7 @@
 #
 
 PROG = smatch
-SPARSE_VERSION = 0.5.1-il-6
+SPARSE_VERSION = 0.6.1-rc1-il-1
 
 include ../Makefile.tools
 
@@ -51,78 +51,168 @@
 INS.file = $(RM) $@; $(CP) $< $(@D); $(CHMOD) $(FILEMODE) $@
 INS.dir = mkdir -p $@; $(CHMOD) $(DIRMODE) $@
 
-SMATCH_CHECK_OBJS:sh=ls src/check_*.c | sed -e 's+\.c+.o+;s+src/++;'
+# fine for us
+OS=linux
 
-OBJS = smatch.o $(SMATCH_CHECK_OBJS)
+LIB_OBJS =
+LIB_OBJS += allocate.o
+LIB_OBJS += builtin.o
+LIB_OBJS += char.o
+LIB_OBJS += compat-$(OS).o
+LIB_OBJS += cse.o
+LIB_OBJS += dissect.o
+LIB_OBJS += dominate.o
+LIB_OBJS += evaluate.o
+LIB_OBJS += expand.o
+LIB_OBJS += expression.o
+LIB_OBJS += flow.o
+LIB_OBJS += flowgraph.o
+LIB_OBJS += inline.o
+LIB_OBJS += ir.o
+LIB_OBJS += lib.o
+LIB_OBJS += linearize.o
+LIB_OBJS += liveness.o
+LIB_OBJS += memops.o
+LIB_OBJS += opcode.o
+LIB_OBJS += optimize.o
+LIB_OBJS += parse.o
+LIB_OBJS += pre-process.o
+LIB_OBJS += ptrlist.o
+LIB_OBJS += ptrmap.o
+LIB_OBJS += scope.o
+LIB_OBJS += show-parse.o
+LIB_OBJS += simplify.o
+LIB_OBJS += sort.o
+LIB_OBJS += ssa.o
+LIB_OBJS += sset.o
+LIB_OBJS += stats.o
+LIB_OBJS += storage.o
+LIB_OBJS += symbol.o
+LIB_OBJS += target.o
+LIB_OBJS += tokenize.o
+LIB_OBJS += unssa.o
+LIB_OBJS += utils.o
+LIB_OBJS += macro_table.o
+LIB_OBJS += token_store.o
+LIB_OBJS += hashtable.o
 
-OBJS += smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \
-	smatch_helper.o smatch_type.o smatch_hooks.o smatch_function_hooks.o \
-	smatch_modification_hooks.o smatch_extra.o smatch_estate.o smatch_math.o \
-	smatch_sval.o smatch_ranges.o smatch_implied.o smatch_ignore.o smatch_project.o \
-	smatch_var_sym.o smatch_tracker.o smatch_files.o smatch_expression_stacks.o \
-	smatch_equiv.o smatch_buf_size.o smatch_strlen.o smatch_capped.o smatch_db.o \
-	smatch_expressions.o smatch_returns.o smatch_parse_call_math.o \
-	smatch_param_limit.o smatch_param_filter.o \
-	smatch_param_set.o smatch_comparison.o smatch_param_compare_limit.o smatch_local_values.o \
-	smatch_function_ptrs.o smatch_annotate.o smatch_string_list.o \
-	smatch_param_cleared.o smatch_start_states.o \
-	smatch_recurse.o smatch_data_source.o smatch_type_val.o \
-	smatch_common_functions.o smatch_struct_assignment.o \
-	smatch_unknown_value.o smatch_stored_conditions.o avl.o \
-	smatch_function_info.o smatch_links.o smatch_auto_copy.o \
-	smatch_type_links.o smatch_untracked_param.o smatch_impossible.o \
-	smatch_strings.o smatch_param_used.o smatch_container_of.o smatch_address.o \
-	smatch_buf_comparison.o smatch_real_absolute.o smatch_scope.o \
-	smatch_imaginary_absolute.o smatch_parameter_names.o \
-	smatch_return_to_param.o smatch_passes_array_size.o \
-	smatch_constraints.o smatch_constraints_required.o \
-	smatch_fn_arg_link.o smatch_about_fn_ptr_arg.o smatch_mtag.o \
-	smatch_mtag_map.o smatch_mtag_data.o \
-	smatch_param_to_mtag_data.o smatch_mem_tracker.o smatch_array_values.o \
-	smatch_nul_terminator.o smatch_assigned_expr.o smatch_kernel_user_data.o \
-	smatch_statement_count.o smatch_bits.o smatch_integer_overflow.o
+SMATCH_OBJS =
+SMATCH_OBJS += avl.o
+SMATCH_OBJS += smatch_about_fn_ptr_arg.o
+SMATCH_OBJS += smatch_address.o
+SMATCH_OBJS += smatch_annotate.o
+SMATCH_OBJS += smatch_array_values.o
+SMATCH_OBJS += smatch_assigned_expr.o
+SMATCH_OBJS += smatch_bits.o
+SMATCH_OBJS += smatch_buf_comparison.o
+SMATCH_OBJS += smatch_buf_size.o
+SMATCH_OBJS += smatch_capped.o
+SMATCH_OBJS += smatch_common_functions.o
+SMATCH_OBJS += smatch_comparison.o
+SMATCH_OBJS += smatch_conditions.o
+SMATCH_OBJS += smatch_constraints.o
+SMATCH_OBJS += smatch_constraints_required.o
+SMATCH_OBJS += smatch_container_of.o
+SMATCH_OBJS += smatch_data_source.o
+SMATCH_OBJS += smatch_db.o
+SMATCH_OBJS += smatch_equiv.o
+SMATCH_OBJS += smatch_estate.o
+SMATCH_OBJS += smatch_expressions.o
+SMATCH_OBJS += smatch_expression_stacks.o
+SMATCH_OBJS += smatch_extra.o
+SMATCH_OBJS += smatch_files.o
+SMATCH_OBJS += smatch_flow.o
+SMATCH_OBJS += smatch_fn_arg_link.o
+SMATCH_OBJS += smatch_function_hooks.o
+SMATCH_OBJS += smatch_function_info.o
+SMATCH_OBJS += smatch_function_ptrs.o
+SMATCH_OBJS += smatch_helper.o
+SMATCH_OBJS += smatch_hooks.o
+SMATCH_OBJS += smatch_ignore.o
+SMATCH_OBJS += smatch_imaginary_absolute.o
+SMATCH_OBJS += smatch_implied.o
+SMATCH_OBJS += smatch_impossible.o
+SMATCH_OBJS += smatch_integer_overflow.o
+SMATCH_OBJS += smatch_kernel_user_data.o
+SMATCH_OBJS += smatch_links.o
+SMATCH_OBJS += smatch_math.o
+SMATCH_OBJS += smatch_mem_tracker.o
+SMATCH_OBJS += smatch_modification_hooks.o
+SMATCH_OBJS += smatch_mtag_data.o
+SMATCH_OBJS += smatch_mtag_map.o
+SMATCH_OBJS += smatch_mtag.o
+SMATCH_OBJS += smatch_nul_terminator.o
+SMATCH_OBJS += smatch_param_cleared.o
+SMATCH_OBJS += smatch_param_compare_limit.o
+SMATCH_OBJS += smatch_parameter_names.o
+SMATCH_OBJS += smatch_param_filter.o
+SMATCH_OBJS += smatch_param_limit.o
+SMATCH_OBJS += smatch_param_set.o
+SMATCH_OBJS += smatch_param_to_mtag_data.o
+SMATCH_OBJS += smatch_param_used.o
+SMATCH_OBJS += smatch_parse_call_math.o
+SMATCH_OBJS += smatch_passes_array_size.o
+SMATCH_OBJS += smatch_project.o
+SMATCH_OBJS += smatch_ranges.o
+SMATCH_OBJS += smatch_real_absolute.o
+SMATCH_OBJS += smatch_recurse.o
+SMATCH_OBJS += smatch_returns.o
+SMATCH_OBJS += smatch_return_to_param.o
+SMATCH_OBJS += smatch_scope.o
+SMATCH_OBJS += smatch_slist.o
+SMATCH_OBJS += smatch_start_states.o
+SMATCH_OBJS += smatch_statement_count.o
+SMATCH_OBJS += smatch_states.o
+SMATCH_OBJS += smatch_stored_conditions.o
+SMATCH_OBJS += smatch_string_list.o
+SMATCH_OBJS += smatch_strings.o
+SMATCH_OBJS += smatch_strlen.o
+SMATCH_OBJS += smatch_struct_assignment.o
+SMATCH_OBJS += smatch_sval.o
+SMATCH_OBJS += smatch_tracker.o
+SMATCH_OBJS += smatch_type_links.o
+SMATCH_OBJS += smatch_type.o
+SMATCH_OBJS += smatch_type_val.o
+SMATCH_OBJS += smatch_unknown_value.o
+SMATCH_OBJS += smatch_untracked_param.o
+SMATCH_OBJS += smatch_var_sym.o
 
-OBJS += target.o parse.o tokenize.o pre-process.o symbol.o lib.o scope.o \
-	expression.o show-parse.o evaluate.o expand.o inline.o linearize.o \
-	char.o sort.o allocate.o compat-linux.o ptrlist.o \
-	builtin.o \
-	stats.o \
-	flow.o cse.o simplify.o memops.o liveness.o storage.o unssa.o \
-	dissect.o \
-	macro_table.o token_store.o hashtable.o
+SMATCH_CHECK_OBJS:sh=ls src/check_*.c | sed -e 's+\.c+.o+;s+src/++;'
 
+OBJS = smatch.o $(LIB_OBJS) $(SMATCH_OBJS) $(SMATCH_CHECK_OBJS)
+
 SMATCH_DATA = \
 	illumos_kernel.skipped_functions \
 	illumos_user.skipped_functions
 
-SMATCH_DB_DATA = \
-	return_states.schema \
-	call_implies.schema \
-	type_value.schema \
-	param_map.schema \
-	function_type_size.schema \
-	parameter_name.schema \
-	fn_ptr_data_link.schema \
-	constraints.schema \
-	mtag_about.schema \
-	type_info.schema \
-	function_type_info.schema \
-	caller_info.schema \
-	function_type_value.schema \
-	return_implies.schema \
-	type_size.schema \
-	constraints_required.schema \
-	fn_data_link.schema \
-	mtag_alias.schema \
-	common_caller_info.schema \
-	data_info.schema \
-	function_type.schema \
-	db.schema \
-	mtag_data.schema \
-	function_ptr.schema \
-	sink_info.schema \
-	local_values.schema \
-	mtag_map.schema
+SMATCH_DB_DATA =
+SMATCH_DB_DATA += call_implies.schema
+SMATCH_DB_DATA += function_ptr.schema
+SMATCH_DB_DATA += mtag_map.schema
+SMATCH_DB_DATA += caller_info.schema
+SMATCH_DB_DATA += function_type.schema
+SMATCH_DB_DATA += param_map.schema
+SMATCH_DB_DATA += common_caller_info.schema
+SMATCH_DB_DATA += function_type_info.schema
+SMATCH_DB_DATA += parameter_name.schema
+SMATCH_DB_DATA += constraints.schema
+SMATCH_DB_DATA += function_type_size.schema
+SMATCH_DB_DATA += return_implies.schema
+SMATCH_DB_DATA += constraints_required.schema
+SMATCH_DB_DATA += function_type_value.schema
+SMATCH_DB_DATA += return_states.schema
+SMATCH_DB_DATA += data_info.schema
+SMATCH_DB_DATA += local_values.schema
+SMATCH_DB_DATA += sink_info.schema
+SMATCH_DB_DATA += db.schema
+SMATCH_DB_DATA += mtag_about.schema
+SMATCH_DB_DATA += type_info.schema
+SMATCH_DB_DATA += fn_data_link.schema
+SMATCH_DB_DATA += mtag_alias.schema
+SMATCH_DB_DATA += type_size.schema
+SMATCH_DB_DATA += fn_ptr_data_link.schema
+SMATCH_DB_DATA += mtag_data.schema
+SMATCH_DB_DATA += type_value.schema
 
 ROOTONBLDDATAFILES = $(SMATCH_DATA:%=$(SMATCHDATADIR)/smatch_data/%)
 ROOTONBLDDATAFILES += $(SMATCH_DB_DATA:%=$(SMATCHDATADIR)/smatch_data/db/%)
--- /dev/null	Mon Nov 18 13:18:35 2019
+++ new/usr/src/tools/smatch/src/Documentation/.gitignore	Mon Nov 18 13:18:35 2019
@@ -0,0 +1,2 @@
+build
+dev-options.1
--- /dev/null	Mon Nov 18 13:18:35 2019
+++ new/usr/src/tools/smatch/src/Documentation/IR.rst	Mon Nov 18 13:18:35 2019
@@ -0,0 +1,427 @@
+.. default-domain:: ir
+
+Sparse's Intermediate Representation
+====================================
+
+Instructions
+~~~~~~~~~~~~
+
+This document briefly describes which field of struct instruction is
+used by which operation.
+
+Some of those fields are used by almost all instructions,
+some others are specific to only one or a few instructions.
+The common ones are:
+
+* .src1, .src2, .src3: (pseudo_t) operands of binops or ternary ops.
+* .src: (pseudo_t) operand of unary ops (alias for .src1).
+* .target: (pseudo_t) result of unary, binary & ternary ops, is
+  sometimes used otherwise by some others instructions.
+* .cond: (pseudo_t) input operands for condition (alias .src/.src1)
+* .type: (symbol*) usually the type of .result, sometimes of the operands
+
+Terminators
+-----------
+.. op:: OP_RET
+	Return from subroutine.
+
+	* .src : returned value (NULL if void)
+	* .type: type of .src
+
+.. op:: OP_BR
+	Unconditional branch
+
+	* .bb_true: destination basic block
+
+.. op:: OP_CBR
+	Conditional branch
+
+	* .cond: condition
+	* .type: type of .cond, must be an integral type
+	* .bb_true, .bb_false: destination basic blocks
+
+.. op:: OP_SWITCH
+	Switch / multi-branch
+
+	* .cond: condition
+	* .type: type of .cond, must be an integral type
+	* .multijmp_list: pairs of case-value - destination basic block
+
+.. op:: OP_COMPUTEDGOTO
+	Computed goto / branch to register
+
+	* .src: address to branch to (void*)
+	* .multijmp_list: list of possible destination basic blocks
+
+Arithmetic binops
+-----------------
+They all follow the same signature:
+	* .src1, .src1: operands (types must be compatible with .target)
+	* .target: result of the operation (must be an integral type)
+	* .type: type of .target
+
+.. op:: OP_ADD
+	Integer addition.
+
+.. op:: OP_SUB
+	Integer subtraction.
+
+.. op:: OP_MUL
+	Integer multiplication.
+
+.. op:: OP_DIVU
+	Integer unsigned division.
+
+.. op:: OP_DIVS
+	Integer signed division.
+
+.. op:: OP_MODU
+	Integer unsigned remainder.
+
+.. op:: OP_MODS
+	Integer signed remainder.
+
+.. op:: OP_SHL
+	Shift left (integer only)
+
+.. op:: OP_LSR
+	Logical Shift right (integer only)
+
+.. op:: OP_ASR
+	Arithmetic Shift right (integer only)
+
+Floating-point binops
+---------------------
+They all follow the same signature:
+	* .src1, .src1: operands (types must be compatible with .target)
+	* .target: result of the operation (must be a floating-point type)
+	* .type: type of .target
+
+.. op:: OP_FADD
+	Floating-point addition.
+
+.. op:: OP_FSUB
+	Floating-point subtraction.
+
+.. op:: OP_FMUL
+	Floating-point multiplication.
+
+.. op:: OP_FDIV
+	Floating-point division.
+
+Logical ops
+-----------
+They all follow the same signature:
+	* .src1, .src2: operands (types must be compatible with .target)
+	* .target: result of the operation
+	* .type: type of .target, must be an integral type
+
+.. op:: OP_AND
+	Logical AND
+
+.. op:: OP_OR
+	Logical OR
+
+.. op:: OP_XOR
+	Logical XOR
+
+Integer compares
+----------------
+They all have the following signature:
+	* .src1, .src2: operands (types must be compatible)
+	* .target: result of the operation (0/1 valued integer)
+	* .type: type of .target, must be an integral type
+
+.. op:: OP_SET_EQ
+	Compare equal.
+
+.. op:: OP_SET_NE
+	Compare not-equal.
+
+.. op:: OP_SET_LE
+	Compare less-than-or-equal (signed).
+
+.. op:: OP_SET_GE
+	Compare greater-than-or-equal (signed).
+
+.. op:: OP_SET_LT
+	Compare less-than (signed).
+
+.. op:: OP_SET_GT
+	Compare greater-than (signed).
+
+.. op:: OP_SET_B
+	Compare less-than (unsigned).
+
+.. op:: OP_SET_A
+	Compare greater-than (unsigned).
+
+.. op:: OP_SET_BE
+	Compare less-than-or-equal (unsigned).
+
+.. op:: OP_SET_AE
+	Compare greater-than-or-equal (unsigned).
+
+Floating-point compares
+-----------------------
+They all have the same signature as the integer compares.
+
+The usual 6 operations exist in two versions: 'ordered' and
+'unordered'. These operations first check if any operand is a
+NaN and if it is the case the ordered compares return false
+and then unordered return true, otherwise the result of the
+comparison, now guaranteed to be done on non-NaNs, is returned.
+
+.. op:: OP_FCMP_OEQ
+	Floating-point compare ordered equal
+
+.. op:: OP_FCMP_ONE
+	Floating-point compare ordered not-equal
+
+.. op:: OP_FCMP_OLE
+	Floating-point compare ordered less-than-or-equal
+
+.. op:: OP_FCMP_OGE
+	Floating-point compare ordered greater-or-equal
+
+.. op:: OP_FCMP_OLT
+	Floating-point compare ordered less-than
+
+.. op:: OP_FCMP_OGT
+	Floating-point compare ordered greater-than
+
+
+.. op:: OP_FCMP_UEQ
+	Floating-point compare unordered equal
+
+.. op:: OP_FCMP_UNE
+	Floating-point compare unordered not-equal
+
+.. op:: OP_FCMP_ULE
+	Floating-point compare unordered less-than-or-equal
+
+.. op:: OP_FCMP_UGE
+	Floating-point compare unordered greater-or-equal
+
+.. op:: OP_FCMP_ULT
+	Floating-point compare unordered less-than
+
+.. op:: OP_FCMP_UGT
+	Floating-point compare unordered greater-than
+
+
+.. op:: OP_FCMP_ORD
+	Floating-point compare ordered: return true if both operands are ordered
+	(none of the operands are a NaN) and false otherwise.
+
+.. op:: OP_FCMP_UNO
+	Floating-point compare unordered: return false if no operands is ordered
+	and true otherwise.
+
+Unary ops
+---------
+.. op:: OP_NOT
+	Logical not.
+
+	* .src: operand (type must be compatible with .target)
+	* .target: result of the operation
+	* .type: type of .target, must be an integral type
+
+.. op:: OP_NEG
+	Integer negation.
+
+	* .src: operand (type must be compatible with .target)
+	* .target: result of the operation (must be an integral type)
+	* .type: type of .target
+
+.. op:: OP_FNEG
+	Floating-point negation.
+
+	* .src: operand (type must be compatible with .target)
+	* .target: result of the operation (must be a floating-point type)
+	* .type: type of .target
+
+.. op:: OP_SYMADDR
+	Create a pseudo corresponding to the address of a symbol.
+
+	* .src: input symbol (must be a PSEUDO_SYM)
+	* .target: symbol's address
+
+.. op:: OP_COPY
+	Copy (only needed after out-of-SSA).
+
+	* .src: operand (type must be compatible with .target)
+	* .target: result of the operation
+	* .type: type of .target
+
+Type conversions
+----------------
+They all have the following signature:
+	* .src: source value
+	* .orig_type: type of .src
+	* .target: result value
+	* .type: type of .target
+
+Currently, a cast to a void pointer is treated like a cast to
+an unsigned integer of the same size.
+
+.. op:: OP_TRUNC
+	Cast from integer to an integer of a smaller size.
+
+.. op:: OP_SEXT
+	Cast from integer to an integer of a bigger size with sign extension.
+
+.. op:: OP_ZEXT
+	Cast from integer to an integer of a bigger size with zero extension.
+
+.. op:: OP_UTPTR
+	Cast from pointer-sized unsigned integer to pointer type.
+
+.. op:: OP_PTRTU
+	Cast from pointer type to pointer-sized unsigned integer.
+
+.. op:: OP_PTRCAST
+	Cast between pointers.
+
+.. op:: OP_FCVTU
+	Conversion from float type to unsigned integer.
+
+.. op:: OP_FCVTS
+	Conversion from float type to signed integer.
+
+.. op:: OP_UCVTF
+	Conversion from unsigned integer to float type.
+
+.. op:: OP_SCVTF
+	Conversion from signed integer to float type.
+
+.. op:: OP_FCVTF
+	Conversion between float types.
+
+Ternary ops
+-----------
+.. op:: OP_SEL
+	* .src1: condition, must be of integral type
+	* .src2, .src3: operands (types must be compatible with .target)
+	* .target: result of the operation
+	* .type: type of .target
+
+.. op:: OP_RANGE
+	Range/bounds checking (only used for an unused sparse extension).
+
+	* .src1: value to be checked
+	* .src2, src3: bound of the value (must be constants?)
+	* .type: type of .src[123]?
+
+Memory ops
+----------
+.. op:: OP_LOAD
+	Load.
+
+	* .src: base address to load from
+	* .offset: address offset
+	* .target: loaded value
+	* .type: type of .target
+
+.. op:: OP_STORE
+	Store.
+
+	* .src: base address to store to
+	* .offset: address offset
+	* .target: value to be stored
+	* .type: type of .target
+
+Others
+------
+.. op:: OP_SETFVAL
+	Create a pseudo corresponding to a floating-point literal.
+
+	* .fvalue: the literal's value (long double)
+	* .target: the corresponding pseudo
+	* .type: type of the literal & .target
+
+.. op:: OP_SETVAL
+	Create a pseudo corresponding to a string literal or a label-as-value.
+	The value is given as an expression EXPR_STRING or EXPR_LABEL.
+
+	* .val: (expression) input expression
+	* .target: the resulting value
+	* .type: type of .target, the value
+
+.. op:: OP_PHI
+	Phi-node (for SSA form).
+
+	* .phi_list: phi-operands (type must be compatible with .target)
+	* .target: "result"
+	* .type: type of .target
+
+.. op:: OP_PHISOURCE
+	Phi-node source.
+	Like OP_COPY but exclusively used to give a defining instructions
+	(and thus also a type) to *all* OP_PHI operands.
+
+	* .phi_src: operand (type must be compatible with .target, alias .src)
+	* .target: the "result" PSEUDO_PHI
+	* .type: type of .target
+	* .phi_users: list of phi instructions using the target pseudo
+
+.. op:: OP_CALL
+	Function call.
+
+	* .func: (pseudo_t) the function (can be a symbol or a "register",
+	  alias .src))
+	* .arguments: (pseudo_list) list of the associated arguments
+	* .target: function return value (if any)
+	* .type: type of .target
+	* .fntypes: (symbol_list) list of the function's types: the first
+	  entry is the full function type, the next ones are the type of
+	  each arguments
+
+.. op:: OP_INLINED_CALL
+	Only used as an annotation to show that the instructions just above
+	correspond to a function that have been inlined.
+
+	* .func: (pseudo_t) the function (must be a symbol, alias .src))
+	* .arguments: list of pseudos that where the function's arguments
+	* .target: function return value (if any)
+	* .type: type of .target
+
+.. op:: OP_SLICE
+	Extract a "slice" from an aggregate.
+
+	* .base: (pseudo_t) aggregate (alias .src)
+	* .from, .len: offet & size of the "slice" within the aggregate
+	* .target: result
+	* .type: type of .target
+
+.. op:: OP_ASM
+	Inlined assembly code.
+
+	* .string: asm template
+	* .asm_rules: asm constraints, rules
+
+Sparse tagging (line numbers, context, whatever)
+------------------------------------------------
+.. op:: OP_CONTEXT
+	Currently only used for lock/unlock tracking.
+
+	* .context_expr: unused
+	* .increment: (1 for locking, -1 for unlocking)
+	* .check: (ignore the instruction if 0)
+
+Misc ops
+--------
+.. op:: OP_ENTRY
+	Function entry point (no associated semantic).
+
+.. op:: OP_BADOP
+	Invalid operation (should never be generated).
+
+.. op:: OP_NOP
+	No-op (should never be generated).
+
+.. op:: OP_DEATHNOTE
+	Annotation telling the pseudo will be death after the next
+	instruction (other than some other annotation, that is).
+
+.. # vim: tabstop=4
--- /dev/null	Mon Nov 18 13:18:35 2019
+++ new/usr/src/tools/smatch/src/Documentation/Makefile	Mon Nov 18 13:18:35 2019
@@ -0,0 +1,26 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    = -a
+SPHINXBUILD   = sphinx-build
+SPHINXPROJ    = sparse
+SOURCEDIR     = .
+BUILDDIR      = build
+
+targets := help
+targets += html
+targets += man
+
+
+# Put it first so that "make" without argument is like "make help".
+help:
+
+# route all targets to Sphinx using the new "make mode" option.
+$(targets): conf.py Makefile
+	@$(SPHINXBUILD) -M  $@  "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
+
+%.1: %.rst man
+	@mv build/man/$@ $@
+
+.PHONY: Makefile	# avoid circular deps with the catch-all rule
--- /dev/null	Mon Nov 18 13:18:35 2019
+++ new/usr/src/tools/smatch/src/Documentation/TODO.md	Mon Nov 18 13:18:35 2019
@@ -0,0 +1,98 @@
+TODO
+====
+
+Essential
+---------
+* SSA is broken by simplify_loads() & branches rewriting/simplification
+* attributes of struct, union & enums are ignored (and possibly in other
+  cases too).
+* add support for bitwise enums
+
+Documentation
+-------------
+* document the extensions
+* document the API
+* document the limitations of modifying ptrlists during list walking
+* document the data structures
+* document flow of data / architecture / code structure
+
+Core
+----
+* if a variable has its address taken but in an unreachable BB then
+  its MOD_ADDRESSABLE may be wrong and it won't be SSA converted.
+  - let kill_insn() check killing of SYMADDR,
+  - add the sym into a list and
+  - recalculate the addressability before memops's SSA conversion
+* bool_ctype should be split into internal 1-bit / external 8-bit
+* Previous declarations and the definition need to be merged. For example,
+  in the code here below, the function definition is **not** static:
+  ```
+	static void foo(void);
+	void foo(void) { ... }
+  ```
+
+Testsuite
+--------
+* there are more than 50 failing tests. They should be fixed
+  (but most are non-trivial to fix).
+
+Misc
+----
+* GCC's -Wenum-compare / clangs's -Wenum-conversion -Wassign-enum
+* parse __attribute_((fallthrough))
+* add support for __builtin_unreachable()
+* add support for format(printf())  (WIP by Ben Dooks)
+* make use of UNDEFs (issues warnings, simplification, ... ?)
+* add a pass to inline small functions during simplification.
+
+Optimization
+------------
+* the current way of doing CSE uses a lot of time
+* add SSA based DCE
+* add SSA based PRE
+* Add SSA based SCCP
+* use better/more systematic use of internal verification framework
+
+IR
+--
+* OP_SET should return a bool, always
+* add IR instructions for va_arg() & friends
+* add a possibility to import of file in "IR assembly"
+* dump the symtable
+* dump the CFG
+
+LLVM
+----
+* fix ...
+
+Internal backends
+-----------------
+* add some basic register allocation
+* add a pass to transform 3-addresses code to 2-addresses
+* what can be done for x86?
+
+Longer term/to investigate
+--------------------------
+* better architecture handling than current machine.h + target.c
+* attributes are represented as ctypes's alignment, modifiers & contexts
+  but plenty of attributes doesn't fit, for example they need arguments.
+  * format(printf, ...),
+  * section("...")
+  * assume_aligned(alignment[, offsert])
+  * error("message"), warning("message")
+  * ...
+* should support "-Werror=..." ?
+* All warning messages should include the option how to disable it.
+  For example:
+  	"warning: Variable length array is used."
+  should be something like:
+	"warning: Variable length array is used. (-Wno-vla)"
+* ptrlists must have elements be removed while being iterated but this
+  is hard to insure it is not done.
+* having 'struct symbol' used to represent symbols *and* types is
+  quite handy but it also creates lots of problems and complications
+* Possible mixup of symbol for a function designator being not a pointer?
+  This seems to make evaluation of function pointers much more complex
+  than needed.
+* extend test-inspect to inspect more AST fields.
+* extend test-inspect to inspect instructions.
--- /dev/null	Mon Nov 18 13:18:36 2019
+++ new/usr/src/tools/smatch/src/Documentation/api.rst	Mon Nov 18 13:18:36 2019
@@ -0,0 +1,27 @@
+Sparse API
+==========
+
+.. contents::
+	:local:
+	:depth: 2
+
+Utilities
+~~~~~~~~~
+
+.. c:autodoc:: ptrlist.c
+.. c:autodoc:: utils.h
+
+Parsing
+~~~~~~~
+
+.. c:autodoc:: expression.h
+
+Typing
+~~~~~~
+
+.. c:autodoc:: evaluate.h
+
+Optimization
+~~~~~~~~~~~~
+
+.. c:autodoc:: simplify.c
--- /dev/null	Mon Nov 18 13:18:36 2019
+++ new/usr/src/tools/smatch/src/Documentation/arm64-detecting-tagged-addresses.txt	Mon Nov 18 13:18:36 2019
@@ -0,0 +1,207 @@
+Detecting ARM64 tagged pointers
+===============================
+
+The ARM64 ABI allows tagged memory addresses to be passed through the
+user-kernel syscall ABI boundary. Tagged memory addresses are those which
+contain a non-zero top byte - the hardware will always ignore this top
+byte, however software does not. Therefore it is helpful to be able to
+detect code that erroneously compares tagged memory addresses with
+untagged memory addresses. This document describes how smatch can be used
+for this.
+
+Smatch will provide a warning when it detects that a comparison is being
+made between a user originated 64 bit data where the top byte may be
+non-zero and any variable which may contain an untagged address.
+
+Untagged variables are detected by looking for hard-coded known struct
+members (such as vm_start, vm_end and addr_limit) and hard-coded known
+macros (such as PAGE_SIZE, PAGE_MASK and TASK_SIZE). This check is
+also able to detect when comparisons are made against variables that
+have been assigned from these known untagged variables, though this
+tracking is limited to the scope of the function.
+
+This check is only performed when the ARCH environment variable is set to
+arm64. To provide a worked example, consider the following command which is
+used to perform Smatch static analysis on the Linux kernel:
+
+$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- ~/smatch/smatch_scripts/build_kernel_data.sh
+
+It is recommended that this command is run multiple times (6 or more) to
+provide Smatch with a deeper knowledge of the call stack. Before running
+multiple iterations of Smatch, it may be beneficial to delete any smatch*
+files in the root of the linux tree.
+
+Once Smatch has run, you can observe warnings as follows:
+
+$ cat smatch_warns.txt | grep "tagged address"
+mm/gup.c:818 __get_user_pages() warn: comparison of a potentially tagged
+address (__get_user_pages, 2, start)
+...
+
+This warning tells us that on line 818 of mm/gup.c an erroneous comparison
+may have been made between a tagged address (variable 'start' which originated
+from parameter 2 of the function) and existing kernel addresses (untagged).
+
+The code that this relates to follows:
+
+790: static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+791:                unsigned long start, unsigned long nr_pages,
+792:                unsigned int gup_flags, struct page **pages,
+793:                struct vm_area_struct **vmas, int *nonblocking)
+794:{
+...
+818:                if (!vma || start >= vma->vm_end) {
+
+Through manual inspection of this code, we can verify that the variable 'start'
+originated from parameter 2 of its function '__get_user_pages'.
+
+A suggested fix at this point may be to call the untagged_addr macro prior
+to the comparison on line 818. However it's often helpful to follow the
+parameter up the call stack, we can do this with the following Smatch command:
+
+$ ~/smatch/smatch_data/db/smdb.py find_tagged __get_user_pages 2
+    copy_strings (param ?) -> get_arg_page (param 1)
+    vfio_pin_map_dma (param ?) -> vfio_pin_pages_remote (param 1)
+    __se_sys_ptrace (param 2)
+    environ_read (param ?) -> access_remote_vm (param 1)
+    io_sqe_buffer_register (param ?) -> get_user_pages (param 0)
+    gntdev_grant_copy_seg (param ?) -> gntdev_get_page (param 1)
+    get_futex_key (param ?) -> get_user_pages_fast (param 0)
+    __se_sys_madvise (param 0)
+    __mm_populate (param ?) -> populate_vma_page_range (param 1)
+    __se_sys_mprotect (param 0)
+
+
+This script will examine all of the possible callers of __get_user_pages where
+parameter 2 contains user data and where the top byte of the parameter may be
+non-zero. It will recurse up the possible call stacks as far as it can go. This
+will leave a list of functions that provide tagged addresses to __get_user_pages
+and the parameter of interest (or variable if Smatch cannot determine the
+function parameter).
+
+Sometimes Smatch is able to determine a caller of a function but is unable
+to determine which parameter of that function relates to the parameter of the
+called function, when this happens the following output it shown:
+
+get_futex_key (param ?) -> get_user_pages_fast (param 0)
+
+This shows that when following up the call tree from __get_user_pages, we stop
+at get_user_pages_fast with parameter 0 of that function containing user data.
+Smatch knows that get_futex_key calls get_user_pages_fast but cannot determine
+which parameter of get_futex_key provided the data of interest. In these cases
+manual inspection of the source tree can help and if necessary re-run the
+smdb.py script with new parameters (e.g. smdb.py find_tagged get_futex_key 0).
+
+To provide a summary of all of the tagged issues found, the following command
+can be run directly on the smatch_warns.txt file:
+
+$ ~/smatch/smatch_data/db/smdb.py parse_warns_tagged smatch_warns.txt
+
+This will run find_tagged for each issue found, e.g.
+
+mm/mmap.c:2918 (func: __do_sys_remap_file_pages, param: 0:start) may be caused by:
+    __se_sys_remap_file_pages (param 0)
+
+mm/mmap.c:2963 (func: __do_sys_remap_file_pages, param: -1:__UNIQUE_ID___y73) may be caused by:
+    __do_sys_remap_file_pages (variable __UNIQUE_ID___y73 (can't walk call tree)
+
+mm/mmap.c:3000 (func: do_brk_flags, param: -1:error) may be caused by:
+    do_brk_flags (variable error (can't walk call tree)
+
+mm/mmap.c:540 (func: find_vma_links, param: 1:addr) may be caused by:
+    find_vma_links (param 1) (can't walk call tree)
+
+mm/mmap.c:570 (func: count_vma_pages_range, param: -1:__UNIQUE_ID___x64) may be caused by:
+    count_vma_pages_range (variable __UNIQUE_ID___x64 (can't walk call tree)
+
+mm/mmap.c:580 (func: count_vma_pages_range, param: -1:__UNIQUE_ID___x68) may be caused by:
+    count_vma_pages_range (variable __UNIQUE_ID___x68 (can't walk call tree)
+
+mm/mmap.c:856 (func: __vma_adjust, param: 1:start) may be caused by:
+    __se_sys_mprotect (param 0)
+    __se_sys_mlock (param 0)
+    __se_sys_mlock2 (param 0)
+    __se_sys_munlock (param 0)
+    mbind_range (param ?) -> vma_merge (param 2)
+    __se_sys_madvise (param 0)
+    __se_sys_mbind (param 0)
+
+
+The above commands do not output a call stack, instead they provide the 'highest'
+caller found, to provide a call stack perform the following:
+
+$ ~/smatch/smatch_data/db/smdb.py call_tree __get_user_pages
+__get_user_pages()
+  __get_user_pages_locked()
+    get_user_pages_remote()
+      get_arg_page()
+        copy_strings()
+        remove_arg_zero()
+      vaddr_get_pfn()
+        vfio_pin_pages_remote()
+        vfio_pin_page_external()
+      process_vm_rw_single_vec()
+        process_vm_rw_core()
+      __access_remote_vm()
+        ptrace_access_vm()
+        access_remote_vm()
+        access_process_vm()
+    check_and_migrate_cma_pages()
+      __gup_longterm_locked()
+        get_user_pages()
+        __gup_longterm_unlocked()
+    get_user_pages_locked()
+      get_vaddr_frames()
+        vb2_create_framevec()
+      lookup_node()
+        do_get_mempolicy()
+    get_user_pages_unlocked()
+      hva_to_pfn_slow()
+        hva_to_pfn()
+
+Please note that this will show all the callers and is not filtered for those
+carrying tagged addresses in their parameters.
+
+It is possible to filter out false positives by annotating function parameters
+with __untagged. For example:
+
+unsigned long do_mmap(struct file *file, unsigned long addr,
+			unsigned long __untagged len, unsigned long prot,
+			unsigned long flags, vm_flags_t vm_flags,
+			unsigned long pgoff, unsigned long *populate,
+			struct list_head *uf)
+{
+
+This annotation tells smatch that regardless to the value stored in 'len' it
+should be treated as an untagged address. As Smatch is able to track the
+potential ranges of values a variable may hold, it will also track the
+annotation - therefore it is not necessary to use the annotation in every
+function that do_mmap calls. When using this annotation smdb.py will filter
+out functions that carry a value which has been annotated as untagged. Please
+note that due to limitations in parameter tracking some annotations will be
+ignored and not propogated all the way down the call tree.
+
+Finally, the following patch is required to add annotations to the Linux
+kernel:
+
+diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
+index 19e58b9138a0..755e8df375a5 100644
+--- a/include/linux/compiler_types.h
++++ b/include/linux/compiler_types.h
+@@ -19,6 +19,7 @@
+ # define __cond_lock(x,c)      ((c) ? ({ __acquire(x); 1; }) : 0)
+ # define __percpu      __attribute__((noderef, address_space(3)))
+ # define __rcu         __attribute__((noderef, address_space(4)))
++# define __untagged    __attribute__((address_space(5)))
+ # define __private     __attribute__((noderef))
+ extern void __chk_user_ptr(const volatile void __user *);
+ extern void __chk_io_ptr(const volatile void __iomem *);
+@@ -45,6 +46,7 @@ extern void __chk_io_ptr(const volatile void __iomem *);
+ # define __cond_lock(x,c) (c)
+ # define __percpu
+ # define __rcu
++# define __untagged
+ # define __private
+ # define ACCESS_PRIVATE(p, member) ((p)->member)
+ #endif /* __CHECKER__ */
+
--- /dev/null	Mon Nov 18 13:18:36 2019
+++ new/usr/src/tools/smatch/src/Documentation/conf.py	Mon Nov 18 13:18:36 2019
@@ -0,0 +1,178 @@
+# -*- coding: utf-8 -*-
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another
+# directory, add these directories to sys.path here. If the directory
+# is relative to the documentation root, use os.path.abspath to make
+# it absolute, like shown here.
+# sys.path.insert(0, os.path.abspath('.'))
+
+import os
+import sys
+import datetime
+
+# -- General configuration ------------------------------------------------
+
+needs_sphinx = '1.3'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+sys.path.insert(0, os.path.abspath('sphinx'))
+extensions = [
+	'cdoc'
+	, 'ir'
+]
+
+# support .md with python2 & python3
+if sys.version_info[0] > 2:
+    from recommonmark.parser import CommonMarkParser
+    source_parsers = {
+        '.md': CommonMarkParser,
+    }
+else:
+    source_parsers = {
+        '.md': 'recommonmark.parser.CommonMarkParser',
+    }
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+source_suffix = ['.rst', '.md']
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'sparse'
+copyright = '2003 - ' + str(datetime.datetime.now().year)
+author = "sparse's development community"
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The full version, including alpha/beta/rc tags.
+release = next(open('../Makefile', 'r')).split('=')[1].rstrip()
+# The short X.Y version.
+version = release.split('-')[0]
+
+# it's a C project, so:
+primary_domain = 'c'
+# disable syntax highlight in non-code sections
+highlight_language = 'none'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['build']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+# -- Options for cdoc extension -------------------------------------------
+
+cdoc_srcdir = '..'
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'classic'
+# html_theme_options = {}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+# html_static_path = ['sphinx/static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# This is required for the alabaster theme
+# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
+html_sidebars = {
+	'**': [
+	    'relations.html',  # needs 'show_related': True theme option to display
+	    'searchbox.html',
+	]
+}
+
+html_logo = 'logo.svg'
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'sparsedoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+	# The paper size ('letterpaper' or 'a4paper').
+	#
+	'papersize': 'a4paper',
+
+	# The font size ('10pt', '11pt' or '12pt').
+	#
+	# 'pointsize': '10pt',
+
+	# Additional stuff for the LaTeX preamble.
+	#
+	# 'preamble': '',
+
+	# Latex figure (float) alignment
+	#
+	# 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+	('index', 'sparse.tex', u'sparse Documentation', author, 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+	('dev-options', 'dev-options', u'options for development', [author], 1),
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+	('index', 'sparse', u'sparse Documentation', author, 'sparse', 'C semantic parser & checker', 'Software development'),
+]
+
+
+# vim: tabstop=4
--- /dev/null	Mon Nov 18 13:18:36 2019
+++ new/usr/src/tools/smatch/src/Documentation/dev-options.rst	Mon Nov 18 13:18:36 2019
@@ -0,0 +1,58 @@
+sparse - extra options for developers
+=====================================
+
+SYNOPSIS
+--------
+``tools`` [`options`]... `file.c``
+
+DESCRIPTION
+-----------
+
+This file is a complement of sparse's man page meant to
+document options only useful for development on sparse itself.
+
+OPTIONS
+-------
+
+.. option:: -fdump-ir=pass,[pass]
+
+  Dump the IR at each of the given passes.
+
+  The passes currently understood are:
+
+    * ``linearize``
+    * ``mem2reg``
+    * ``final``
+
+  The default pass is ``linearize``.
+
+.. option:: -f<name-of-the-pass>[-disable|-enable|=last]
+
+  If ``=last`` is used, all passes after the specified one are disabled.
+  By default all passes are enabled.
+
+  The passes currently understood are:
+
+    * ``linearize`` (can't be disabled)
+    * ``mem2reg``
+    * ``optim``
+
+.. option:: -vcompound
+
+  Print all compound global data symbols with their sizes and alignment.
+
+.. option:: -vdead
+
+  Add ``OP_DEATHNOTE`` annotations to dead pseudos.
+
+.. option:: -vdomtree
+
+  Dump the dominance tree after its calculation.
+
+.. option:: -ventry
+
+  Dump the IR after all optimization passes.
+
+.. option:: -vpostorder
+
+  Dump the reverse postorder traversal of the CFG.
--- /dev/null	Mon Nov 18 13:18:36 2019
+++ new/usr/src/tools/smatch/src/Documentation/doc-guide.rst	Mon Nov 18 13:18:36 2019
@@ -0,0 +1,155 @@
+How to write sparse documentation
+=================================
+
+Introduction
+------------
+
+
+The documentation for Sparse is written in plain text augmented with
+either `reStructuredText`_ (.rst) or `MarkDown`_ (.md) markup. These
+files can be organized hierarchically, allowing a good structuring
+of the documentation.
+Sparse uses `Sphinx`_ to format this documentation in several formats,
+like HTML or PDF.
+
+All documentation related files are in the ``Documentation/`` directory.
+In this directory you can use ``make html`` or ``make man`` to generate
+the documentation in HTML or manpage format. The generated files can then
+be found in the ``build/`` sub-directory.
+
+The root of the documentation is the file ``index.rst`` which mainly
+lists the names of the files with real documentation.
+
+.. _Sphinx: http://www.sphinx-doc.org/
+.. _reStructuredText: http://docutils.sourceforge.net/rst.html
+.. _MarkDown: https://en.wikipedia.org/wiki/Markdown
+
+
+.. _rest-markup:
+
+Minimal reST cheatsheet
+-----------------------
+
+Basic inline markup is:
+
+* ``*italic*`` gives *italic*
+* ``**bold**`` gives **bold**
+* ````mono```` gives ``mono``
+
+Headings are created by underlining the title with a punctuation
+character; it can also be optionally overlined::
+
+	#############
+	Major heading
+	#############
+
+	Minor heading
+	-------------
+
+Any punctuation character can be used and the levels are automatically
+determined from their nesting. However, the convention is to use:
+
+* ``#`` with overline for parts
+* ``*`` with overline for chapters
+* ``=`` for sections
+* ``-`` for subsections
+* ``^`` for subsubsections
+
+
+Lists can be created like this::
+
+	* this is a bulleted list
+	* with the second item
+	  on two lines
+	* nested lists are supported
+
+		* subitem
+		* another subitem
+
+	* and here is the fourth item
+
+	#. this is an auto-numbered list
+	#. with two items
+
+	1. this is an explicitly numbered list
+	2. with two items
+
+
+Definition lists are created with a simple indentation, like::
+
+	term, concept, whatever
+		Definition, must be indented and
+		continue here.
+
+		It can also have several paragraphs.
+
+Literal blocks are introduced with ``::``, either at the end of the
+preceding paragraph or on its own line, and indented text::
+
+	This is a paragraph introducing a literal block::
+
+		This is the literal block.
+		It can span several lines.
+
+		It can also consist of several paragraphs.
+
+Code examples with syntax highlighting use the *code-block* directive.
+For example::
+
+	.. code-block:: c
+
+		int foo(int a)
+		{
+			return a + 1;
+		}
+
+will give:
+
+.. code-block:: c
+
+	int foo(int a)
+	{
+		return a + 1;
+	}
+
+
+Autodoc
+-------
+
+.. highlight:: none
+.. c:autodoc:: Documentation/sphinx/cdoc.py
+
+For example, a doc-block like::
+
+	///
+	// increment a value
+	//
+	// @val: the value to increment
+	// @return: the incremented value
+	//
+	// This function is to be used to increment a
+	// value.
+	//
+	// It's strongly encouraged to use this
+	// function instead of open coding a simple
+	// ``++``.
+	int inc(int val)
+
+will be displayed like this:
+
+.. c:function:: int inc(int val)
+	:noindex:
+
+	:param val: the value to increment
+	:return: the incremented value
+
+	This function is to be used to increment a
+	value.
+
+	It's strongly encouraged to use this
+	function instead of open coding a simple
+	``++``.
+
+Intermediate Representation
+---------------------------
+.. c:autodoc:: Documentation/sphinx/ir.py
--- /dev/null	Mon Nov 18 13:18:36 2019
+++ new/usr/src/tools/smatch/src/Documentation/index.rst	Mon Nov 18 13:18:36 2019
@@ -0,0 +1,38 @@
+.. sparse documentation master file.
+
+Welcome to sparse's documentation
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+User documentation
+------------------
+.. toctree::
+   :maxdepth: 1
+
+   nocast-vs-bitwise
+
+Developer documentation
+-----------------------
+.. toctree::
+   :maxdepth: 1
+
+   test-suite
+   dev-options
+   api
+   IR
+   doc-guide
+
+How to contribute
+-----------------
+.. toctree::
+   :maxdepth: 1
+
+   submitting-patches
+   TODO
+
+Indices and tables
+==================
+
+* :ref:`genindex`
--- /dev/null	Mon Nov 18 13:18:36 2019
+++ new/usr/src/tools/smatch/src/Documentation/logo.svg	Mon Nov 18 13:18:37 2019
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="425.19684"
+   height="170.07874"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="logo.svg">
+  <metadata
+     id="metadata24">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs22" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1122"
+     inkscape:window-height="764"
+     id="namedview20"
+     showgrid="false"
+     units="mm"
+     inkscape:zoom="0.41627715"
+     inkscape:cx="115.87347"
+     inkscape:cy="283.465"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2" />
+  <g
+     id="g4"
+     transform="matrix(0.8,0,0,0.8,-15.072782,-220.54503)">
+    <title
+       id="title6">Layer 1</title>
+    <path
+       id="svg_2"
+       d="m 118.652,337.78799 0,8.36701 c -8.532,-5.01502 -15.868,-7.52301 -22.008003,-7.52301 -5.905998,0 -10.839996,1.793 -14.800995,5.379 -3.962006,3.586 -5.941002,8.02801 -5.941002,13.324 0,3.797 1.170998,7.22 3.515999,10.26599 2.343002,3.04801 7.242004,5.97702 14.695,8.789 7.453001,2.81198 12.890001,5.15702 16.312001,7.03101 3.421,1.87601 6.328,4.595 8.719,8.156 2.391,3.56299 3.586,8.181 3.586,13.85199 0,7.54801 -2.767,13.922 -8.297,19.125 -5.532,5.20301 -12.282,7.805 -20.250002,7.805 -8.155998,0 -16.547997,-2.858 -25.171997,-8.57801 l 0,-8.92999 C 78.526,421.836 86.776,425.328 93.761001,425.328 c 5.811996,0 10.722999,-1.88602 14.729999,-5.66 4.00699,-3.77399 6.012,-8.40302 6.012,-13.88901 0,-4.173 -1.243,-7.935 -3.727,-11.28601 -2.484,-3.353 -7.521,-6.48499 -15.111999,-9.4 -7.590004,-2.914 -13.014999,-5.26199 -16.275002,-7.04098 -3.261002,-1.77902 -6.028,-4.32202 -8.303001,-7.625 -2.275002,-3.302 -3.411995,-7.55402 -3.411995,-12.755 0,-7.21402 2.764999,-13.362 8.296997,-18.44599 5.529999,-5.082 12.186996,-7.62402 19.969002,-7.62402 7.640998,-9.8e-4 15.210998,2.06201 22.711998,6.186 z"
+       inkscape:connector-curvature="0" />
+    <path
+       id="svg_3"
+       d="m 139.886,332.866 27.06999,0 c 10.35901,0 18.29201,2.32 23.80101,6.961 5.50701,4.64099 8.262,10.96899 8.262,18.98401 0,8.10998 -2.777,14.53198 -8.332,19.26599 -5.555,4.73501 -13.7,7.10199 -24.43399,7.10199 l -18.77301,0 0,45.914 -7.594,0 0,-98.22699 z m 7.594,6.328 0,39.65601 18.281,0 c 8.202,0 14.437,-1.73301 18.70299,-5.20301 4.265,-3.46802 6.39799,-8.367 6.39799,-14.695 0,-6.047 -2.08599,-10.85099 -6.25799,-14.414 -4.173,-3.56199 -10.149,-5.344 -17.92999,-5.344 l -19.194,0 z"
+       inkscape:connector-curvature="0" />
+    <path
+       id="svg_4"
+       d="m 239.248,332.16299 45.41301,98.93 -7.96802,0 -39.59999,-86.555 -39.45801,86.555 -7.96699,0 45.408,-98.93 4.172,0 z"
+       inkscape:connector-curvature="0"
+       style="fill:#ff0000" />
+    <path
+       id="svg_5"
+       d="m 296.543,332.866 25.172,0 c 10.54699,0 18.60699,2.285 24.18801,6.85501 5.577,4.56997 8.36698,10.74698 8.36698,18.52698 0,11.345 -6.23499,19.31301 -18.703,23.906 3.234,1.547 7.59402,6.539 13.078,14.97702 l 22.21902,33.961 -8.99002,0 -17.10898,-26.92102 c -5.71701,-9.004 -10.169,-14.61798 -13.35501,-16.84699 -3.18701,-2.22799 -7.85,-3.34201 -13.987,-3.34201 l -13.28399,0 0,47.10901 -7.594,0 0,-98.225 -0.002,0 z m 7.59399,6.328 0,38.461 16.31201,0 c 8.297,0 14.63498,-1.67499 19.01999,-5.02701 4.38199,-3.35098 6.57401,-8.09698 6.57401,-14.23798 0,-6.04702 -2.228,-10.75802 -6.68002,-14.13302 -4.45499,-3.375 -10.85398,-5.06198 -19.19498,-5.06198 l -16.03101,0 0,-0.001 z"
+       inkscape:connector-curvature="0" />
+    <path
+       id="svg_6"
+       d="m 425.285,337.78799 0,8.36701 c -8.53299,-5.01502 -15.86801,-7.52301 -22.00799,-7.52301 -5.90601,0 -10.841,1.793 -14.801,5.379 -3.96301,3.586 -5.94101,8.02801 -5.94101,13.324 0,3.797 1.16999,7.22 3.51599,10.26599 2.34302,3.04801 7.24201,5.97702 14.69501,8.789 7.453,2.81198 12.88998,5.15702 16.31201,7.03101 3.41999,1.87601 6.32797,4.595 8.719,8.156 2.39099,3.56299 3.586,8.181 3.586,13.85199 0,7.54801 -2.76801,13.922 -8.297,19.125 -5.53201,5.20301 -12.28201,7.805 -20.25,7.805 -8.15601,0 -16.54901,-2.858 -25.172,-8.57801 l 0,-8.92999 c 9.51499,6.98502 17.76398,10.47702 24.75,10.47702 5.81098,0 10.72299,-1.88602 14.72998,-5.66 4.00699,-3.77399 6.012,-8.40302 6.012,-13.88901 0,-4.173 -1.24299,-7.935 -3.72699,-11.28601 -2.48401,-3.353 -7.521,-6.48499 -15.112,-9.4 -7.59101,-2.914 -13.01499,-5.26199 -16.27399,-7.04098 -3.26203,-1.77902 -6.02902,-4.32202 -8.30301,-7.625 -2.27499,-3.302 -3.41199,-7.55402 -3.41199,-12.755 0,-7.21402 2.76499,-13.362 8.297,-18.44599 5.52899,-5.082 12.18698,-7.62402 19.96899,-7.62402 7.63901,-9.8e-4 15.20999,2.06201 22.711,6.186 z"
+       inkscape:connector-curvature="0" />
+    <path
+       id="svg_7"
+       d="m 500.379,332.866 0,6.328 -45.98401,0 0,39.30499 20.60501,0 0,6.39801 -20.60501,0 0,39.86701 47.10901,0 0,6.328 -54.70301,0 0,-98.22702 53.57801,0 0,0.001 z"
+       inkscape:connector-curvature="0"
+       style="fill:#00f200" />
+    <g
+       id="svg_8" />
+    <g
+       id="svg_9" />
+    <g
+       id="svg_10" />
+    <g
+       id="svg_11" />
+    <g
+       id="svg_12" />
+    <g
+       id="svg_13" />
+  </g>
+</svg>
--- /dev/null	Mon Nov 18 13:18:37 2019
+++ new/usr/src/tools/smatch/src/Documentation/nocast-vs-bitwise.md	Mon Nov 18 13:18:37 2019
@@ -0,0 +1,41 @@
+# __nocast vs __bitwise
+
+`__nocast` warns about explicit or implicit casting to different types.
+HOWEVER, it doesn't consider two 32-bit integers to be different
+types, so a `__nocast int` type may be returned as a regular `int`
+type and then the `__nocast` is lost.
+
+So `__nocast` on integer types is usually not that powerful. It just
+gets lost too easily. It's more useful for things like pointers. It
+also doesn't warn about the mixing: you can add integers to `__nocast`
+integer types, and it's not really considered anything wrong.
+
+`__bitwise` ends up being a *stronger integer separation*. That one
+doesn't allow you to mix with non-bitwise integers, so now it's much
+harder to lose the type by mistake.
+
+So the basic rule is:
+
+ - `__nocast` on its own tends to be more useful for *big* integers
+that still need to act like integers, but you want to make it much
+less likely that they get truncated by mistake. So a 64-bit integer
+that you don't want to mistakenly/silently be returned as `int`, for
+example. But they mix well with random integer types, so you can add
+to them etc without using anything special. However, that mixing also
+means that the `__nocast` really gets lost fairly easily.
+
+ - `__bitwise` is for *unique types* that cannot be mixed with other
+types, and that you'd never want to just use as a random integer (the
+integer `0` is special, though, and gets silently accepted - it's
+kind of like `NULL` for pointers). So `gfp_t` or the `safe endianness`
+types would be `__bitwise`: you can only operate on them by doing
+specific operations that know about *that* particular type.
+
+Generally, you want `__bitwise` if you are looking for type safety.
+`__nocast` really is pretty weak.
+
+## Reference:
+
+* Linus' e-mail about `__nocast` vs `__bitwise`:
+
+  <https://marc.info/?l=linux-mm&m=133245421127324&w=2>
--- old/usr/src/tools/smatch/src/Documentation/project-ideas.md	Mon Nov 18 13:18:37 2019
+++ /dev/null	Mon Nov 18 13:18:37 2019
@@ -1,52 +0,0 @@
-Why hacking on sparse
-=====================
-
-1. sparse is small.  
-   The full project compiles in less than 10 seconds on old and not performing laptop.
-2. sparse is fast.  
-   Typically, sparse can check a C file 1/10 of time it takes for gcc to generate object files.
-3. sparse can digest the full kernel source files.  
-   With sparse-llvm, sparse uses llvm as back end to emit real machine code.
-
-New developer hacking on sparse
-==============================
-
-
-* All sparse warning messages should include the option how
-   to disable it.  
-       e.g. "pre-process.c:20*:28: warning: Variable length array is used."
-       should be something like   
-        "pre-process.c:20*:28: warning: Variable length array is
-used. (-Wno-vla)"
-* extend test-inspect to inspect more AST fields.
-* extend test-inspect to inspect instructions.
-* adding architecture handling in sparse similar to cgcc
-* parallel processing of test-suite
-* Howto: fix the kernel rcu related checker warnings
-* option to disable AST level inline.
-* debug: debug version of sparse do all the verification double check
-* test suite: verify and compare IR (suggested by Dibyendu Majumdar)
-* checker error output database
-
-For experienced developers
-==========================
-
-* merge C type on incremental declare of C type and function prototype.
-* move attribute out of ctype to allow easier to add new attribute.
-* serialize, general object walking driven by data structures.
-* serialize, write sparse byte code into file
-* serialize, load sparse byte code from file.
-* symbol index/linker, know which symbol in which byte code file.
-* inline function in instruction level
-* cross function checking
-* debug: optimization step by step log
-* debug: fancy animation of CFG
-* phi node location (Luc has patch)
-* revisit crazy programmer warning, invalid SSA form.
-* ptrlist, looping while modify inside the loop.
-* dead code elimination using ssa
-* constant propagation using ssa.
-* x86/arm back end instruction set define
-* register allocation.
-* emit x86/arm machine level code
-
--- old/usr/src/tools/smatch/src/Documentation/smatch.txt	Mon Nov 18 13:18:37 2019
+++ new/usr/src/tools/smatch/src/Documentation/smatch.txt	Mon Nov 18 13:18:37 2019
@@ -55,6 +55,10 @@
 
 The kchecker script prints its warnings to stdout.
 
+The above scripts will ensure that any ARCH or CROSS_COMPILE environment
+variables are passed to kernel build system - thus allowing for the use of
+Smatch with kernels that are normally built with cross-compilers.
+
 If you are building something else (which is not the Linux kernel) then use
 something like:
 
--- old/usr/src/tools/smatch/src/Documentation/sparse.txt	Mon Nov 18 13:18:37 2019
+++ /dev/null	Mon Nov 18 13:18:37 2019
@@ -1,45 +0,0 @@
-Sparse
-~~~~~~
-
-__nocast vs __bitwise:
-
-__nocast warns about explicit or implicit casting to different types.
-
-HOWEVER, it doesn't consider two 32-bit integers to be different
-types, so a __nocast 'int' type may be returned as a regular 'int'
-type and then the __nocast is lost.
-
-So "__nocast" on integer types is usually not that powerful. It just
-gets lost too easily. It's more useful for things like pointers. It
-also doesn't warn about the mixing: you can add integers to __nocast
-integer types, and it's not really considered anything wrong.
-
-__bitwise ends up being a "stronger integer separation". That one
-doesn't allow you to mix with non-bitwise integers, so now it's much
-harder to lose the type by mistake.
-
-So the basic rule is:
-
- - "__nocast" on its own tends to be more useful for *big* integers
-that still need to act like integers, but you want to make it much
-less likely that they get truncated by mistake. So a 64-bit integer
-that you don't want to mistakenly/silently be returned as "int", for
-example. But they mix well with random integer types, so you can add
-to them etc without using anything special. However, that mixing also
-means that the __nocast really gets lost fairly easily.
-
- - "__bitwise" is for *unique types* that cannot be mixed with other
-types, and that you'd never want to just use as a random integer (the
-integer 0 is special, though, and gets silently accepted iirc - it's
-kind of like "NULL" for pointers). So "gfp_t" or the "safe endianness"
-types would be __bitwise: you can only operate on them by doing
-specific operations that know about *that* particular type.
-
-Generally, you want __bitwise if you are looking for type safety.
-"__nocast" really is pretty weak.
-
-Reference:
-
-* Linus' e-mail about __nocast vs __bitwise:
-
-  http://marc.info/?l=linux-mm&m=133245421127324&w=2
--- /dev/null	Mon Nov 18 13:18:37 2019
+++ new/usr/src/tools/smatch/src/Documentation/sphinx/cdoc.py	Mon Nov 18 13:18:38 2019
@@ -0,0 +1,315 @@
+#!/usr/bin/env python
+# SPDX_License-Identifier: MIT
+#
+# Copyright (C) 2018 Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
+#
+
+"""
+///
+// Sparse source files may contain documentation inside block-comments
+// specifically formatted::
+//
+// 	///
+// 	// Here is some doc
+// 	// and here is some more.
+//
+// More precisely, a doc-block begins with a line containing only ``///``
+// and continues with lines beginning by ``//`` followed by either a space,
+// a tab or nothing, the first space after ``//`` is ignored.
+//
+// For functions, some additional syntax must be respected inside the
+// block-comment::
+//
+// 	///
+// 	// <mandatory short one-line description>
+// 	// <optional blank line>
+// 	// @<1st parameter's name>: <description>
+// 	// @<2nd parameter's name>: <long description
+// 	// <tab>which needs multiple lines>
+// 	// @return: <description> (absent for void functions)
+// 	// <optional blank line>
+// 	// <optional long multi-line description>
+// 	int somefunction(void *ptr, int count);
+//
+// Inside the description fields, parameter's names can be referenced
+// by using ``@<parameter name>``. A function doc-block must directly precede
+// the function it documents. This function can span multiple lines and
+// can either be a function prototype (ending with ``;``) or a
+// function definition.
+//
+// Some future versions will also allow to document structures, unions,
+// enums, typedefs and variables.
+//
+// This documentation can be extracted into a .rst document by using
+// the *autodoc* directive::
+//
+// 	.. c:autodoc:: file.c
+//
+
+"""
+
+import re
+
+class Lines:
+	def __init__(self, lines):
+		# type: (Iterable[str]) -> None
+		self.index = 0
+		self.lines = lines
+		self.last = None
+		self.back = False
+
+	def __iter__(self):
+		# type: () -> Lines
+		return self
+
+	def memo(self):
+		# type: () -> Tuple[int, str]
+		return (self.index, self.last)
+
+	def __next__(self):
+		# type: () -> Tuple[int, str]
+		if not self.back:
+			self.last = next(self.lines).rstrip()
+			self.index += 1
+		else:
+			self.back = False
+		return self.memo()
+	def next(self):
+		return self.__next__()
+
+	def undo(self):
+		# type: () -> None
+		self.back = True
+
+def readline_multi(lines, line):
+	# type: (Lines, str) -> str
+	try:
+		while True:
+			(n, l) = next(lines)
+			if not l.startswith('//\t'):
+				raise StopIteration
+			line += '\n' + l[3:]
+	except:
+		lines.undo()
+	return line
+
+def readline_delim(lines, delim):
+	# type: (Lines, Tuple[str, str]) -> Tuple[int, str]
+	try:
+		(lineno, line) = next(lines)
+		if line == '':
+			raise StopIteration
+		while line[-1] not in delim:
+			(n, l) = next(lines)
+			line += ' ' + l.lstrip()
+	except:
+		line = ''
+	return (lineno, line)
+
+
+def process_block(lines):
+	# type: (Lines) -> Dict[str, Any]
+	info = { }
+	tags = []
+	desc = []
+	state = 'START'
+
+	(n, l) = lines.memo()
+	#print('processing line ' + str(n) + ': ' + l)
+
+	## is it a single line comment ?
+	m = re.match(r"^///\s+(.+)$", l)	# /// ...
+	if m:
+		info['type'] = 'single'
+		info['desc'] = (n, m.group(1).rstrip())
+		return info
+
+	## read the multi line comment
+	for (n, l) in lines:
+		#print('state %d: %4d: %s' % (state, n, l))
+		if l.startswith('// '):
+			l = l[3:]					## strip leading '// '
+		elif l.startswith('//\t') or l == '//':
+			l = l[2:]					## strip leading '//'
+		else:
+			lines.undo()				## end of doc-block
+			break
+
+		if state == 'START':			## one-line short description
+			info['short'] = (n ,l)
+			state = 'PRE-TAGS'
+		elif state == 'PRE-TAGS':		## ignore empty line
+			if l != '':
+				lines.undo()
+				state = 'TAGS'
+		elif state == 'TAGS':			## match the '@tagnames'
+			m = re.match(r"^@([\w-]*)(:?\s*)(.*)", l)
+			if m:
+				tag = m.group(1)
+				sep = m.group(2)
+				## FIXME/ warn if sep != ': '
+				l = m.group(3)
+				l = readline_multi(lines, l)
+				tags.append((n, tag, l))
+			else:
+				lines.undo()
+				state = 'PRE-DESC'
+		elif state == 'PRE-DESC':		## ignore the first empty lines
+			if l != '':					## or first line of description
+				desc = [n, l]
+				state = 'DESC'
+		elif state == 'DESC':			## remaining lines -> description
+			desc.append(l)
+		else:
+			pass
+
+	## fill the info
+	if len(tags):
+		info['tags'] = tags
+	if len(desc):
+		info['desc'] = desc
+
+	## read the item (function only for now)
+	(n, line) = readline_delim(lines, (')', ';'))
+	if len(line):
+		line = line.rstrip(';')
+		#print('function: %4d: %s' % (n, line))
+		info['type'] = 'func'
+		info['func'] = (n, line)
+	else:
+		info['type'] = 'bloc'
+
+	return info
+
+def process_file(f):
+	# type: (TextIOWrapper) -> List[Dict[str, Any]]
+	docs = []
+	lines = Lines(f)
+	for (n, l) in lines:
+		#print("%4d: %s" % (n, l))
+		if l.startswith('///'):
+			info = process_block(lines)
+			docs.append(info)
+
+	return docs
+
+def decorate(l):
+	# type: (str) -> str
+	l = re.sub(r"@(\w+)", "**\\1**", l)
+	return l
+
+def convert_to_rst(info):
+	# type: (Dict[str, Any]) -> List[Tuple[int, str]]
+	lst = []
+	#print('info= ' + str(info))
+	typ = info.get('type', '???')
+	if typ == '???':
+		## uh ?
+		pass
+	elif typ == 'bloc':
+		if 'short' in info:
+			(n, l) = info['short']
+			lst.append((n, l))
+		if 'desc' in info:
+			desc = info['desc']
+			n = desc[0] - 1
+			desc.append('')
+			for i in range(1, len(desc)):
+				l = desc[i]
+				lst.append((n+i, l))
+				# auto add a blank line for a list
+				if re.search(r":$", desc[i]) and re.search(r"\S", desc[i+1]):
+					lst.append((n+i, ''))
+
+	elif typ == 'func':
+		(n, l) = info['func']
+		l = '.. c:function:: ' + l
+		lst.append((n, l + '\n'))
+		if 'short' in info:
+			(n, l) = info['short']
+			l = l[0].capitalize() + l[1:].strip('.')
+			l = '\t' + l + '.'
+			lst.append((n, l + '\n'))
+		if 'tags' in info:
+			for (n, name, l) in info.get('tags', []):
+				if name != 'return':
+					name = 'param ' + name
+				l = decorate(l)
+				l = '\t:%s: %s' % (name, l)
+				l = '\n\t\t'.join(l.split('\n'))
+				lst.append((n, l))
+			lst.append((n+1, ''))
+		if 'desc' in info:
+			desc = info['desc']
+			n = desc[0]
+			r = ''
+			for l in desc[1:]:
+				l = decorate(l)
+				r += '\t' + l + '\n'
+			lst.append((n, r))
+	return lst
+
+def extract(f, filename):
+	# type: (TextIOWrapper, str) -> List[Tuple[int, str]]
+	res = process_file(f)
+	res = [ i for r in res for i in convert_to_rst(r) ]
+	return res
+
+def dump_doc(lst):
+	# type: (List[Tuple[int, str]]) -> None
+	for (n, lines) in lst:
+		for l in lines.split('\n'):
+			print('%4d: %s' % (n, l))
+			n += 1
+
+if __name__ == '__main__':
+	""" extract the doc from stdin """
+	import sys
+
+	dump_doc(extract(sys.stdin, '<stdin>'))
+
+
+from sphinx.ext.autodoc import AutodocReporter
+import docutils
+import os
+class CDocDirective(docutils.parsers.rst.Directive):
+	required_argument = 1
+	optional_arguments = 1
+	has_content = False
+	option_spec = {
+	}
+
+	def run(self):
+		env = self.state.document.settings.env
+		filename = os.path.join(env.config.cdoc_srcdir, self.arguments[0])
+		env.note_dependency(os.path.abspath(filename))
+
+		## create a (view) list from the extracted doc
+		lst = docutils.statemachine.ViewList()
+		f = open(filename, 'r')
+		for (lineno, lines) in extract(f, filename):
+			for l in lines.split('\n'):
+				lst.append(l.expandtabs(8), filename, lineno)
+				lineno += 1
+
+		## let parse this new reST content
+		memo = self.state.memo
+		save = memo.reporter, memo.title_styles, memo.section_level
+		memo.reporter = AutodocReporter(lst, memo.reporter)
+		node = docutils.nodes.section()
+		try:
+			self.state.nested_parse(lst, 0, node, match_titles=1)
+		finally:
+			memo.reporter, memo.title_styles, memo.section_level = save
+		return node.children
+
+def setup(app):
+	app.add_config_value('cdoc_srcdir', None, 'env')
+	app.add_directive_to_domain('c', 'autodoc', CDocDirective)
+
+	return {
+		'version': '1.0',
+		'parallel_read_safe': True,
+	}
+
+# vim: tabstop=4
--- /dev/null	Mon Nov 18 13:18:38 2019
+++ new/usr/src/tools/smatch/src/Documentation/sphinx/ir.py	Mon Nov 18 13:18:38 2019
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# SPDX_License-Identifier: MIT
+#
+# Copyright (C) 2018 Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
+#
+
+"""
+///
+// To document the instructions used in the intermediate representation
+// a new domain is defined: 'ir' with a directive::
+//
+//	.. op: <OP_NAME>
+//		<description of OP_NAME>
+//		...
+//
+// This is equivalent to using a definition list but with the name
+// also placed in the index (with 'IR instruction' as descriptions).
+
+"""
+
+import docutils
+import sphinx
+
+class IROpDirective(docutils.parsers.rst.Directive):
+
+	# use the first line of content as the argument, this allow
+	# to not have to write a blanck line after the directive
+	final_argument_whitespace = True
+	required_argument = 0
+	#optional_arguments = 0
+	has_content = True
+
+	objtype = None
+
+	def run(self):
+		self.env = self.state.document.settings.env
+
+		source = self.state.document
+		lineno = self.lineno
+		text = self.content
+		name = text[0]
+
+		node = docutils.nodes.section()
+		node['ids'].append(name)
+		node.document = source
+
+		index = '.. index:: pair: %s; IR instruction' % name
+		content = docutils.statemachine.ViewList()
+		content.append(index, source, lineno)
+		content.append(''   , source, lineno)
+		content.append(name , source, lineno)
+		content.append(''   , source, lineno)
+		self.state.nested_parse(content, self.content_offset, node)
+
+		defnode = docutils.nodes.definition()
+		self.state.nested_parse(text[1:], self.content_offset, defnode)
+		node.append(defnode)
+
+		return [node]
+
+class IRDomain(sphinx.domains.Domain):
+
+    """IR domain."""
+    name = 'ir'
+
+def setup(app):
+	app.add_domain(IRDomain)
+	app.add_directive_to_domain('ir', 'op', IROpDirective)
+
+	return {
+		'version': '1.0',
+		'parallel_read_safe': True,
+	}
+
+# vim: tabstop=4
--- old/usr/src/tools/smatch/src/Documentation/test-suite	Mon Nov 18 13:18:38 2019
+++ /dev/null	Mon Nov 18 13:18:38 2019
@@ -1,136 +0,0 @@
-
-
-	Sparse test suite
-	~~~~~~~~~~~~~~~~~
-
-Sparse has a number of test cases in its validation directory. The test-suite
-script aims at making automated checking of these tests possible. It works by
-embedding tags in C comments in the test cases.
-
-check-name: (mandatory)
-	Name of the test.
-
-check-description: (optional)
-	A description of what the test checks.
-
-check-command: (optional)
-	There are different kinds of tests. Some can validate the sparse
-	preprocessor, while others will use sparse, cgcc, or even other backends
-	of the library. check-command allows you to give a custom command to
-	run the test-case.
-	The '$file' string is special. It will be expanded to the file name at
-	run time.
-	It defaults to "sparse $file".
-
-check-exit-value: (optional)
-	The expected exit value of check-command. It defaults to 0.
-
-check-timeout: (optional)
-	The maximum expected duration of check-command, in seconds.
-	It defaults to 1.
-
-check-output-start / check-output-end (optional)
-	The expected output (stdout and stderr) of check-command lies between
-	those two tags. It defaults to no output.
-
-check-output-ignore / check-error-ignore (optional)
-	Don't check the expected output (stdout or stderr) of check-command
-	(useful when this output is not comparable or if you're only interested
-	in the exit value).
-	By default this check is done.
-
-check-known-to-fail (optional)
-	Mark the test as being known to fail.
-
-check-output-contains: <pattern> (optional)
-	Check that the output (stdout) contains the given pattern.
-	Several such tags can be given, in which case the output
-	must contains all the patterns.
-
-check-output-excludes: <pattern> (optional)
-	Similar than the above one, but with opposite logic.
-	Check that the output (stdout) doesn't contain the given pattern.
-	Several such tags can be given, in which case the output
-	must contains none of the patterns.
-
-check-output-pattern-<nbr>-times: <pattern> (optional)
-	Similar to the contains/excludes above, but with full control
-	of the number of times the pattern should occur in the output.
-
-	Using test-suite
-	~~~~~~~~~~~~~~~~
-
-The test-suite script is called through the check target of the Makefile. It
-will try to check every test case it finds (find validation -name '*.c').
-
-It can be called to check a single test with:
-$ cd validation
-$ ./test-suite single preprocessor/preprocessor1.c
-     TEST     Preprocessor #1 (preprocessor/preprocessor1.c)
-preprocessor/preprocessor1.c passed !
-
-
-	Writing a test
-	~~~~~~~~~~~~~~
-
-test-suite comes with a format command to make a test easier to write:
-
-	test-suite format file [name [cmd]]
-
-name:
-	check-name value. If no name is provided, it defaults to the file name.
-cmd:
-	check-command value. If no cmd is provided, it defaults to
-	"sparse $file".
-
-The output of the test-suite format command can be redirected into the
-test case to create a test-suite formatted file.
-
-$ ./test-suite format bad-assignment.c Assignment >> bad-assignment.c
-$ cat !$
-cat bad-assignment.c
-/*
- * check-name: bad assignment
- *
- * check-command: sparse $file
- * check-exit-value: 1
- *
- * check-output-start
-bad-assignment.c:3:6: error: Expected ; at end of statement
-bad-assignment.c:3:6: error: got \
- * check-output-end
- */
-
-You can define the check-command you want to use for the test. $file will be
-extended to the file name at run time.
-
-$ ./test-suite format validation/preprocessor2.c "Preprocessor #2" \
-		"sparse -E \$file" >> validation/preprocessor2.c
-$ cat !$
-cat validation/preprocessor2.c
-/*
- * This one we happen to get right.
- *
- * It should result in a simple
- *
- *	a + b
- *
- * for a proper preprocessor.
- */
-#define TWO a, b
-
-#define UNARY(x) BINARY(x)
-#define BINARY(x, y) x + y
-
-UNARY(TWO)
-/*
- * check-name: Preprocessor #2
- *
- * check-command: sparse -E $file
- * check-exit-value: 0
- *
- * check-output-start
-
-a + b
- * check-output-end
- */
--- /dev/null	Mon Nov 18 13:18:38 2019
+++ new/usr/src/tools/smatch/src/Documentation/test-suite.rst	Mon Nov 18 13:18:38 2019
@@ -0,0 +1,169 @@
+Test suite
+##########
+
+Sparse has a number of test cases in its validation directory. The test-suite
+script aims at making automated checking of these tests possible. It works by
+embedding tags in C comments in the test cases.
+
+Tag's syntax
+============
+
+``check-name:`` *name*
+
+	Name of the test. This is the only mandatory tag.
+
+``check-description:`` *description ...*
+
+	A description of what the test checks.
+
+``check-command:`` *command arg ...*
+
+	There are different kinds of tests. Some can validate the sparse
+	preprocessor, while others will use sparse, cgcc, or even other backends
+	of the library. check-command allows you to give a custom command to
+	run the test-case.
+	The ``$file`` string is special. It will be expanded to the file name at
+	run time.
+	It defaults to ``sparse $file``.
+
+``check-arch-ignore:`` *arch[|...]*
+
+``check-arch-only:`` *arch[|...]*
+
+	Ignore the test if the current architecture (as returned by ``uname -m``)
+	matches or not one of the archs given in the pattern.
+
+``check-assert:`` *condition*
+
+	Ignore the test if the given condition is false when evaluated as a
+	static assertion (``_Static_assert``).
+
+``check-cpp-if:`` *condition*
+
+	Ignore the test if the given condition is false when evaluated
+	by sparse's pre-processor.
+
+``check-exit-value:`` *value*
+
+	The expected exit value of check-command. It defaults to 0.
+
+``check-timeout:`` *timeout*
+
+	The maximum expected duration of check-command, in seconds.
+	It defaults to 1.
+
+``check-output-start`` / ``check-output-end``
+
+	The expected output (stdout and stderr) of check-command lies between
+	those two tags. It defaults to no output.
+
+``check-output-ignore`` / ``check-error-ignore``
+
+	Don't check the expected output (stdout or stderr) of check-command
+	(useful when this output is not comparable or if you're only interested
+	in the exit value).  By default this check is done.
+
+``check-known-to-fail``
+
+	Mark the test as being known to fail.
+
+``check-output-contains:`` *pattern*
+
+	Check that the output (stdout) contains the given pattern.
+	Several such tags can be given, in which case the output
+	must contains all the patterns.
+
+``check-output-excludes:`` *pattern*
+
+	Similar than the above one, but with opposite logic.
+	Check that the output (stdout) doesn't contain the given pattern.
+	Several such tags can be given, in which case the output
+	must contains none of the patterns.
+
+``check-output-pattern(``\ *nbr*\ ``):`` *pattern*
+
+``check-output-pattern(``\ *min*\ ``,``\ *max*\ ``):`` *pattern*
+
+	Similar to the contains/excludes above, but with full control
+	of the number of times the pattern should occur in the output.
+	If *min* or *max* is ``-`` the corresponding check is ignored.
+
+Using test-suite
+================
+
+The test-suite script is called through the check target of the Makefile. It
+will try to check every test case it finds (``find validation -name '*.c'``).
+It can be called to check a single test with::
+
+	$ cd validation
+	$ ./test-suite single preprocessor/preprocessor1.c
+	     TEST     Preprocessor #1 (preprocessor/preprocessor1.c)
+	preprocessor/preprocessor1.c passed !
+
+
+Writing a test
+==============
+
+The test-suite comes with a format command to make a test easier to write::
+
+	test-suite format [-a] [-l] [-f] file [name [cmd]]
+
+`name:`  check-name value
+	If no name is provided, it defaults to the file name.
+
+`cmd:`   check-command value
+	If no cmd is provided, it defaults to ``sparse $file``.
+
+The output of the test-suite format command can be redirected into the
+test case to create a test-suite formatted file.::
+
+	$ ./test-suite format bad-assignment.c Assignment >> bad-assignment.c
+	$ cat !$
+	cat bad-assignment.c
+	/*
+	 * check-name: bad assignment
+	 *
+	 * check-command: sparse $file
+	 * check-exit-value: 1
+	 *
+	 * check-output-start
+	bad-assignment.c:3:6: error: Expected ; at end of statement
+	bad-assignment.c:3:6: error: got \
+	 * check-output-end
+	 */
+
+The same effect without the redirection can be achieved by using the ``-a``
+option.
+
+You can define the check-command you want to use for the test.::
+
+	$ ./test-suite format -a validation/preprocessor2.c "Preprocessor #2" \
+			"sparse -E \$file"
+	$ cat !$
+	cat validation/preprocessor2.c
+	/*
+	 * This one we happen to get right.
+	 *
+	 * It should result in a simple
+	 *
+	 *	a + b
+	 *
+	 * for a proper preprocessor.
+	 */
+	#define TWO a, b
+
+	#define UNARY(x) BINARY(x)
+	#define BINARY(x, y) x + y
+
+	UNARY(TWO)
+	/*
+	 * check-name: Preprocessor #2
+	 *
+	 * check-command: sparse -E $file
+	 * check-exit-value: 0
+	 *
+	 * check-output-start
+
+	a + b
+	 * check-output-end
+	 */
--- old/usr/src/tools/smatch/src/Makefile	Mon Nov 18 13:18:38 2019
+++ new/usr/src/tools/smatch/src/Makefile	Mon Nov 18 13:18:38 2019
@@ -1,318 +1,390 @@
-VERSION=0.5.1-il-6
+VERSION=0.6.1-rc1-il1
 
-# Generating file version.h if current version has changed
-SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)')
-VERSION_H := $(shell cat version.h 2>/dev/null)
-ifneq ($(lastword $(VERSION_H)),"$(SPARSE_VERSION)")
-$(info $(shell echo '     GEN      'version.h))
-$(shell echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h)
-endif
-
+########################################################################
+# The following variables can be overwritten from the command line
 OS = linux
 
-ifeq ($(CC),"")
-CC = gcc
-endif
 
-CFLAGS += -O2 -finline-functions -fno-strict-aliasing -g
-CFLAGS += -Wall -Wwrite-strings -Wno-switch
-LDFLAGS += -g -lm -lsqlite3 -lssl -lcrypto
-LD = gcc
+CC ?= gcc
+LD = $(CC)
 AR = ar
-PKG_CONFIG = pkg-config
-COMMON_CFLAGS = -O2 -finline-functions -fno-strict-aliasing -g
-COMMON_CFLAGS += -Wall -Wwrite-strings
 
-ALL_CFLAGS = $(COMMON_CFLAGS) $(PKG_CFLAGS) $(CFLAGS)
-#
+CFLAGS ?= -O2 -g
+
+DESTDIR ?=
+PREFIX ?= $(HOME)
+BINDIR ?= $(PREFIX)/bin
+MANDIR ?= $(PREFIX)/share/man
+
+PKG_CONFIG ?= pkg-config
+
+CHECKER_FLAGS ?= -Wno-vla
+
+# Allow users to override build settings without dirtying their trees
 # For debugging, put this in local.mk:
 #
 #     CFLAGS += -O0 -DDEBUG -g3 -gdwarf-2
 #
+SPARSE_LOCAL_CONFIG ?= local.mk
+-include ${SPARSE_LOCAL_CONFIG}
+########################################################################
 
-HAVE_LIBXML:=$(shell $(PKG_CONFIG) --exists libxml-2.0 2>/dev/null && echo 'yes')
-HAVE_GCC_DEP:=$(shell touch .gcc-test.c && 				\
-		$(CC) -c -Wp,-MD,.gcc-test.d .gcc-test.c 2>/dev/null && \
-		echo 'yes'; rm -f .gcc-test.d .gcc-test.o .gcc-test.c)
 
-GTK_VERSION:=3.0
-HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
-ifneq ($(HAVE_GTK),yes)
-	GTK_VERSION:=2.0
-	HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
-endif
+LIB_OBJS :=
+LIB_OBJS += allocate.o
+LIB_OBJS += builtin.o
+LIB_OBJS += char.o
+LIB_OBJS += compat-$(OS).o
+LIB_OBJS += cse.o
+LIB_OBJS += dissect.o
+LIB_OBJS += dominate.o
+LIB_OBJS += evaluate.o
+LIB_OBJS += expand.o
+LIB_OBJS += expression.o
+LIB_OBJS += flow.o
+LIB_OBJS += flowgraph.o
+LIB_OBJS += inline.o
+LIB_OBJS += ir.o
+LIB_OBJS += lib.o
+LIB_OBJS += linearize.o
+LIB_OBJS += liveness.o
+LIB_OBJS += memops.o
+LIB_OBJS += opcode.o
+LIB_OBJS += optimize.o
+LIB_OBJS += parse.o
+LIB_OBJS += pre-process.o
+LIB_OBJS += ptrlist.o
+LIB_OBJS += ptrmap.o
+LIB_OBJS += scope.o
+LIB_OBJS += show-parse.o
+LIB_OBJS += simplify.o
+LIB_OBJS += sort.o
+LIB_OBJS += ssa.o
+LIB_OBJS += sset.o
+LIB_OBJS += stats.o
+LIB_OBJS += storage.o
+LIB_OBJS += symbol.o
+LIB_OBJS += target.o
+LIB_OBJS += tokenize.o
+LIB_OBJS += unssa.o
+LIB_OBJS += utils.o
+LIB_OBJS += macro_table.o
+LIB_OBJS += token_store.o
+LIB_OBJS += cwchash/hashtable.o
 
-LLVM_CONFIG:=llvm-config
-HAVE_LLVM:=$(shell $(LLVM_CONFIG) --version >/dev/null 2>&1 && echo 'yes')
+PROGRAMS :=
+PROGRAMS += compile
+PROGRAMS += ctags
+PROGRAMS += example
+PROGRAMS += graph
+PROGRAMS += obfuscate
+PROGRAMS += sparse
+PROGRAMS += test-dissect
+PROGRAMS += test-lexing
+PROGRAMS += test-linearize
+PROGRAMS += test-parsing
+PROGRAMS += test-unssa
 
-GCC_BASE := $(shell $(CC) --print-file-name=)
-COMMON_CFLAGS += -DGCC_BASE=\"$(GCC_BASE)\"
+INST_PROGRAMS=smatch sparse cgcc
+INST_MAN1=sparse.1 cgcc.1
 
-MULTIARCH_TRIPLET := $(shell $(CC) -print-multiarch 2>/dev/null)
-COMMON_CFLAGS += -DMULTIARCH_TRIPLET=\"$(MULTIARCH_TRIPLET)\"
 
-ifeq ($(HAVE_GCC_DEP),yes)
-COMMON_CFLAGS += -Wp,-MD,$(@D)/.$(@F).d
-endif
+all:
 
-DESTDIR=
-INSTALL_PREFIX ?=$(HOME)
-BINDIR=$(INSTALL_PREFIX)/bin
-LIBDIR=$(INSTALL_PREFIX)/lib
-MANDIR=$(INSTALL_PREFIX)/share/man
-MAN1DIR=$(MANDIR)/man1
-INCLUDEDIR=$(INSTALL_PREFIX)/include
-PKGCONFIGDIR=$(LIBDIR)/pkgconfig
-SMATCHDATADIR=$(INSTALL_PREFIX)/share/smatch
+########################################################################
+# common flags/options/...
 
-SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \
-	smatch_helper.o smatch_type.o smatch_hooks.o smatch_function_hooks.o \
-	smatch_modification_hooks.o smatch_extra.o smatch_estate.o smatch_math.o \
-	smatch_sval.o smatch_ranges.o smatch_implied.o smatch_ignore.o smatch_project.o \
-	smatch_var_sym.o smatch_tracker.o smatch_files.o smatch_expression_stacks.o \
-	smatch_equiv.o smatch_buf_size.o smatch_strlen.o smatch_capped.o smatch_db.o \
-	smatch_expressions.o smatch_returns.o smatch_parse_call_math.o \
-	smatch_param_limit.o smatch_param_filter.o \
-	smatch_param_set.o smatch_comparison.o smatch_param_compare_limit.o smatch_local_values.o \
-	smatch_function_ptrs.o smatch_annotate.o smatch_string_list.o \
-	smatch_param_cleared.o smatch_start_states.o \
-	smatch_recurse.o smatch_data_source.o smatch_type_val.o \
-	smatch_common_functions.o smatch_struct_assignment.o \
-	smatch_unknown_value.o smatch_stored_conditions.o avl.o \
-	smatch_function_info.o smatch_links.o smatch_auto_copy.o \
-	smatch_type_links.o smatch_untracked_param.o smatch_impossible.o \
-	smatch_strings.o smatch_param_used.o smatch_container_of.o smatch_address.o \
-	smatch_buf_comparison.o smatch_real_absolute.o smatch_scope.o \
-	smatch_imaginary_absolute.o smatch_parameter_names.o \
-	smatch_return_to_param.o smatch_passes_array_size.o \
-	smatch_constraints.o smatch_constraints_required.o \
-	smatch_fn_arg_link.o smatch_about_fn_ptr_arg.o smatch_mtag.o \
-	smatch_mtag_map.o smatch_mtag_data.o \
-	smatch_param_to_mtag_data.o smatch_mem_tracker.o smatch_array_values.o \
-	smatch_nul_terminator.o smatch_assigned_expr.o smatch_kernel_user_data.o \
-	smatch_statement_count.o smatch_integer_overflow.o smatch_bits.o
+cflags = -fno-strict-aliasing
+cflags += -Wall -Wwrite-strings -Wno-switch
 
-SMATCH_CHECKS=$(shell ls check_*.c | sed -e 's/\.c/.o/')
-SMATCH_DATA=smatch_data/kernel.allocation_funcs \
-	smatch_data/kernel.frees_argument smatch_data/kernel.puts_argument \
-	smatch_data/kernel.dev_queue_xmit smatch_data/kernel.returns_err_ptr \
-	smatch_data/kernel.dma_funcs smatch_data/kernel.returns_held_funcs \
-	smatch_data/kernel.no_return_funcs
+GCC_BASE := $(shell $(CC) --print-file-name=)
+cflags += -DGCC_BASE=\"$(GCC_BASE)\"
 
-SMATCH_SCRIPTS=smatch_scripts/add_gfp_to_allocations.sh \
-	smatch_scripts/build_kernel_data.sh \
-	smatch_scripts/call_tree.pl smatch_scripts/filter_kernel_deref_check.sh \
-	smatch_scripts/find_expanded_holes.pl smatch_scripts/find_null_params.sh \
-	smatch_scripts/follow_params.pl smatch_scripts/gen_allocation_list.sh \
-	smatch_scripts/gen_bit_shifters.sh smatch_scripts/gen_dma_funcs.sh \
-	smatch_scripts/generisize.pl smatch_scripts/gen_err_ptr_list.sh \
-	smatch_scripts/gen_expects_err_ptr.sh smatch_scripts/gen_frees_list.sh \
-	smatch_scripts/gen_gfp_flags.sh smatch_scripts/gen_no_return_funcs.sh \
-	smatch_scripts/gen_puts_list.sh smatch_scripts/gen_returns_held.sh \
-	smatch_scripts/gen_rosenberg_funcs.sh smatch_scripts/gen_sizeof_param.sh \
-	smatch_scripts/gen_unwind_functions.sh smatch_scripts/kchecker \
-	smatch_scripts/kpatch.sh smatch_scripts/new_bugs.sh \
-	smatch_scripts/show_errs.sh smatch_scripts/show_ifs.sh \
-	smatch_scripts/show_unreachable.sh smatch_scripts/strip_whitespace.pl \
-	smatch_scripts/summarize_errs.sh smatch_scripts/test_kernel.sh \
-	smatch_scripts/trace_params.pl smatch_scripts/unlocked_paths.pl \
-	smatch_scripts/whitespace_only.sh smatch_scripts/wine_checker.sh \
+MULTIARCH_TRIPLET := $(shell $(CC) -print-multiarch 2>/dev/null)
+cflags += -DMULTIARCH_TRIPLET=\"$(MULTIARCH_TRIPLET)\"
 
-PROGRAMS=test-lexing test-parsing obfuscate compile graph sparse \
-	 test-linearize example test-unssa test-dissect ctags
-INST_PROGRAMS=smatch cgcc
 
-INST_MAN1=sparse.1 cgcc.1
+bindir := $(DESTDIR)$(BINDIR)
+man1dir := $(DESTDIR)$(MANDIR)/man1
 
+########################################################################
+# target specificities
+
+compile: compile-i386.o
+EXTRA_OBJS += compile-i386.o
+
+# Can we use GCC's generated dependencies?
+HAVE_GCC_DEP:=$(shell touch .gcc-test.c && 				\
+		$(CC) -c -Wp,-MP,-MMD,.gcc-test.d .gcc-test.c 2>/dev/null && \
+		echo 'yes'; rm -f .gcc-test.d .gcc-test.o .gcc-test.c)
+ifeq ($(HAVE_GCC_DEP),yes)
+cflags += -Wp,-MP,-MMD,$(@D)/.$(@F).d
+endif
+
+# Can we use libxml (needed for c2xml)?
+HAVE_LIBXML:=$(shell $(PKG_CONFIG) --exists libxml-2.0 2>/dev/null && echo 'yes')
 ifeq ($(HAVE_LIBXML),yes)
 PROGRAMS+=c2xml
 INST_PROGRAMS+=c2xml
-c2xml_EXTRA_OBJS = `$(PKG_CONFIG) --libs libxml-2.0`
-LIBXML_CFLAGS := $(shell $(PKG_CONFIG) --cflags libxml-2.0)
+c2xml-ldlibs := $(shell $(PKG_CONFIG) --libs libxml-2.0)
+c2xml-cflags := $(shell $(PKG_CONFIG) --cflags libxml-2.0)
 else
 $(warning Your system does not have libxml, disabling c2xml)
 endif
 
+# Can we use gtk (needed for test-inspect)
+GTK_VERSION:=3.0
+HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
+ifneq ($(HAVE_GTK),yes)
+GTK_VERSION:=2.0
+HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
+endif
 ifeq ($(HAVE_GTK),yes)
 GTK_CFLAGS := $(shell $(PKG_CONFIG) --cflags gtk+-$(GTK_VERSION))
-GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-$(GTK_VERSION))
+ast-view-cflags := $(GTK_CFLAGS)
+ast-model-cflags := $(GTK_CFLAGS)
+ast-inspect-cflags := $(GTK_CFLAGS)
+test-inspect-cflags := $(GTK_CFLAGS)
+test-inspect-ldlibs := $(shell $(PKG_CONFIG) --libs gtk+-$(GTK_VERSION))
+test-inspect: ast-model.o ast-view.o ast-inspect.o
+EXTRA_OBJS += ast-model.o ast-view.o ast-inspect.o
 PROGRAMS += test-inspect
 INST_PROGRAMS += test-inspect
-test-inspect_EXTRA_DEPS := ast-model.o ast-view.o ast-inspect.o
-test-inspect_OBJS := test-inspect.o $(test-inspect_EXTRA_DEPS)
-$(test-inspect_OBJS) $(test-inspect_OBJS:.o=.sc): PKG_CFLAGS += $(GTK_CFLAGS)
-test-inspect_EXTRA_OBJS := $(GTK_LIBS)
 else
 $(warning Your system does not have gtk3/gtk2, disabling test-inspect)
 endif
 
+# Can we use LLVM (needed for ... sparse-llvm)?
+LLVM_CONFIG:=llvm-config
+HAVE_LLVM:=$(shell $(LLVM_CONFIG) --version >/dev/null 2>&1 && echo 'yes')
 ifeq ($(HAVE_LLVM),yes)
-ifeq ($(shell uname -m | grep -q '\(i386\|x86\)' && echo ok),ok)
+arch := $(shell uname -m)
+ifeq (${MULTIARCH_TRIPLET},x86_64-linux-gnux32)
+arch := x32
+endif
+ifneq ($(filter ${arch},i386 i486 i586 i686 x86_64 amd64),)
 LLVM_VERSION:=$(shell $(LLVM_CONFIG) --version)
 ifeq ($(shell expr "$(LLVM_VERSION)" : '[3-9]\.'),2)
 LLVM_PROGS := sparse-llvm
 $(LLVM_PROGS): LD := g++
 LLVM_LDFLAGS := $(shell $(LLVM_CONFIG) --ldflags)
-LLVM_CFLAGS := $(shell $(LLVM_CONFIG) --cflags | sed -e "s/-DNDEBUG//g" | sed -e "s/-pedantic//g")
+LLVM_CFLAGS := -I$(shell $(LLVM_CONFIG) --includedir)
 LLVM_LIBS := $(shell $(LLVM_CONFIG) --libs)
 LLVM_LIBS += $(shell $(LLVM_CONFIG) --system-libs 2>/dev/null)
+LLVM_LIBS += $(shell $(LLVM_CONFIG) --cxxflags | grep -F -q -e '-stdlib=libc++' && echo -lc++)
 PROGRAMS += $(LLVM_PROGS)
 INST_PROGRAMS += sparse-llvm sparsec
-sparse-llvm.o sparse-llvm.sc: PKG_CFLAGS += $(LLVM_CFLAGS)
-sparse-llvm_EXTRA_OBJS := $(LLVM_LIBS) $(LLVM_LDFLAGS)
+sparse-llvm-cflags := $(LLVM_CFLAGS) -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
+sparse-llvm-ldflags := $(LLVM_LDFLAGS)
+sparse-llvm-ldlibs := $(LLVM_LIBS)
 else
 $(warning LLVM 3.0 or later required. Your system has version $(LLVM_VERSION) installed.)
 endif
 else
-$(warning sparse-llvm disabled on $(shell uname -m))
+$(warning sparse-llvm disabled on ${arch})
 endif
 else
 $(warning Your system does not have llvm, disabling sparse-llvm)
 endif
 
-LIB_H=    token.h parse.h lib.h symbol.h scope.h expression.h target.h \
-	  linearize.h bitmap.h ident-list.h compat.h flow.h allocate.h \
-	  storage.h ptrlist.h dissect.h
+########################################################################
+LIBS := libsparse.a
+OBJS := $(LIB_OBJS) $(EXTRA_OBJS) $(PROGRAMS:%=%.o)
 
-LIB_OBJS= target.o parse.o tokenize.o pre-process.o symbol.o lib.o scope.o \
-	  expression.o show-parse.o evaluate.o expand.o inline.o linearize.o \
-	  char.o sort.o allocate.o compat-$(OS).o ptrlist.o \
-	  builtin.o \
-	  stats.o \
-	  flow.o cse.o simplify.o memops.o liveness.o storage.o unssa.o \
-	  dissect.o \
-	  macro_table.o token_store.o cwchash/hashtable.o
-
-LIB_FILE= libsparse.a
-SLIB_FILE= libsparse.so
-
-# If you add $(SLIB_FILE) to this, you also need to add -fpic to BASIC_CFLAGS above.
-# Doing so incurs a noticeable performance hit, and Sparse does not have a
-# stable shared library interface, so this does not occur by default.  If you
-# really want a shared library, you may want to build Sparse twice: once
-# without -fpic to get all the Sparse tools, and again with -fpic to get the
-# shared library.
-LIBS=$(LIB_FILE)
-
-#
 # Pretty print
-#
-V	      = @
-Q	      = $(V:1=)
-QUIET_CC      = $(Q:@=@echo    '     CC       '$@;)
-QUIET_CHECK   = $(Q:@=@echo    '     CHECK    '$<;)
-QUIET_AR      = $(Q:@=@echo    '     AR       '$@;)
-QUIET_GEN     = $(Q:@=@echo    '     GEN      '$@;)
-QUIET_LINK    = $(Q:@=@echo    '     LINK     '$@;)
-# We rely on the -v switch of install to print 'file -> $install_dir/file'
-QUIET_INST_SH = $(Q:@=echo -n  '     INSTALL  ';)
-QUIET_INST    = $(Q:@=@echo -n '     INSTALL  ';)
+V := @
+Q := $(V:1=)
 
-define INSTALL_EXEC
-	$(QUIET_INST)install -v $1 $(DESTDIR)$2/$1 || exit 1;
+########################################################################
 
-endef
+SMATCHDATADIR=$(INSTALL_PREFIX)/share/smatch
 
-define INSTALL_FILE
-	$(QUIET_INST)install -v -m 644 $1 $(DESTDIR)$2/$1 || exit 1;
+SMATCH_OBJS :=
+SMATCH_OBJS += avl.o
+SMATCH_OBJS += smatch_about_fn_ptr_arg.o
+SMATCH_OBJS += smatch_address.o
+SMATCH_OBJS += smatch_annotate.o
+SMATCH_OBJS += smatch_array_values.o
+SMATCH_OBJS += smatch_assigned_expr.o
+SMATCH_OBJS += smatch_bits.o
+SMATCH_OBJS += smatch_buf_comparison.o
+SMATCH_OBJS += smatch_buf_size.o
+SMATCH_OBJS += smatch_capped.o
+SMATCH_OBJS += smatch_common_functions.o
+SMATCH_OBJS += smatch_comparison.o
+SMATCH_OBJS += smatch_conditions.o
+SMATCH_OBJS += smatch_constraints.o
+SMATCH_OBJS += smatch_constraints_required.o
+SMATCH_OBJS += smatch_container_of.o
+SMATCH_OBJS += smatch_data_source.o
+SMATCH_OBJS += smatch_db.o
+SMATCH_OBJS += smatch_equiv.o
+SMATCH_OBJS += smatch_estate.o
+SMATCH_OBJS += smatch_expressions.o
+SMATCH_OBJS += smatch_expression_stacks.o
+SMATCH_OBJS += smatch_extra.o
+SMATCH_OBJS += smatch_files.o
+SMATCH_OBJS += smatch_flow.o
+SMATCH_OBJS += smatch_fn_arg_link.o
+SMATCH_OBJS += smatch_function_hooks.o
+SMATCH_OBJS += smatch_function_info.o
+SMATCH_OBJS += smatch_function_ptrs.o
+SMATCH_OBJS += smatch_helper.o
+SMATCH_OBJS += smatch_hooks.o
+SMATCH_OBJS += smatch_ignore.o
+SMATCH_OBJS += smatch_imaginary_absolute.o
+SMATCH_OBJS += smatch_implied.o
+SMATCH_OBJS += smatch_impossible.o
+SMATCH_OBJS += smatch_integer_overflow.o
+SMATCH_OBJS += smatch_kernel_user_data.o
+SMATCH_OBJS += smatch_links.o
+SMATCH_OBJS += smatch_math.o
+SMATCH_OBJS += smatch_mem_tracker.o
+SMATCH_OBJS += smatch_modification_hooks.o
+SMATCH_OBJS += smatch_mtag_data.o
+SMATCH_OBJS += smatch_mtag_map.o
+SMATCH_OBJS += smatch_mtag.o
+SMATCH_OBJS += smatch_nul_terminator.o
+SMATCH_OBJS += smatch_param_cleared.o
+SMATCH_OBJS += smatch_param_compare_limit.o
+SMATCH_OBJS += smatch_parameter_names.o
+SMATCH_OBJS += smatch_param_filter.o
+SMATCH_OBJS += smatch_param_limit.o
+SMATCH_OBJS += smatch_param_set.o
+SMATCH_OBJS += smatch_param_to_mtag_data.o
+SMATCH_OBJS += smatch_param_used.o
+SMATCH_OBJS += smatch_parse_call_math.o
+SMATCH_OBJS += smatch_passes_array_size.o
+SMATCH_OBJS += smatch_project.o
+SMATCH_OBJS += smatch_ranges.o
+SMATCH_OBJS += smatch_real_absolute.o
+SMATCH_OBJS += smatch_recurse.o
+SMATCH_OBJS += smatch_returns.o
+SMATCH_OBJS += smatch_return_to_param.o
+SMATCH_OBJS += smatch_scope.o
+SMATCH_OBJS += smatch_slist.o
+SMATCH_OBJS += smatch_start_states.o
+SMATCH_OBJS += smatch_statement_count.o
+SMATCH_OBJS += smatch_states.o
+SMATCH_OBJS += smatch_stored_conditions.o
+SMATCH_OBJS += smatch_string_list.o
+SMATCH_OBJS += smatch_strings.o
+SMATCH_OBJS += smatch_strlen.o
+SMATCH_OBJS += smatch_struct_assignment.o
+SMATCH_OBJS += smatch_sval.o
+SMATCH_OBJS += smatch_tracker.o
+SMATCH_OBJS += smatch_type_links.o
+SMATCH_OBJS += smatch_type.o
+SMATCH_OBJS += smatch_type_val.o
+SMATCH_OBJS += smatch_unknown_value.o
+SMATCH_OBJS += smatch_untracked_param.o
+SMATCH_OBJS += smatch_var_sym.o
 
-endef
+SMATCH_CHECKS=$(shell ls check_*.c | sed -e 's/\.c/.o/')
+SMATCH_DATA=smatch_data/kernel.allocation_funcs \
+	smatch_data/kernel.frees_argument smatch_data/kernel.puts_argument \
+	smatch_data/kernel.dev_queue_xmit smatch_data/kernel.returns_err_ptr \
+	smatch_data/kernel.dma_funcs smatch_data/kernel.returns_held_funcs \
+	smatch_data/kernel.no_return_funcs
 
-SED_PC_CMD = 's|@version@|$(VERSION)|g;		\
-	      s|@prefix@|$(INSTALL_PREFIX)|g;		\
-	      s|@libdir@|$(LIBDIR)|g;		\
-	      s|@includedir@|$(INCLUDEDIR)|g'
+SMATCH_SCRIPTS=smatch_scripts/add_gfp_to_allocations.sh \
+	smatch_scripts/build_kernel_data.sh \
+	smatch_scripts/call_tree.pl smatch_scripts/filter_kernel_deref_check.sh \
+	smatch_scripts/find_expanded_holes.pl smatch_scripts/find_null_params.sh \
+	smatch_scripts/follow_params.pl smatch_scripts/gen_allocation_list.sh \
+	smatch_scripts/gen_bit_shifters.sh smatch_scripts/gen_dma_funcs.sh \
+	smatch_scripts/generisize.pl smatch_scripts/gen_err_ptr_list.sh \
+	smatch_scripts/gen_expects_err_ptr.sh smatch_scripts/gen_frees_list.sh \
+	smatch_scripts/gen_gfp_flags.sh smatch_scripts/gen_no_return_funcs.sh \
+	smatch_scripts/gen_puts_list.sh smatch_scripts/gen_returns_held.sh \
+	smatch_scripts/gen_rosenberg_funcs.sh smatch_scripts/gen_sizeof_param.sh \
+	smatch_scripts/gen_unwind_functions.sh smatch_scripts/kchecker \
+	smatch_scripts/kpatch.sh smatch_scripts/new_bugs.sh \
+	smatch_scripts/show_errs.sh smatch_scripts/show_ifs.sh \
+	smatch_scripts/show_unreachable.sh smatch_scripts/strip_whitespace.pl \
+	smatch_scripts/summarize_errs.sh smatch_scripts/test_kernel.sh \
+	smatch_scripts/trace_params.pl smatch_scripts/unlocked_paths.pl \
+	smatch_scripts/whitespace_only.sh smatch_scripts/wine_checker.sh \
 
+SMATCH_LDFLAGS := -lsqlite3  -lssl -lcrypto -lm
 
+smatch: smatch.o $(SMATCH_OBJS) $(SMATCH_CHECKS) $(LIBS)
+	$(Q)$(LD) -o $@ $< $(SMATCH_OBJS) $(SMATCH_CHECKS) $(LIBS) $(SMATCH_LDFLAGS)
 
-# Allow users to override build settings without dirtying their trees
--include local.mk
-
-
-all: $(PROGRAMS) sparse.pc smatch
-
-all-installable: $(INST_PROGRAMS) $(LIBS) $(LIB_H) sparse.pc
-
-install: all-installable
-	$(Q)install -d $(DESTDIR)$(BINDIR)
-	$(Q)install -d $(DESTDIR)$(LIBDIR)
-	$(Q)install -d $(DESTDIR)$(MAN1DIR)
-	$(Q)install -d $(DESTDIR)$(INCLUDEDIR)/sparse
-	$(Q)install -d $(DESTDIR)$(PKGCONFIGDIR)
-	$(Q)install -d $(DESTDIR)$(SMATCHDATADIR)/smatch_data
-	$(Q)install -d $(DESTDIR)$(SMATCHDATADIR)/smatch_scripts
-	$(foreach f,$(INST_PROGRAMS),$(call INSTALL_EXEC,$f,$(BINDIR)))
-	$(foreach f,$(INST_MAN1),$(call INSTALL_FILE,$f,$(MAN1DIR)))
-	$(foreach f,$(LIBS),$(call INSTALL_FILE,$f,$(LIBDIR)))
-	$(foreach f,$(LIB_H),$(call INSTALL_FILE,$f,$(INCLUDEDIR)/sparse))
-	$(call INSTALL_FILE,sparse.pc,$(PKGCONFIGDIR))
-	$(foreach f,$(SMATCH_DATA),$(call INSTALL_FILE,$f,$(SMATCHDATADIR)))
-	$(foreach f,$(SMATCH_SCRIPTS),$(call INSTALL_EXEC,$f,$(SMATCHDATADIR)))
-
-sparse.pc: sparse.pc.in
-	$(QUIET_GEN)sed $(SED_PC_CMD) sparse.pc.in > sparse.pc
-
-
-compile_EXTRA_DEPS = compile-i386.o
-
-$(foreach p,$(PROGRAMS),$(eval $(p): $($(p)_EXTRA_DEPS) $(LIBS)))
-$(PROGRAMS): % : %.o 
-	$(QUIET_LINK)$(LD) -o $@ $^ $($@_EXTRA_OBJS) $(LDFLAGS)
-
-smatch: smatch.o $(SMATCH_FILES) $(SMATCH_CHECKS) $(LIBS) 
-	$(QUIET_LINK)$(LD) -o $@ $< $(SMATCH_FILES) $(SMATCH_CHECKS) $(LIBS) $(LDFLAGS)
-
-$(LIB_FILE): $(LIB_OBJS)
-	$(QUIET_AR)$(AR) rcs $@ $(LIB_OBJS)
-
-$(SLIB_FILE): $(LIB_OBJS)
-	$(QUIET_LINK)$(CC) -Wl,-soname,$@ -shared -o $@ $(LIB_OBJS) $(LDFLAGS)
-
 check_list_local.h:
 	touch check_list_local.h
 
 smatch.o: smatch.c $(LIB_H) smatch.h check_list.h check_list_local.h
 	$(CC) $(CFLAGS) -c smatch.c -DSMATCHDATADIR='"$(SMATCHDATADIR)"'
-$(SMATCH_CHECKS): smatch.h smatch_slist.h smatch_extra.h avl.h
-DEP_FILES := $(wildcard .*.o.d)
 
-ifneq ($(DEP_FILES),)
-include $(DEP_FILES)
-endif
+$(SMATCH_OBJS) $(SMATCH_CHECKS): smatch.h smatch_slist.h smatch_extra.h avl.h
 
-c2xml.o c2xml.sc: PKG_CFLAGS += $(LIBXML_CFLAGS)
+########################################################################
+all: $(PROGRAMS) smatch
 
-pre-process.sc: CHECKER_FLAGS += -Wno-vla
+ldflags += $($(@)-ldflags) $(LDFLAGS)
+ldlibs  += $($(@)-ldlibs)  $(LDLIBS) -lm
+$(PROGRAMS): % : %.o $(LIBS)
+	@echo "  LD      $@"
+	$(Q)$(LD) $(ldflags) $^ $(ldlibs) -o $@
 
-%.o: %.c $(LIB_H)
-	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+libsparse.a: $(LIB_OBJS)
+	@echo "  AR      $@"
+	$(Q)$(AR) rcs $@ $^
 
-%.sc: %.c sparse
-	$(QUIET_CHECK) $(CHECKER) $(CHECKER_FLAGS) -c $(ALL_CFLAGS) $<
 
-ALL_OBJS :=  $(LIB_OBJS) $(foreach p,$(PROGRAMS),$(p).o $($(p)_EXTRA_DEPS))
-selfcheck: $(ALL_OBJS:.o=.sc)
+cflags   += $($(*)-cflags) $(CPPFLAGS) $(CFLAGS)
+%.o: %.c
+	@echo "  CC      $@"
+	$(Q)$(CC) $(cflags) -c -o $@ $<
 
+%.sc: %.c sparse
+	@echo "  CHECK   $<"
+	$(Q)CHECK=./sparse ./cgcc -no-compile $(CHECKER_FLAGS) $(cflags) -c $<
 
-clean: clean-check
-	rm -f *.[oa] .*.d *.so cwchash/*.o cwchash/.*.d cwchash/tester \
-		$(PROGRAMS) $(SLIB_FILE) pre-process.h sparse.pc version.h
+selfcheck: $(OBJS:.o=.sc)
 
-dist:
-	@if test "$(SPARSE_VERSION)" != "v$(VERSION)" ; then \
-		echo 'Update VERSION in the Makefile before running "make dist".' ; \
-		exit 1 ; \
+
+SPARSE_VERSION:=$(shell git describe --dirty 2>/dev/null || echo '$(VERSION)')
+lib.o: version.h
+version.h: FORCE
+	@echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h.tmp
+	@if cmp -s version.h version.h.tmp; then \
+		rm version.h.tmp; \
+	else \
+		echo "  GEN     $@"; \
+		mv version.h.tmp version.h; \
 	fi
-	git archive --format=tar --prefix=sparse-$(VERSION)/ HEAD^{tree} | gzip -9 > sparse-$(VERSION).tar.gz
 
+
 check: all
 	$(Q)cd validation && ./test-suite
+validation/%.t: $(PROGRAMS)
+	@validation/test-suite single $*.c
 
+
+clean: clean-check
+	@rm -f *.[oa] .*.d $(PROGRAMS) version.h smatch
 clean-check:
-	find validation/ \( -name "*.c.output.expected" \
-	                 -o -name "*.c.output.got" \
-	                 -o -name "*.c.output.diff" \
-	                 -o -name "*.c.error.expected" \
-	                 -o -name "*.c.error.got" \
-	                 -o -name "*.c.error.diff" \
-	                 \) -exec rm {} \;
+	@echo "  CLEAN"
+	@find validation/ \( -name "*.c.output.*" \
+			  -o -name "*.c.error.*" \
+			  -o -name "*.o" \
+	                  \) -exec rm {} \;
+
+
+install: install-bin install-man
+install-bin: $(INST_PROGRAMS:%=$(bindir)/%)
+install-man: $(INST_MAN1:%=$(man1dir)/%)
+
+$(bindir)/%: %
+	@echo "  INSTALL $@"
+	$(Q)install -D        $< $@ || exit 1;
+$(man1dir)/%: %
+	@echo "  INSTALL $@"
+	$(Q)install -D -m 644 $< $@ || exit 1;
+
+.PHONY: FORCE
+
+# GCC's dependencies
+-include $(OBJS:%.o=.%.o.d)
--- old/usr/src/tools/smatch/src/README	Mon Nov 18 13:18:38 2019
+++ new/usr/src/tools/smatch/src/README	Mon Nov 18 13:18:39 2019
@@ -1,3 +1,72 @@
-There are some documents under the Documentation/ directory.
-
 For parsing implicit dependencies, see smatch_scripts/implicit_dependencies.
+=======
+  sparse (spärs), adj,., spars-er, spars-est.
+	1. thinly scattered or distributed; "a sparse population"
+	2. thin; not thick or dense: "sparse hair"
+	3. scanty; meager.
+	4. semantic parse
+  	[ from Latin: spars(us) scattered, past participle of
+	  spargere 'to sparge' ]
+
+	Antonym: abundant
+
+Sparse is a semantic parser of source files: it's neither a compiler
+(although it could be used as a front-end for one) nor is it a
+preprocessor (although it contains as a part of it a preprocessing
+phase).
+
+It is meant to be a small - and simple - library.  Scanty and meager,
+and partly because of that easy to use.  It has one mission in life:
+create a semantic parse tree for some arbitrary user for further
+analysis.  It's not a tokenizer, nor is it some generic context-free
+parser.  In fact, context (semantics) is what it's all about - figuring
+out not just what the grouping of tokens are, but what the _types_ are
+that the grouping implies.
+
+And no, it doesn't use lex and yacc (or flex and bison).  In my personal
+opinion, the result of using lex/yacc tends to end up just having to
+fight the assumptions the tools make.
+
+The parsing is done in five phases:
+
+ - full-file tokenization
+ - pre-processing (which can cause another tokenization phase of another
+   file)
+ - semantic parsing.
+ - lazy type evaluation
+ - inline function expansion and tree simplification
+
+Note the "full file" part. Partly for efficiency, but mostly for ease of
+use, there are no "partial results". The library completely parses one
+whole source file, and builds up the _complete_ parse tree in memory.
+
+Also note the "lazy" in the type evaluation.  The semantic parsing
+itself will know which symbols are typedefines (required for parsing C
+correctly), but it will not have calculated what the details of the
+different types are.  That will be done only on demand, as the back-end
+requires the information. 
+
+This means that a user of the library will literally just need to do
+
+  struct string_list *filelist = NULL;
+  char *file;
+
+  action(sparse_initialize(argc, argv, filelist));
+
+  FOR_EACH_PTR(filelist, file) {
+    action(sparse(file));
+  } END_FOR_EACH_PTR(file);
+
+and he is now done - having a full C parse of the file he opened.  The
+library doesn't need any more setup, and once done does not impose any
+more requirements.  The user is free to do whatever he wants with the
+parse tree that got built up, and needs not worry about the library ever
+again.  There is no extra state, there are no parser callbacks, there is
+only the parse tree that is described by the header files. The action
+funtion takes a pointer to a symbol_list and does whatever it likes with it.
+
+The library also contains (as an example user) a few clients that do the
+preprocessing, parsing and type evaluation and just print out the
+results.  These clients were done to verify and debug the library, and
+also as trivial examples of what you can do with the parse tree once it
+is formed, so that users can see how the tree is organized.
--- old/usr/src/tools/smatch/src/allocate.c	Mon Nov 18 13:18:39 2019
+++ new/usr/src/tools/smatch/src/allocate.c	Mon Nov 18 13:18:39 2019
@@ -103,6 +103,8 @@
 		struct allocation_blob *newblob = blob_alloc(chunking);
 		if (!newblob)
 			die("out of memory");
+		if (size > chunking)
+			die("alloc too big");
 		desc->total_bytes += chunking;
 		newblob->next = blob;
 		blob = newblob;
--- old/usr/src/tools/smatch/src/allocate.h	Mon Nov 18 13:18:39 2019
+++ new/usr/src/tools/smatch/src/allocate.h	Mon Nov 18 13:18:39 2019
@@ -1,6 +1,8 @@
 #ifndef ALLOCATE_H
 #define ALLOCATE_H
 
+#include "compat.h"
+
 struct allocation_blob {
 	struct allocation_blob *next;
 	unsigned int left, offset;
--- /dev/null	Mon Nov 18 13:18:40 2019
+++ new/usr/src/tools/smatch/src/bits.h	Mon Nov 18 13:18:40 2019
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Helper functions for manipulation & testing of integer values
+ * like zero or sign-extensions.
+ *
+ * Copyright (C) 2017 Luc Van Oostenryck
+ *
+ */
+
+#ifndef BITS_H
+#define BITS_H
+
+static inline unsigned long long sign_bit(unsigned size)
+{
+	return 1ULL << (size - 1);
+}
+
+static inline unsigned long long sign_mask(unsigned size)
+{
+	unsigned long long sbit = sign_bit(size);
+	return sbit - 1;
+}
+
+static inline unsigned long long bits_mask(unsigned size)
+{
+	unsigned long long sbit = sign_bit(size);
+	return sbit | (sbit - 1);
+}
+
+
+static inline long long zero_extend(long long val, unsigned size)
+{
+	return val & bits_mask(size);
+}
+
+static inline long long sign_extend(long long val, unsigned size)
+{
+	if (val & sign_bit(size))
+		val |= ~sign_mask(size);
+	return val;
+}
+
+///
+// sign extend @val but only if exactly representable
+static inline long long sign_extend_safe(long long val, unsigned size)
+{
+	unsigned long long mask = bits_mask(size);
+	if (!(val & ~mask))
+		val = sign_extend(val, size);
+	return val;
+}
+
+static inline long long bits_extend(long long val, unsigned size, int is_signed)
+{
+	val = zero_extend(val, size);
+	if (is_signed)
+		val = sign_extend(val, size);
+	return val;
+}
+
+#endif
--- old/usr/src/tools/smatch/src/builtin.c	Mon Nov 18 13:18:40 2019
+++ new/usr/src/tools/smatch/src/builtin.c	Mon Nov 18 13:18:40 2019
@@ -24,9 +24,11 @@
  */
 
 #include "expression.h"
+#include "evaluate.h"
 #include "expand.h"
 #include "symbol.h"
 #include "compat/bswap.h"
+#include <stdarg.h>
 
 static int evaluate_to_int_const_expr(struct expression *expr)
 {
@@ -50,37 +52,41 @@
 	return 1;
 }
 
-
-static int evaluate_expect(struct expression *expr)
+/*
+ * eval_args - check the number of arguments and evaluate them.
+ */
+static int eval_args(struct expression *expr, int n)
 {
-	/* Should we evaluate it to return the type of the first argument? */
-	expr->ctype = &int_ctype;
-	return 1;
-}
-
-static int arguments_choose(struct expression *expr)
-{
-	struct expression_list *arglist = expr->args;
 	struct expression *arg;
-	int i = 0;
+	struct symbol *sym;
+	const char *msg;
+	int rc = 1;
 
-	FOR_EACH_PTR (arglist, arg) {
+	FOR_EACH_PTR(expr->args, arg) {
+		if (n-- == 0) {
+			msg = "too many arguments";
+			goto error;
+		}
 		if (!evaluate_expression(arg))
-			return 0;
-		i++;
+			rc = 0;
 	} END_FOR_EACH_PTR(arg);
-	if (i < 3) {
-		sparse_error(expr->pos,
-			     "not enough arguments for __builtin_choose_expr");
-		return 0;
-	} if (i > 3) {
-		sparse_error(expr->pos,
-			     "too many arguments for __builtin_choose_expr");
-		return 0;
+	if (n > 0) {
+		msg = "not enough arguments";
+		goto error;
 	}
-	return 1;
+	return rc;
+
+error:
+	sym = expr->fn->ctype;
+	expression_error(expr, "%s for %s", msg, show_ident(sym->ident));
+	return 0;
 }
 
+static int args_triadic(struct expression *expr)
+{
+	return eval_args(expr, 3);
+}
+
 static int evaluate_choose(struct expression *expr)
 {
 	struct expression_list *list = expr->args;
@@ -185,13 +191,12 @@
 };
 
 static struct symbol_op expect_op = {
-	.evaluate = evaluate_expect,
 	.expand = expand_expect
 };
 
 static struct symbol_op choose_op = {
+	.args = args_triadic,
 	.evaluate = evaluate_choose,
-	.args = arguments_choose,
 };
 
 /* The argument is constant and valid if the cost is zero */
@@ -225,6 +230,92 @@
 };
 
 
+static int evaluate_fp_unop(struct expression *expr)
+{
+	struct expression *arg;
+
+	if (!eval_args(expr, 1))
+		return 0;
+
+	arg = first_expression(expr->args);
+	if (!is_float_type(arg->ctype)) {
+		expression_error(expr, "non-floating-point argument in call to %s()",
+			show_ident(expr->fn->ctype->ident));
+		return 0;
+	}
+	return 1;
+}
+
+static struct symbol_op fp_unop_op = {
+	.evaluate = evaluate_fp_unop,
+};
+
+
+static int evaluate_overflow_gen(struct expression *expr, int ptr)
+{
+	struct expression *arg;
+	int n = 0;
+
+	/* there will be exactly 3; we'd already verified that */
+	FOR_EACH_PTR(expr->args, arg) {
+		struct symbol *type;
+
+		n++;
+		if (!arg || !(type = arg->ctype))
+			return 0;
+		// 1st & 2nd args must be a basic integer type
+		// 3rd arg must be a pointer to such a type.
+		if (n == 3 && ptr) {
+			if (type->type == SYM_NODE)
+				type = type->ctype.base_type;
+			if (!type)
+				return 0;
+			if (type->type != SYM_PTR)
+				goto err;
+			type = type->ctype.base_type;
+			if (!type)
+				return 0;
+		}
+		if (type->type == SYM_NODE)
+			type = type->ctype.base_type;
+		if (!type)
+			return 0;
+		if (type->ctype.base_type != &int_type || type == &bool_ctype)
+			goto err;
+	} END_FOR_EACH_PTR(arg);
+
+	// the builtin returns a bool
+	expr->ctype = &bool_ctype;
+	return 1;
+
+err:
+	sparse_error(arg->pos, "invalid type for argument %d:", n);
+	info(arg->pos, "        %s", show_typename(arg->ctype));
+	expr->ctype = &bad_ctype;
+	return 0;
+}
+
+static int evaluate_overflow(struct expression *expr)
+{
+	return evaluate_overflow_gen(expr, 1);
+}
+
+static struct symbol_op overflow_op = {
+	.args = args_triadic,
+	.evaluate = evaluate_overflow,
+};
+
+static int evaluate_overflow_p(struct expression *expr)
+{
+	return evaluate_overflow_gen(expr, 0);
+}
+
+static struct symbol_op overflow_p_op = {
+	.args = args_triadic,
+	.evaluate = evaluate_overflow_p,
+};
+
+
 /*
  * Builtin functions
  */
@@ -240,9 +331,21 @@
 	{ "__builtin_warning", &builtin_fn_type, MOD_TOPLEVEL, &warning_op },
 	{ "__builtin_expect", &builtin_fn_type, MOD_TOPLEVEL, &expect_op },
 	{ "__builtin_choose_expr", &builtin_fn_type, MOD_TOPLEVEL, &choose_op },
-	{ "__builtin_bswap16", NULL, MOD_TOPLEVEL, &bswap_op },
-	{ "__builtin_bswap32", NULL, MOD_TOPLEVEL, &bswap_op },
-	{ "__builtin_bswap64", NULL, MOD_TOPLEVEL, &bswap_op },
+	{ "__builtin_bswap16", &builtin_fn_type, MOD_TOPLEVEL, &bswap_op },
+	{ "__builtin_bswap32", &builtin_fn_type, MOD_TOPLEVEL, &bswap_op },
+	{ "__builtin_bswap64", &builtin_fn_type, MOD_TOPLEVEL, &bswap_op },
+	{ "__builtin_isfinite", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+	{ "__builtin_isinf", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+	{ "__builtin_isinf_sign", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+	{ "__builtin_isnan", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+	{ "__builtin_isnormal", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+	{ "__builtin_signbit", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op },
+	{ "__builtin_add_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+	{ "__builtin_sub_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+	{ "__builtin_mul_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op },
+	{ "__builtin_add_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+	{ "__builtin_sub_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
+	{ "__builtin_mul_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op },
 	{ NULL,		NULL,		0 }
 };
 
@@ -257,5 +360,199 @@
 		sym->ctype.base_type = ptr->base_type;
 		sym->ctype.modifiers = ptr->modifiers;
 		sym->op = ptr->op;
+		sym->builtin = 1;
 	}
+}
+
+static void declare_builtin(const char *name, struct symbol *rtype, int variadic, ...)
+{
+	int stream = 0;			// FIXME
+	struct symbol *sym = create_symbol(stream, name, SYM_NODE, NS_SYMBOL);
+	struct symbol *fun = alloc_symbol(sym->pos, SYM_FN);
+	struct symbol *arg;
+	va_list args;
+
+	sym->ctype.base_type = fun;
+	sym->ctype.modifiers = MOD_TOPLEVEL;
+	sym->builtin = 1;
+
+	fun->ctype.base_type = rtype;
+	fun->variadic = variadic;
+
+	va_start(args, variadic);
+	while ((arg = va_arg(args, struct symbol *))) {
+		struct symbol *anode = alloc_symbol(sym->pos, SYM_NODE);
+		anode->ctype.base_type = arg;
+		add_symbol(&fun->arguments, anode);
+	}
+	va_end(args);
+}
+
+void declare_builtins(void)
+{
+	struct symbol *va_list_ctype = &ptr_ctype;
+
+	declare_builtin("__builtin_abort", &void_ctype, 0, NULL);
+	declare_builtin("__builtin_abs", &int_ctype , 0, &int_ctype, NULL);
+	declare_builtin("__builtin_alloca", &ptr_ctype, 0, size_t_ctype, NULL);
+	declare_builtin("__builtin_alpha_cmpbge", &long_ctype, 0, &long_ctype, &long_ctype, NULL);
+	declare_builtin("__builtin_alpha_extbl", &long_ctype, 0, &long_ctype, &long_ctype, NULL);
+	declare_builtin("__builtin_alpha_extwl", &long_ctype, 0, &long_ctype, &long_ctype, NULL);
+	declare_builtin("__builtin_alpha_insbl", &long_ctype, 0, &long_ctype, &long_ctype, NULL);
+	declare_builtin("__builtin_alpha_inslh", &long_ctype, 0, &long_ctype, &long_ctype, NULL);
+	declare_builtin("__builtin_alpha_insql", &long_ctype, 0, &long_ctype, &long_ctype, NULL);
+	declare_builtin("__builtin_alpha_inswl", &long_ctype, 0, &long_ctype, &long_ctype, NULL);
+	declare_builtin("__builtin_bcmp", &int_ctype , 0, &const_ptr_ctype, &const_ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_bcopy", &void_ctype, 0, &const_ptr_ctype, &ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_bswap16", &ushort_ctype, 0, &ushort_ctype, NULL);
+	declare_builtin("__builtin_bswap32", &uint_ctype, 0, &uint_ctype, NULL);
+	declare_builtin("__builtin_bswap64", &ullong_ctype, 0, &ullong_ctype, NULL);
+	declare_builtin("__builtin_bzero", &void_ctype, 0, &ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_calloc", &ptr_ctype, 0, size_t_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_clrsb", &int_ctype, 0, &int_ctype, NULL);
+	declare_builtin("__builtin_clrsbl", &int_ctype, 0, &long_ctype, NULL);
+	declare_builtin("__builtin_clrsbll", &int_ctype, 0, &llong_ctype, NULL);
+	declare_builtin("__builtin_clz", &int_ctype, 0, &int_ctype, NULL);
+	declare_builtin("__builtin_clzl", &int_ctype, 0, &long_ctype, NULL);
+	declare_builtin("__builtin_clzll", &int_ctype, 0, &llong_ctype, NULL);
+	declare_builtin("__builtin_ctz", &int_ctype, 0, &int_ctype, NULL);
+	declare_builtin("__builtin_ctzl", &int_ctype, 0, &long_ctype, NULL);
+	declare_builtin("__builtin_ctzll", &int_ctype, 0, &llong_ctype, NULL);
+	declare_builtin("__builtin_exit", &void_ctype, 0, &int_ctype, NULL);
+	declare_builtin("__builtin_expect", &long_ctype, 0, &long_ctype ,&long_ctype, NULL);
+	declare_builtin("__builtin_extract_return_addr", &ptr_ctype, 0, &ptr_ctype, NULL);
+	declare_builtin("__builtin_fabs", &double_ctype, 0, &double_ctype, NULL);
+	declare_builtin("__builtin_ffs", &int_ctype, 0, &int_ctype, NULL);
+	declare_builtin("__builtin_ffsl", &int_ctype, 0, &long_ctype, NULL);
+	declare_builtin("__builtin_ffsll", &int_ctype, 0, &llong_ctype, NULL);
+	declare_builtin("__builtin_frame_address", &ptr_ctype, 0, &uint_ctype, NULL);
+	declare_builtin("__builtin_free", &void_ctype, 0, &ptr_ctype, NULL);
+	declare_builtin("__builtin_huge_val", &double_ctype, 0, NULL);
+	declare_builtin("__builtin_huge_valf", &float_ctype, 0, NULL);
+	declare_builtin("__builtin_huge_vall", &ldouble_ctype, 0, NULL);
+	declare_builtin("__builtin_index", &string_ctype, 0, &const_string_ctype, &int_ctype, NULL);
+	declare_builtin("__builtin_inf", &double_ctype, 0, NULL);
+	declare_builtin("__builtin_inff", &float_ctype, 0, NULL);
+	declare_builtin("__builtin_infl", &ldouble_ctype, 0, NULL);
+	declare_builtin("__builtin_isfinite", &int_ctype, 1, NULL);
+	declare_builtin("__builtin_isgreater", &int_ctype, 0, &float_ctype, &float_ctype, NULL);
+	declare_builtin("__builtin_isgreaterequal", &int_ctype, 0, &float_ctype, &float_ctype, NULL);
+	declare_builtin("__builtin_isinf", &int_ctype, 1, NULL);
+	declare_builtin("__builtin_isinf_sign", &int_ctype, 1, NULL);
+	declare_builtin("__builtin_isless", &int_ctype, 0, &float_ctype, &float_ctype, NULL);
+	declare_builtin("__builtin_islessequal", &int_ctype, 0, &float_ctype, &float_ctype, NULL);
+	declare_builtin("__builtin_islessgreater", &int_ctype, 0, &float_ctype, &float_ctype, NULL);
+	declare_builtin("__builtin_isnan", &int_ctype, 1, NULL);
+	declare_builtin("__builtin_isnormal", &int_ctype, 1, NULL);
+	declare_builtin("__builtin_isunordered", &int_ctype, 0, &float_ctype, &float_ctype, NULL);
+	declare_builtin("__builtin_labs", &long_ctype, 0, &long_ctype, NULL);
+	declare_builtin("__builtin_llabs", &llong_ctype, 0, &llong_ctype, NULL);
+	declare_builtin("__builtin_malloc", &ptr_ctype, 0, size_t_ctype, NULL);
+	declare_builtin("__builtin_memchr", &ptr_ctype, 0, &const_ptr_ctype, &int_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_memcmp", &int_ctype, 0, &const_ptr_ctype, &const_ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_memcpy", &ptr_ctype, 0, &ptr_ctype, &const_ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_memmove", &ptr_ctype, 0, &ptr_ctype, &const_ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_mempcpy", &ptr_ctype, 0, &ptr_ctype, &const_ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_memset", &ptr_ctype, 0, &ptr_ctype, &int_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_nan", &double_ctype, 0, &const_string_ctype, NULL);
+	declare_builtin("__builtin_nanf", &float_ctype, 0, &const_string_ctype, NULL);
+	declare_builtin("__builtin_nanl", &ldouble_ctype, 0, &const_string_ctype, NULL);
+	declare_builtin("__builtin_object_size", size_t_ctype, 0, &const_ptr_ctype, &int_ctype, NULL);
+	declare_builtin("__builtin_parity", &int_ctype, 0, &uint_ctype, NULL);
+	declare_builtin("__builtin_parityl", &int_ctype, 0, &ulong_ctype, NULL);
+	declare_builtin("__builtin_parityll", &int_ctype, 0, &ullong_ctype, NULL);
+	declare_builtin("__builtin_popcount", &int_ctype, 0, &uint_ctype, NULL);
+	declare_builtin("__builtin_popcountl", &int_ctype, 0, &ulong_ctype, NULL);
+	declare_builtin("__builtin_popcountll", &int_ctype, 0, &ullong_ctype, NULL);
+	declare_builtin("__builtin_prefetch", &void_ctype, 1, &const_ptr_ctype, NULL);
+	declare_builtin("__builtin_printf", &int_ctype, 1, &const_string_ctype, NULL);
+	declare_builtin("__builtin_puts", &int_ctype, 0, &const_string_ctype, NULL);
+	declare_builtin("__builtin_realloc", &ptr_ctype, 0, &ptr_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_return_address", &ptr_ctype, 0, &uint_ctype, NULL);
+	declare_builtin("__builtin_rindex", &string_ctype, 0, &const_string_ctype, &int_ctype, NULL);
+	declare_builtin("__builtin_sadd_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+	declare_builtin("__builtin_saddl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+	declare_builtin("__builtin_saddll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
+	declare_builtin("__builtin_signbit", &int_ctype, 1, NULL);
+	declare_builtin("__builtin_smul_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+	declare_builtin("__builtin_smull_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+	declare_builtin("__builtin_smulll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
+	declare_builtin("__builtin_snprintf", &int_ctype, 1, &string_ctype, size_t_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_sprintf", &int_ctype, 1, &string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_ssub_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL);
+	declare_builtin("__builtin_ssubl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL);
+	declare_builtin("__builtin_ssubll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL);
+	declare_builtin("__builtin_stpcpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_stpncpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_strcasecmp", &int_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strcasestr", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strcat", &string_ctype, 0, &string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strchr", &string_ctype, 0, &const_string_ctype, &int_ctype, NULL);
+	declare_builtin("__builtin_strcmp", &int_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strcpy", &string_ctype, 0, &string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strcspn", size_t_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strdup", &string_ctype, 0, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strlen", size_t_ctype, 0, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strncasecmp", &int_ctype, 0, &const_string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_strncat", &string_ctype, 0, &string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_strncmp", &int_ctype, 0, &const_string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_strncpy", &string_ctype, 0, &string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_strndup", &string_ctype, 0, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_strnstr", &string_ctype, 0, &const_string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin_strpbrk", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strrchr", &string_ctype, 0, &const_string_ctype, &int_ctype, NULL);
+	declare_builtin("__builtin_strspn", size_t_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_strstr", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin_trap", &void_ctype, 0, NULL);
+	declare_builtin("__builtin_uadd_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+	declare_builtin("__builtin_uaddl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+	declare_builtin("__builtin_uaddll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
+	declare_builtin("__builtin_umul_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+	declare_builtin("__builtin_umull_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+	declare_builtin("__builtin_umulll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
+	declare_builtin("__builtin_unreachable", &void_ctype, 0, NULL);
+	declare_builtin("__builtin_usub_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL);
+	declare_builtin("__builtin_usubl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL);
+	declare_builtin("__builtin_usubll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL);
+	declare_builtin("__builtin_va_arg_pack_len", size_t_ctype, 0, NULL);
+	declare_builtin("__builtin_vprintf", &int_ctype, 0, &const_string_ctype, va_list_ctype, NULL);
+	declare_builtin("__builtin_vsnprintf", &int_ctype, 0, &string_ctype, size_t_ctype, &const_string_ctype, va_list_ctype, NULL);
+	declare_builtin("__builtin_vsprintf", &int_ctype, 0, &string_ctype, &const_string_ctype, va_list_ctype, NULL);
+
+	declare_builtin("__builtin___memcpy_chk", &ptr_ctype, 0, &ptr_ctype, &const_ptr_ctype, size_t_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___memmove_chk", &ptr_ctype, 0, &ptr_ctype, &const_ptr_ctype, size_t_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___mempcpy_chk", &ptr_ctype, 0, &ptr_ctype, &const_ptr_ctype, size_t_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___memset_chk", &ptr_ctype, 0, &ptr_ctype, &int_ctype, size_t_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___snprintf_chk", &int_ctype, 1, &string_ctype, size_t_ctype, &int_ctype , size_t_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin___sprintf_chk", &int_ctype, 1, &string_ctype, &int_ctype, size_t_ctype, &const_string_ctype, NULL);
+	declare_builtin("__builtin___stpcpy_chk", &string_ctype, 0, &string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___strcat_chk", &string_ctype, 0, &string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___strcpy_chk", &string_ctype, 0, &string_ctype, &const_string_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___strncat_chk", &string_ctype, 0, &string_ctype, &const_string_ctype, size_t_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___strncpy_chk", &string_ctype, 0, &string_ctype, &const_string_ctype, size_t_ctype, size_t_ctype, NULL);
+	declare_builtin("__builtin___vsnprintf_chk", &int_ctype, 0, &string_ctype, size_t_ctype, &int_ctype, size_t_ctype, &const_string_ctype, va_list_ctype, NULL);
+	declare_builtin("__builtin___vsprintf_chk", &int_ctype, 0, &string_ctype, &int_ctype, size_t_ctype, &const_string_ctype, va_list_ctype, NULL);
+
+	declare_builtin("__sync_add_and_fetch", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_and_and_fetch", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_bool_compare_and_swap", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_fetch_and_add", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_fetch_and_and", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_fetch_and_nand", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_fetch_and_or", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_fetch_and_sub", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_fetch_and_xor", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_lock_release", &void_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_lock_test_and_set", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_nand_and_fetch", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_or_and_fetch", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_sub_and_fetch", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_synchronize", &void_ctype, 0, NULL);
+	declare_builtin("__sync_val_compare_and_swap", &int_ctype, 1, &ptr_ctype, NULL);
+	declare_builtin("__sync_xor_and_fetch", &int_ctype, 1, &ptr_ctype, NULL);
+
+	// Blackfin-specific stuff
+	declare_builtin("__builtin_bfin_csync", &void_ctype, 0, NULL);
+	declare_builtin("__builtin_bfin_ssync", &void_ctype, 0, NULL);
+	declare_builtin("__builtin_bfin_norm_fr1x32", &int_ctype, 0, &int_ctype, NULL);
 }
--- old/usr/src/tools/smatch/src/c2xml.c	Mon Nov 18 13:18:40 2019
+++ new/usr/src/tools/smatch/src/c2xml.c	Mon Nov 18 13:18:40 2019
@@ -318,12 +318,12 @@
 */
 	symlist = sparse_initialize(argc, argv, &filelist);
 
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		examine_symbol_list(file, symlist);
 		sparse_keep_tokens(file);
 		examine_symbol_list(file, file_scope->symbols);
 		examine_symbol_list(file, global_scope->symbols);
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 
 	xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
--- old/usr/src/tools/smatch/src/cgcc	Mon Nov 18 13:18:40 2019
+++ new/usr/src/tools/smatch/src/cgcc	Mon Nov 18 13:18:41 2019
@@ -1,6 +1,9 @@
 #!/usr/bin/perl -w
 # -----------------------------------------------------------------------------
 
+use strict;
+use warnings;
+
 my $cc = $ENV{'REAL_CC'} || 'cc';
 my $check = $ENV{'CHECK'} || 'sparse';
 my $ccom = $cc;
@@ -14,20 +17,42 @@
 my $gcc_base_dir;
 my $multiarch_dir;
 my $verbose = 0;
+my $nargs = 0;
 
 while (@ARGV) {
     $_ = shift(@ARGV);
+
+    if ($nargs) {
+	$nargs--;
+	goto add_option;
+    }
+
     # Look for a .c file.  We don't want to run the checker on .o or .so files
-    # in the link run.  (This simplistic check knows nothing about options
-    # with arguments, but it seems to do the job.)
+    # in the link run.
     $do_check = 1 if /^[^-].*\.c$/;
 
     # Ditto for stdin.
     $do_check = 1 if $_ eq '-';
 
+    if (/^-(o|MF|MT|MQ)$/) {
+	# Need to be checked explicitly since otherwise
+	# the argument would be processed as a
+	# (non-existant) source file or as an option.
+	die ("$0: missing argument for $_") if !@ARGV;
+	$nargs = 1;
+    }
+
+    # Ignore the extension if '-x c' is given.
+    if ($_ eq '-x') {
+	die ("$0: missing argument for $_") if !@ARGV;
+	die ("$0: invalid argument for $_") if $ARGV[0] ne 'c';
+	$do_check = 1;
+	$nargs = 1;
+    }
+
     $m32 = 1 if /^-m32$/;
     $m64 = 1 if /^-m64$/;
-    $gendeps = 1 if /^-M$/;
+    $gendeps = 1 if /^-(M|MM|MD|MMD)$/;
 
     if (/^-target=(.*)$/) {
 	$check .= &add_specs ($1);
@@ -57,6 +82,7 @@
 
     $verbose = 1 if $_ eq '-v';
 
+add_option:
     my $this_arg = ' ' . &quote_arg ($_);
     $cc .= $this_arg unless &check_only_option ($_);
     $check .= $this_arg;
@@ -101,9 +127,10 @@
 
 sub check_only_option {
     my ($arg) = @_;
-    return 1 if $arg =~ /^-W(no-?)?(address-space|bitwise|cast-to-as|cast-truncate|context|decl|default-bitfield-sign|designated-init|do-while|enum-mismatch|external-function-has-definition|init-cstring|memcpy-max-count|non-ansi-function-declaration|non-pointer-null|old-initializer|one-bit-signed-bitfield|override-init-all|paren-string|ptr-subtraction-blows|return-void|sizeof-bool|sparse-all|sparse-error|transparent-union|typesign|undef|unknown-attribute)$/;
+    return 1 if $arg =~ /^-W(no-?)?(address-space|bitwise|cast-to-as|cast-truncate|constant-suffix|context|decl|default-bitfield-sign|designated-init|do-while|enum-mismatch|external-function-has-definition|init-cstring|memcpy-max-count|non-pointer-null|old-initializer|one-bit-signed-bitfield|override-init-all|paren-string|ptr-subtraction-blows|return-void|sizeof-bool|sparse-all|sparse-error|transparent-union|typesign|undef|unknown-attribute)$/;
     return 1 if $arg =~ /^-v(no-?)?(entry|dead)$/;
-    return 1 if $arg =~ /^-f(dump-linearize|memcpy-max-count)(=\S*)?$/;
+    return 1 if $arg =~ /^-f(dump-ir|memcpy-max-count|diagnostic-prefix)(=\S*)?$/;
+    return 1 if $arg =~ /^-f(mem2reg|optim)(-enable|-disable|=last)?$/;
     return 0;
 }
 
@@ -241,9 +268,18 @@
     } elsif ($spec eq 'openbsd') {
 	return &add_specs ('unix') .
 	    ' -D__OpenBSD__=1';
+    } elsif ($spec eq 'freebsd') {
+	return &add_specs ('unix') .
+	    ' -D__FreeBSD__=1';
+    } elsif ($spec eq 'netbsd') {
+	return &add_specs ('unix') .
+	    ' -D__NetBSD__=1';
     } elsif ($spec eq 'darwin') {
 	return
-	    ' -D__APPLE__=1 -D__MACH__=1';
+	    ' -D__APPLE__=1 -D__APPLE_CC__=1 -D__MACH__=1';
+    } elsif ($spec eq 'gnu') {		# Hurd
+	return &add_specs ('unix') .	# So, GNU is Unix, uh?
+	    ' -D__GNU__=1 -D__gnu_hurd__=1 -D__MACH__=1';
     } elsif ($spec eq 'unix') {
 	return ' -Dunix=1 -D__unix=1 -D__unix__=1';
     } elsif ( $spec =~ /^cygwin/) {
@@ -256,59 +292,49 @@
 	    " -D'_fastcall=__attribute__((__fastcall__))'" .
 	    " -D'__fastcall=__attribute__((__fastcall__))'" .
 	    " -D'__declspec(x)=__attribute__((x))'";
-    } elsif ($spec eq 'i86') {
-	return (' -D__i386=1 -D__i386__=1' .
-		&integer_types (8, 16, 32, $m64 ? 64 : 32, 64) .
-		&float_types (1, 1, 21, [24,8], [53,11], [64,15]) .
-		&define_size_t ($m64 ? "long unsigned int" : "unsigned int") .
-		' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4'));
+    } elsif ($spec eq 'i386') {
+	return (
+		&float_types (1, 1, 21, [24,8], [53,11], [64,15]));
     } elsif ($spec eq 'sparc') {
-	return (' -D__sparc=1 -D__sparc__=1' .
+	return (
 		&integer_types (8, 16, 32, $m64 ? 64 : 32, 64) .
 		&float_types (1, 1, 33, [24,8], [53,11], [113,15]) .
 		&define_size_t ($m64 ? "long unsigned int" : "unsigned int") .
 		' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4'));
     } elsif ($spec eq 'sparc64') {
-	return (' -D__sparc=1 -D__sparc__=1 -D__sparcv9__=1 -D__sparc64__=1 -D__arch64__=1 -D__LP64__=1' .
+	return (
 		&integer_types (8, 16, 32, 64, 64, 128) .
 		&float_types (1, 1, 33, [24,8], [53,11], [113,15]) .
 		&define_size_t ("long unsigned int") .
 		' -D__SIZEOF_POINTER__=8');
     } elsif ($spec eq 'x86_64') {
-	return (' -D__x86_64=1 -D__x86_64__=1' . ($m32 ? '' : ' -D__LP64__=1') .
-		&integer_types (8, 16, 32, $m32 ? 32 : 64, 64, 128) .
-		&float_types (1, 1, 33, [24,8], [53,11], [113,15]) .
-		&define_size_t ($m32 ? "unsigned int" : "long unsigned int") .
-		' -D__SIZEOF_POINTER__=' . ($m32 ? '4' : '8'));
+	return &float_types (1, 1, 33, [24,8], [53,11], [113,15]);
     } elsif ($spec eq 'ppc') {
-	return (' -D__powerpc__=1 -D_BIG_ENDIAN -D_STRING_ARCH_unaligned=1' .
+	return (' -D_BIG_ENDIAN -D_STRING_ARCH_unaligned=1' .
 		&integer_types (8, 16, 32, $m64 ? 64 : 32, 64) .
 		&float_types (1, 1, 21, [24,8], [53,11], [113,15]) .
 		&define_size_t ($m64 ? "long unsigned int" : "unsigned int") .
 		' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4'));
     } elsif ($spec eq 'ppc64') {
-	return (' -D__powerpc__=1 -D__PPC__=1 -D_STRING_ARCH_unaligned=1' .
-		' -D__powerpc64__=1 -D__PPC64__=1' .
-		' -m64' .
+	return (' -D_STRING_ARCH_unaligned=1 -m64' .
 		&float_types (1, 1, 21, [24,8], [53,11], [113,15]));
+    } elsif ($spec eq 'ppc64+be') {
+	return &add_specs ('ppc64') . ' -mbig-endian -D_CALL_ELF=1';
+    } elsif ($spec eq 'ppc64+le') {
+	return &add_specs ('ppc64') . ' -mlittle-endian -D_CALL_ELF=2';
     } elsif ($spec eq 's390x') {
-	return (' -D__s390x__ -D__s390__ -D_BIG_ENDIAN' .
+	return (' -D_BIG_ENDIAN' .
 		&integer_types (8, 16, 32, $m64 ? 64 : 32, 64) .
 		&float_types (1, 1, 36, [24,8], [53,11], [113,15]) .
 		&define_size_t ("long unsigned int") .
 		' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4'));
     } elsif ($spec eq 'arm') {
-	chomp (my $gccmachine = `$cc -dumpmachine`);
-	my $cppsymbols = ' -D__arm__=1 -m32';
-
-	if ($gccmachine eq 'arm-linux-gnueabihf') {
-	    $cppsymbols .= ' -D__ARM_PCS_VFP=1';
-	}
-
-	return ($cppsymbols .
+	return (' -m32' .
 		&float_types (1, 1, 36, [24,8], [53,11], [53, 11]));
+    } elsif ($spec eq 'arm+hf') {
+	return &add_specs ('arm') . ' -D__ARM_PCS_VFP=1';
     } elsif ($spec eq 'aarch64') {
-	return (' -D__aarch64__=1 -m64' .
+	return (' -m64' .
 		&float_types (1, 1, 36, [24,8], [53,11], [113,15]));
     } elsif ($spec eq 'host_os_specs') {
 	my $os = `uname -s`;
@@ -315,10 +341,39 @@
 	chomp $os;
 	return &add_specs (lc $os);
     } elsif ($spec eq 'host_arch_specs') {
-	my $arch = `uname -m`;
+	my $gccmachine;
+	my $arch;
+
+	$gccmachine = `$ccom -dumpmachine`;
+	chomp $gccmachine;
+
+	if ($gccmachine =~ '^aarch64-') {
+	    return &add_specs ('aarch64');
+	} elsif ($gccmachine =~ '^arm-.*eabihf$') {
+	    return &add_specs ('arm+hf');
+	} elsif ($gccmachine =~ '^arm-') {
+	    return &add_specs ('arm');
+	} elsif ($gccmachine =~ '^i[23456]86-') {
+	    return &add_specs ('i386');
+	} elsif ($gccmachine =~ '^(powerpc|ppc)64le-') {
+	    return &add_specs ('ppc64+le');
+	} elsif ($gccmachine =~ '^s390x-') {
+	    return &add_specs ('s390x');
+	} elsif ($gccmachine eq 'x86_64-linux-gnux32') {
+	    return &add_specs ('x86_64') . ' -mx32';
+	} elsif ($gccmachine =~ '^x86_64-') {
+	    return &add_specs ('x86_64');
+	}
+
+	# fall back to uname -m to determine the specifics.
+	# Note: this is only meaningful when using natively
+	#       since information about the host is used to
+	#	guess characteristics of the target.
+
+	$arch = `uname -m`;
 	chomp $arch;
 	if ($arch =~ /^(i.?86|athlon)$/i) {
-	    return &add_specs ('i86');
+	    return &add_specs ('i386');
 	} elsif ($arch =~ /^(sun4u)$/i) {
 	    return &add_specs ('sparc');
 	} elsif ($arch =~ /^(x86_64)$/i) {
@@ -326,9 +381,9 @@
 	} elsif ($arch =~ /^(ppc)$/i) {
 	    return &add_specs ('ppc');
 	} elsif ($arch =~ /^(ppc64)$/i) {
-	    return &add_specs ('ppc64') . ' -mbig-endian -D_CALL_ELF=1';
+	    return &add_specs ('ppc64+be');
 	} elsif ($arch =~ /^(ppc64le)$/i) {
-	    return &add_specs ('ppc64') . ' -mlittle-endian -D_CALL_ELF=2';
+	    return &add_specs ('ppc64+le');
 	} elsif ($arch =~ /^(s390x)$/i) {
 	    return &add_specs ('s390x');
 	} elsif ($arch =~ /^(sparc64)$/i) {
--- old/usr/src/tools/smatch/src/char.c	Mon Nov 18 13:18:41 2019
+++ new/usr/src/tools/smatch/src/char.c	Mon Nov 18 13:18:41 2019
@@ -84,7 +84,7 @@
 		end = p + type - TOKEN_WIDE_CHAR;
 	}
 	p = parse_escape(p, &v, end,
-			type < TOKEN_WIDE_CHAR ? bits_in_char : bits_in_wchar, token->pos);
+			type < TOKEN_WIDE_CHAR ? bits_in_char : wchar_ctype->bit_size, token->pos);
 	if (p != end)
 		warning(token->pos,
 			"multi-character character constant");
@@ -113,7 +113,7 @@
 			done = next;
 		}
 	}
-	bits = is_wide ? bits_in_wchar : bits_in_char;
+	bits = is_wide ? wchar_ctype->bit_size: bits_in_char;
 	while (token != done) {
 		unsigned v;
 		const char *p = token->string->data;
--- old/usr/src/tools/smatch/src/check_access_ok_math.c	Mon Nov 18 13:18:41 2019
+++ new/usr/src/tools/smatch/src/check_access_ok_math.c	Mon Nov 18 13:18:41 2019
@@ -76,24 +76,15 @@
 static void split_asm_constraints(struct expression_list *expr_list)
 {
 	struct expression *expr;
-        int state = 0;
 	int i;
 
 	i = 0;
         FOR_EACH_PTR(expr_list, expr) {
-
-                switch (state) {
-                case 0: /* identifier */
-                case 1: /* constraint */
-                        state++;
-                        continue;
-                case 2: /* expression */
-                        state = 0;
-			if (i == 1)
-				match_size(expr);
-			i++;
-                        continue;
-                }
+		i++;
+		if (expr->type != EXPR_ASM_OPERAND)
+			continue;
+		if (i == 1)
+			match_size(expr->expr);
         } END_FOR_EACH_PTR(expr);
 }
 
--- /dev/null	Mon Nov 18 13:18:41 2019
+++ new/usr/src/tools/smatch/src/check_arm64_tagged.c	Mon Nov 18 13:18:42 2019
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2019 ARM.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
+ */
+
+#include "smatch.h"
+#include "smatch_extra.h"
+#include "smatch_function_hashtable.h"
+
+static bool expr_has_memory_addr(struct expression *expr);
+
+static DEFINE_HASHTABLE_SEARCH(search_symbol, char, char);
+static DEFINE_HASHTABLE_INSERT(insert_symbol, char, char);
+static struct hashtable *symbols;
+
+static void match_assign(struct expression *expr)
+{
+	char *left_name;
+	struct symbol *left_sym;
+
+	left_name = expr_to_var_sym(expr->left, &left_sym);
+	if (!left_name || !left_sym)
+		return;
+
+	/*
+	 * Once we have spotted a symbol of interest (one that may hold
+	 * an untagged memory address), we keep track of any assignments
+	 * made, such that we can also treat the assigned symbol as something
+	 * of interest. This tracking is limited in scope to the function.
+	 */
+	if (expr_has_memory_addr(expr->right))
+		insert_symbol(symbols, left_name, left_name);
+}
+
+static void match_endfunc(struct symbol *sym)
+{
+	destroy_function_hashtable(symbols);
+	symbols = create_function_hashtable(4000);
+}
+
+static bool expr_has_untagged_symbol(struct expression *expr)
+{
+	char *name;
+	struct symbol *sym;
+
+	if (expr->type != EXPR_SYMBOL)
+		return false;
+
+	name = expr_to_var_sym(expr, &sym);
+	if (!name || !sym)
+		return false;
+
+	/* See if this is something we already know is of interest */
+	if (search_symbol(symbols, name))
+		return true;
+
+	return false;
+}
+
+static bool expr_has_untagged_member(struct expression *expr)
+{
+	if (expr->type != EXPR_DEREF)
+		return false;
+
+	if (!strcmp(expr->member->name, "vm_start") ||
+	    !strcmp(expr->member->name, "vm_end") ||
+	    !strcmp(expr->member->name, "addr_limit"))
+		return true;
+
+	return false;
+}
+
+static bool expr_has_macro_with_name(struct expression *expr, const char *macro_name)
+{
+	char *name;
+
+	name = get_macro_name(expr->pos);
+	return (name && !strcmp(name, macro_name));
+}
+
+static bool expr_has_untagged_macro(struct expression *expr)
+{
+	if (expr_has_macro_with_name(expr, "PAGE_SIZE") ||
+	    expr_has_macro_with_name(expr, "PAGE_MASK") ||
+	    expr_has_macro_with_name(expr, "TASK_SIZE"))
+		return true;
+
+	/**
+	 * We can't detect a marco (such as PAGE_MASK) inside another macro
+	 * such as offset_in_page, therefore we have to detect the outer macro
+	 * instead.
+	 */
+	if (expr_has_macro_with_name(expr, "offset_in_page"))
+		return true;
+
+	return false;
+}
+
+/*
+ * Identify expressions that contain memory addresses, in the future
+ * we may use annotations on symbols or function parameters.
+ */
+static bool expr_has_memory_addr(struct expression *expr)
+{
+	if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP)
+		expr = strip_expr(expr->unop);
+
+	if (expr_has_untagged_member(expr))
+		return true;
+
+	if (expr_has_untagged_macro(expr))
+		return true;
+
+	if (expr_has_untagged_symbol(expr))
+		return true;
+
+	return false;
+}
+
+int rl_is_larger_or_equal(struct range_list *rl, sval_t sval)
+{
+	struct data_range *tmp;
+
+	FOR_EACH_PTR(rl, tmp) {
+		if (sval_cmp(tmp->max, sval) >= 0)
+			return 1;
+	} END_FOR_EACH_PTR(tmp);
+	return 0;
+}
+
+int rl_range_has_min_value(struct range_list *rl, sval_t sval)
+{
+	struct data_range *tmp;
+
+	FOR_EACH_PTR(rl, tmp) {
+		if (!sval_cmp(tmp->min, sval)) {
+			return 1;
+		}
+	} END_FOR_EACH_PTR(tmp);
+	return 0;
+}
+
+static bool rl_is_tagged(struct range_list *rl)
+{
+	sval_t invalid = { .type = &ullong_ctype, .value = (1ULL << 56) };
+	sval_t invalid_kernel = { .type = &ullong_ctype, .value = (0xff8ULL << 52) };
+
+	/*
+	 * We only care for tagged addresses, thus ignore anything where the
+	 * ranges of potential values cannot possibly have any of the top byte
+	 * bits set.
+	 */
+	if (!rl_is_larger_or_equal(rl, invalid))
+		return false;
+
+	/*
+	 * Tagged addresses are untagged in the kernel by using sign_extend64 in
+	 * the untagged_addr macro. For userspace addresses bit 55 will always
+	 * be 0 and thus this has the effect of clearing the top byte. However
+	 * for kernel addresses this is not true and the top bits end up set to
+	 * all 1s. The untagged_addr macro results in leaving a gap in the range
+	 * of possible values which can exist, thus let's look for a tell-tale
+	 * range which starts from (0xff8ULL << 52).
+	 */
+	if (rl_range_has_min_value(rl, invalid_kernel))
+		return false;
+
+	return true;
+}
+
+static void match_condition(struct expression *expr)
+{
+	struct range_list *rl = NULL;
+	struct expression *val = NULL;
+        struct symbol *type;
+	char *var_name;
+
+	/*
+	 * Match instances where something is compared against something
+	 * else - we include binary operators as these are commonly used
+	 * to make a comparison, e.g. if (start & ~PAGE_MASK).
+	 */
+	if (expr->type != EXPR_COMPARE &&
+	    expr->type != EXPR_BINOP)
+		return;
+
+	/*
+	 * Look on both sides of the comparison for something that shouldn't
+	 * be compared with a tagged address, e.g. macros such as PAGE_MASK
+	 * or struct members named .vm_start. 
+	 */
+	if (expr_has_memory_addr(expr->left))
+		val = expr->right;
+
+	/*
+	 * The macro 'offset_in_page' has the PAGE_MASK macro inside it, this
+	 * results in 'expr_has_memory_addr' returning true for both sides. To
+	 * work around this we assume PAGE_MASK (or similar) is on the right
+	 * side, thus we do the following test last.
+	 */
+	if (expr_has_memory_addr(expr->right))
+		val = expr->left;
+
+	if (!val)
+		return;
+
+	/* We only care about memory addresses which are 64 bits */
+        type = get_type(val);
+	if (!type || type_bits(type) != 64)
+		return;
+
+	/* We only care for comparison against user originated data */
+	if (!get_user_rl(val, &rl))
+		return;
+
+	/* We only care for tagged addresses */
+	if (!rl_is_tagged(rl))
+		return;
+
+	/* Finally, we believe we may have spotted a risky comparison */
+	var_name = expr_to_var(val);
+	if (var_name)
+		sm_warning("comparison of a potentially tagged address (%s, %d, %s)", get_function(), get_param_num(val), var_name);
+}
+
+void check_arm64_tagged(int id)
+{
+	char *arch;
+
+	if (option_project != PROJ_KERNEL)
+		return;
+
+	/* Limit to aarch64 */
+	arch = getenv("ARCH");
+	if (!arch || strcmp(arch, "arm64"))
+		return;
+
+	symbols = create_function_hashtable(4000);
+
+	add_hook(&match_assign, ASSIGNMENT_HOOK);
+	add_hook(&match_condition, CONDITION_HOOK);
+	add_hook(&match_endfunc, END_FUNC_HOOK);
+}
--- old/usr/src/tools/smatch/src/check_check_deref.c	Mon Nov 18 13:18:42 2019
+++ new/usr/src/tools/smatch/src/check_check_deref.c	Mon Nov 18 13:18:42 2019
@@ -135,8 +135,11 @@
 static void match_condition(struct expression *expr)
 {
 	struct smatch_state *true_state = NULL;
+	char *name;
 
-	if (get_macro_name(expr->pos))
+	name = get_macro_name(expr->pos);
+	if (name &&
+	    (strcmp(name, "likely") != 0 && strcmp(name, "unlikely") != 0))
 		return;
 
 	if (!is_pointer(expr))
--- old/usr/src/tools/smatch/src/check_continue_vs_break.c	Mon Nov 18 13:18:42 2019
+++ new/usr/src/tools/smatch/src/check_continue_vs_break.c	Mon Nov 18 13:18:42 2019
@@ -36,7 +36,7 @@
 {
 	if (!stmt->iterator_post_condition)
 		return 0;
-	if (!is_zero(stmt->iterator_post_condition))
+	if (!expr_is_zero(stmt->iterator_post_condition))
 		return 0;
 	return 1;
 }
--- old/usr/src/tools/smatch/src/check_debug.c	Mon Nov 18 13:18:42 2019
+++ new/usr/src/tools/smatch/src/check_debug.c	Mon Nov 18 13:18:42 2019
@@ -22,6 +22,7 @@
 void show_sname_alloc(void);
 void show_data_range_alloc(void);
 void show_ptrlist_alloc(void);
+void show_rl_ptrlist_alloc(void);
 void show_sm_state_alloc(void);
 
 int local_debug;
@@ -204,6 +205,7 @@
 {
 	struct expression *arg;
 	struct range_list *rl = NULL;
+	bool capped = false;
 	char *name;
 
 	arg = get_argument_from_call_expr(expr->args, 0);
@@ -210,7 +212,9 @@
 	name = expr_to_str(arg);
 
 	get_user_rl(arg, &rl);
-	sm_msg("user rl: '%s' = '%s'", name, show_rl(rl));
+	if (rl)
+		capped = user_rl_capped(arg);
+	sm_msg("user rl: '%s' = '%s'%s", name, show_rl(rl), capped ? " (capped)" : "");
 
 	free_string(name);
 }
@@ -687,6 +691,8 @@
 static void match_mem(const char *fn, struct expression *expr, void *info)
 {
 	show_sname_alloc();
+	show_data_range_alloc();
+	show_rl_ptrlist_alloc();
 	show_ptrlist_alloc();
 	sm_msg("%lu pools", get_pool_count());
 	sm_msg("%d strees", unfree_stree);
--- old/usr/src/tools/smatch/src/check_deref.c	Mon Nov 18 13:18:43 2019
+++ new/usr/src/tools/smatch/src/check_deref.c	Mon Nov 18 13:18:43 2019
@@ -186,7 +186,7 @@
 {
 	struct statement *stmt;
 
-	if (!is_zero(expr->right))
+	if (!expr_is_zero(expr->right))
 		return;
 
 	if (__in_fake_assign)
--- old/usr/src/tools/smatch/src/check_deref_check.c	Mon Nov 18 13:18:43 2019
+++ new/usr/src/tools/smatch/src/check_deref_check.c	Mon Nov 18 13:18:43 2019
@@ -66,11 +66,14 @@
 static void match_condition(struct expression *expr)
 {
 	struct sm_state *sm;
+	char *name;
 
 	if (__in_pre_condition)
 		return;
 
-	if (get_macro_name(expr->pos))
+	name = get_macro_name(expr->pos);
+	if (name &&
+	    (strcmp(name, "likely") != 0 && strcmp(name, "unlikely") != 0))
 		return;
 
 	if (!is_pointer(expr))
--- old/usr/src/tools/smatch/src/check_dereferences_param.c	Mon Nov 18 13:18:43 2019
+++ new/usr/src/tools/smatch/src/check_dereferences_param.c	Mon Nov 18 13:18:43 2019
@@ -78,8 +78,6 @@
 {
 	if (expr->type != EXPR_PREOP)
 		return;
-	if (getting_address())
-		return;
 	check_deref(expr->unop);
 }
 
--- old/usr/src/tools/smatch/src/check_double_checking.c	Mon Nov 18 13:18:44 2019
+++ new/usr/src/tools/smatch/src/check_double_checking.c	Mon Nov 18 13:18:44 2019
@@ -47,9 +47,9 @@
 	if (expr->type == EXPR_COMPARE &&
 	    (expr->op == SPECIAL_EQUAL ||
 	     expr->op == SPECIAL_NOTEQUAL)) {
-		if (is_zero(expr->left))
+		if (expr_is_zero(expr->left))
 			return strip_condition(expr->right);
-		if (is_zero(expr->right))
+		if (expr_is_zero(expr->right))
 			return strip_condition(expr->left);
 	}
 
@@ -131,6 +131,9 @@
 	struct position prev_pos;
 	char *ident;
 
+	if (!__cur_stmt)
+		return 0;
+
 	if (__prev_stmt) {
 		prev_pos = __prev_stmt->pos;
 		prev_pos.line -= 3;
--- old/usr/src/tools/smatch/src/check_free.c	Mon Nov 18 13:18:44 2019
+++ new/usr/src/tools/smatch/src/check_free.c	Mon Nov 18 13:18:44 2019
@@ -36,10 +36,10 @@
 		set_state(my_id, sm->name, sm->sym, &ok);
 }
 
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
 	if (is_impossible_path())
-		set_state(my_id, sm->name, sm->sym, &ok);
+		set_state(my_id, cur->name, cur->sym, &ok);
 }
 
 static int is_freed(struct expression *expr)
--- old/usr/src/tools/smatch/src/check_free_strict.c	Mon Nov 18 13:18:45 2019
+++ new/usr/src/tools/smatch/src/check_free_strict.c	Mon Nov 18 13:18:45 2019
@@ -36,12 +36,29 @@
 		set_state(my_id, sm->name, sm->sym, &ok);
 }
 
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
 	if (is_impossible_path())
-		set_state(my_id, sm->name, sm->sym, &ok);
+		set_state(my_id, cur->name, cur->sym, &ok);
 }
 
+static struct smatch_state *unmatched_state(struct sm_state *sm)
+{
+	struct smatch_state *state;
+	sval_t sval;
+
+	if (sm->state != &freed)
+		return &undefined;
+
+	state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+	if (!state)
+		return &undefined;
+	if (!estate_get_single_value(state, &sval) || sval.value != 0)
+		return &undefined;
+	/* It makes it easier to consider NULL pointers as freed.  */
+	return &freed;
+}
+
 static int is_freed(struct expression *expr)
 {
 	struct sm_state *sm;
@@ -341,6 +358,7 @@
 
 	add_modification_hook_late(my_id, &ok_to_use);
 	add_pre_merge_hook(my_id, &pre_merge_hook);
+	add_unmatched_state_hook(my_id, &unmatched_state);
 
 	select_return_states_hook(PARAM_FREED, &set_param_freed);
 	add_untracked_param_hook(&match_untracked);
--- old/usr/src/tools/smatch/src/check_get_user_overflow.c	Mon Nov 18 13:18:45 2019
+++ new/usr/src/tools/smatch/src/check_get_user_overflow.c	Mon Nov 18 13:18:45 2019
@@ -108,7 +108,7 @@
 		return;
 	}
 	name = expr_to_var(expr->right);
-	if (!name || strcmp(name, "__val_gu") != 0)
+	if (!name || (strcmp(name, "__val_gu") != 0 && strcmp(name, "__gu_val")))
 		goto free;
 	set_state_expr(my_max_id, expr->left, &user_data);
 	set_state_expr(my_min_id, expr->left, &user_data);
@@ -127,14 +127,15 @@
 
 	sm = get_sm_state_expr(my_max_id, expr);
 	if (sm && slist_has_state(sm->possible, &user_data)) {
-		if (!get_absolute_max(expr, &max) || sval_cmp_val(max, 20000) > 0)
+		get_absolute_max(expr, &max);
+		if (sval_cmp_val(max, 20000) > 0)
 			overflow = 1;
 	}
 
 	sm = get_sm_state_expr(my_min_id, expr);
 	if (sm && slist_has_state(sm->possible, &user_data)) {
-		if (!get_absolute_min(expr, &sval) ||
-		    (sval_is_negative(sval) && sval_cmp_val(sval, -20000) < 0))
+		get_absolute_min(expr, &sval);
+		if (sval_is_negative(sval) && sval_cmp_val(sval, -20000) < 0)
 			underflow = 1;
 	}
 
--- old/usr/src/tools/smatch/src/check_kernel.c	Mon Nov 18 13:18:45 2019
+++ new/usr/src/tools/smatch/src/check_kernel.c	Mon Nov 18 13:18:45 2019
@@ -104,14 +104,18 @@
 {
 	int param = PTR_INT(_param);
 	struct expression *arg;
-	struct range_list *rl;
+	struct range_list *pre, *rl;
 	struct smatch_state *pre_state;
 	struct smatch_state *end_state;
 
 	arg = get_argument_from_call_expr(call_expr->args, param);
 	pre_state = get_state_expr(SMATCH_EXTRA, arg);
+	if (pre_state)
+		pre = estate_rl(pre_state);
+	else
+		pre = alloc_whole_rl(&ptr_ctype);
 	call_results_to_rl(call_expr, &ptr_ctype, "0,(-4095)-(-1)", &rl);
-	rl = rl_intersection(estate_rl(pre_state), rl);
+	rl = rl_intersection(pre, rl);
 	rl = cast_rl(get_type(arg), rl);
 	end_state = alloc_estate_rl(rl);
 	set_extra_expr_nomod(arg, end_state);
--- old/usr/src/tools/smatch/src/check_list.h	Mon Nov 18 13:18:46 2019
+++ new/usr/src/tools/smatch/src/check_list.h	Mon Nov 18 13:18:46 2019
@@ -40,7 +40,6 @@
 CK(register_comparison_links)
 CK(register_comparison_inc_dec)
 CK(register_comparison_inc_dec_links)
-CK(register_local_values)
 CK(register_function_ptrs)
 CK(register_annotate)
 CK(register_start_states)
@@ -48,7 +47,6 @@
 CK(register_data_source)
 CK(register_common_functions)
 CK(register_function_info)
-CK(register_auto_copy)
 CK(register_type_links)
 CK(register_impossible)
 CK(register_impossible_return)
@@ -178,6 +176,7 @@
 CK(check_return_negative_var)
 CK(check_rosenberg)
 CK(check_rosenberg2)
+CK(check_rosenberg3)
 CK(check_wait_for_common)
 CK(check_bogus_irqrestore)
 CK(check_zero_to_err_ptr)
@@ -197,6 +196,8 @@
 CK(check_wine_filehandles)
 CK(check_wine_WtoA)
 
+CK(check_arm64_tagged)
+
 /* illumos specific */
 CK(check_all_func_returns)
 CK(check_cmn_err)
--- old/usr/src/tools/smatch/src/check_locking.c	Mon Nov 18 13:18:46 2019
+++ new/usr/src/tools/smatch/src/check_locking.c	Mon Nov 18 13:18:46 2019
@@ -456,10 +456,10 @@
 	return &start_state;
 }
 
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
 	if (is_impossible_path())
-		set_state(my_id, sm->name, sm->sym, &impossible);
+		set_state(my_id, cur->name, cur->sym, &impossible);
 }
 
 static bool nestable(const char *name)
--- old/usr/src/tools/smatch/src/check_memory.c	Mon Nov 18 13:18:46 2019
+++ /dev/null	Mon Nov 18 13:18:46 2019
@@ -1,466 +0,0 @@
-/*
- * Copyright (C) 2008 Dan Carpenter.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
- */
-
-#include <fcntl.h>
-#include <unistd.h>
-#include "parse.h"
-#include "smatch.h"
-#include "smatch_slist.h"
-
-static void check_sm_is_leaked(struct sm_state *sm);
-
-static int my_id;
-
-STATE(allocated);
-STATE(assigned);
-STATE(isfree);
-STATE(malloced);
-STATE(isnull);
-STATE(unfree);
-
-/*
-  malloced --> allocated --> assigned --> isfree +
-            \-> isnull.    \-> isfree +
-
-  isfree --> unfree.
-          \-> isnull.
-*/
-
-static struct tracker_list *arguments;
-
-static const char *allocation_funcs[] = {
-	"malloc",
-	"kmalloc",
-	"kzalloc",
-	NULL,
-};
-
-static char *get_parent_name(struct symbol *sym)
-{
-	static char buf[256];
-
-	if (!sym || !sym->ident)
-		return NULL;
-
-	snprintf(buf, 255, "-%s", sym->ident->name);
-	buf[255] = '\0';
-	return alloc_string(buf);
-}
-
-static int is_parent_sym(const char *name)
-{
-	if (!strncmp(name, "-", 1))
-		return 1;
-	return 0;
-}
-
-static int is_complex(struct expression *expr)
-{
-	char *name;
-	int ret = 1;
-
-	name = expr_to_var(expr);
-	if (name)
-		ret = 0;
-	free_string(name);
-	return ret;
-}
-
-static struct smatch_state *unmatched_state(struct sm_state *sm)
-{
-	if (is_parent_sym(sm->name))
-		return &assigned;
-	return &undefined;
-}
-
-static void assign_parent(struct symbol *sym)
-{
-	char *name;
-
-	name = get_parent_name(sym);
-	if (!name)
-		return;
-	set_state(my_id, name, sym, &assigned);
-	free_string(name);
-}
-
-static int parent_is_assigned(struct symbol *sym)
-{
-	struct smatch_state *state;
-	char *name;
-
-	name = get_parent_name(sym);
-	if (!name)
-		return 0;
-	state = get_state(my_id, name, sym);
-	free_string(name);
-	if (state == &assigned)
-		return 1;
-	return 0;
-}
-
-static int is_allocation(struct expression *expr)
-{
-	char *fn_name;
-	int i;
-
-	if (expr->type != EXPR_CALL)
-		return 0;
-
-	if (!(fn_name = expr_to_var_sym(expr->fn, NULL)))
-		return 0;
-
-	for (i = 0; allocation_funcs[i]; i++) {
-		if (!strcmp(fn_name, allocation_funcs[i])) {
-			free_string(fn_name);
-			return 1;
-		}
-	}
-	free_string(fn_name);
-	return 0;
-}
-
-static int is_freed(const char *name, struct symbol *sym)
-{
-	struct state_list *slist;
-
-	slist = get_possible_states(my_id, name, sym);
-	if (slist_has_state(slist, &isfree)) {
-		return 1;
-	}
-	return 0;
-}
-
-static int is_argument(struct symbol *sym)
-{
-	struct tracker *arg;
-
-	FOR_EACH_PTR(arguments, arg) {
-		if (arg->sym == sym)
-			return 1;
-	} END_FOR_EACH_PTR(arg);
-	return 0;
-}
-
-static void match_function_def(struct symbol *sym)
-{
-	struct symbol *arg;
-
-	FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
-		add_tracker(&arguments, my_id, (arg->ident?arg->ident->name:"NULL"), arg);
-	} END_FOR_EACH_PTR(arg);
-}
-
-static int is_parent(struct expression *expr)
-{
-	if (expr->type == EXPR_DEREF)
-		return 0;
-	return 1;
-}
-
-static void match_assign(struct expression *expr)
-{
-	struct expression *left, *right;
-	char *left_name = NULL;
-	char *right_name = NULL;
-	struct symbol *left_sym, *right_sym;
-	struct smatch_state *state;
-	struct state_list *slist;
-	struct sm_state *tmp;
-
-	left = strip_expr(expr->left);
-	left_name = expr_to_str_sym(left, &left_sym);
-
-	right = strip_expr(expr->right);
-	while (right->type == EXPR_ASSIGNMENT)
-		right = right->left;
-
-	if (left_name && left_sym && is_allocation(right) && 
-	    !(left_sym->ctype.modifiers & 
-	      (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE)) &&
-	    !parent_is_assigned(left_sym)) {
-		set_state(my_id, left_name, left_sym, &malloced);
-		goto exit;
-	}
-
-	right_name = expr_to_str_sym(right, &right_sym);
-
-	if (right_name && (state = get_state(my_id, right_name, right_sym))) {
-		if (state == &isfree && !is_complex(right))
-			sm_error("assigning freed pointer '%s'", right_name);
-		set_state(my_id, right_name, right_sym, &assigned);
-	}
-
-	if (is_zero(expr->right)) {
-		slist = get_possible_states(my_id, left_name, left_sym);
-
-		FOR_EACH_PTR(slist, tmp) {
-			check_sm_is_leaked(tmp);
-		} END_FOR_EACH_PTR(tmp);
-	}
-
-	if (is_freed(left_name, left_sym)) {
-		set_state(my_id, left_name, left_sym, &unfree);
-	}
-	if (left_name && is_parent(left))
-		assign_parent(left_sym);
-	if (right_name && is_parent(right))
-		assign_parent(right_sym);
-exit:
-	free_string(left_name);
-	free_string(right_name);
-}
-
-static int is_null(const char *name, struct symbol *sym)
-{
-	struct smatch_state *state;
-
-	state = get_state(my_id, name, sym);
-	if (state && !strcmp(state->name, "isnull"))
-		return 1;
-	return 0;
-}
-
-static void set_unfree(struct sm_state *sm, struct expression *mod_expr)
-{
-	if (slist_has_state(sm->possible, &isfree))
-		set_state(my_id, sm->name, sm->sym, &unfree);
-}
-
-static void match_free_func(const char *fn, struct expression *expr, void *data)
-{
-	struct expression *ptr_expr;
-	char *ptr_name;
-	struct symbol *ptr_sym;
-	int arg_num = PTR_INT(data);
-
-	ptr_expr = get_argument_from_call_expr(expr->args, arg_num);
-	ptr_name = expr_to_var_sym(ptr_expr, &ptr_sym);
-	if (!ptr_name)
-		return;
-	set_state(my_id, ptr_name, ptr_sym, &isfree);
-	free_string(ptr_name);
-}
-
-static int possibly_allocated(struct state_list *slist)
-{
-	struct sm_state *tmp;
-
-	FOR_EACH_PTR(slist, tmp) {
-		if (tmp->state == &allocated)
-			return 1;
-		if (tmp->state == &malloced)
-			return 1;
-	} END_FOR_EACH_PTR(tmp);
-	return 0;
-}
-
-static void check_sm_is_leaked(struct sm_state *sm)
-{
-	if (possibly_allocated(sm->possible) && 
-		!is_null(sm->name, sm->sym) &&
-		!is_argument(sm->sym) && 
-		!parent_is_assigned(sm->sym))
-		sm_error("memory leak of '%s'", sm->name);
-}
-
-static void check_tracker_is_leaked(struct tracker *t)
-{
-	struct sm_state *sm;
-
-	sm = get_sm_state(t->owner, t->name, t->sym);
-	if (sm)
-		check_sm_is_leaked(sm);
-	__free_tracker(t);
-}
-
-static void match_declarations(struct symbol *sym)
-{
-	const char *name;
-
-	if ((get_base_type(sym))->type == SYM_ARRAY) {
-		return;
-	}
-
-	name = sym->ident->name;
-
-	if (sym->initializer) {
-		if (is_allocation(sym->initializer)) {
-			set_state(my_id, name, sym, &malloced);
-			add_scope_hook((scope_hook *)&check_tracker_is_leaked,
-				alloc_tracker(my_id, name, sym));
-			scoped_state(my_id, name, sym);
-		} else {
-			assign_parent(sym);
-		}
-	}
-}
-
-static void check_for_allocated(void)
-{
-	struct stree *stree;
-	struct sm_state *tmp;
-
-	stree = __get_cur_stree();
-	FOR_EACH_MY_SM(my_id, stree, tmp) {
-		check_sm_is_leaked(tmp);
-	} END_FOR_EACH_SM(tmp);
-}
-
-static void match_return(struct expression *ret_value)
-{
-	char *name;
-	struct symbol *sym;
-
-	if (__inline_fn)
-		return;
-	name = expr_to_str_sym(ret_value, &sym);
-	if (sym)
-		assign_parent(sym);
-	free_string(name);
-	check_for_allocated();
-}
-
-static void set_new_true_false_paths(const char *name, struct symbol *sym)
-{
-	struct smatch_state *tmp;
-
-	tmp = get_state(my_id, name, sym);
-
-	if (!tmp) {
-		return;
-	}
-
-	if (tmp == &isfree) {
-		sm_warning("why do you care about freed memory? '%s'", name);
-	}
-
-	if (tmp == &assigned) {
-		/* we don't care about assigned pointers any more */
-		return;
-	}
-	set_true_false_states(my_id, name, sym, &allocated, &isnull);
-}
-
-static void match_condition(struct expression *expr)
-{
-	struct symbol *sym;
-	char *name;
-
-	expr = strip_expr(expr);
-	switch (expr->type) {
-	case EXPR_PREOP:
-	case EXPR_SYMBOL:
-	case EXPR_DEREF:
-		name = expr_to_var_sym(expr, &sym);
-		if (!name)
-			return;
-		set_new_true_false_paths(name, sym);
-		free_string(name);
-		return;
-	case EXPR_ASSIGNMENT:
-		 /* You have to deal with stuff like if (a = b = c) */
-		match_condition(expr->right);
-		match_condition(expr->left);
-		return;
-	default:
-		return;
-	}
-}
-
-static void match_function_call(struct expression *expr)
-{
-	struct expression *tmp;
-	struct symbol *sym;
-	char *name;
-	struct sm_state *state;
-
-	FOR_EACH_PTR(expr->args, tmp) {
-		tmp = strip_expr(tmp);
-		name = expr_to_str_sym(tmp, &sym);
-		if (!name)
-			continue;
-		if ((state = get_sm_state(my_id, name, sym))) {
-			if (possibly_allocated(state->possible)) {
-				set_state(my_id, name, sym, &assigned);
-			}
-		}
-		assign_parent(sym);
-		free_string(name);
-	} END_FOR_EACH_PTR(tmp);
-}
-
-static void match_end_func(struct symbol *sym)
-{
-	if (__inline_fn)
-		return;
-	check_for_allocated();
-}
-
-static void match_after_func(struct symbol *sym)
-{
-	if (__inline_fn)
-		return;
-	free_trackers_and_list(&arguments);
-}
-
-static void register_funcs_from_file(void)
-{
-	struct token *token;
-	const char *func;
-	int arg;
-
-	token = get_tokens_file("kernel.frees_argument");
-	if (!token)
-		return;
-	if (token_type(token) != TOKEN_STREAMBEGIN)
-		return;
-	token = token->next;
-	while (token_type(token) != TOKEN_STREAMEND) {
-		if (token_type(token) != TOKEN_IDENT)
-			return;
-		func = show_ident(token->ident);
-		token = token->next;
-		if (token_type(token) != TOKEN_NUMBER)
-			return;
-		arg = atoi(token->number);
-		add_function_hook(func, &match_free_func, INT_PTR(arg));
-		token = token->next;
-	}
-	clear_token_alloc();
-}
-
-void check_memory(int id)
-{
-	my_id = id;
-	add_unmatched_state_hook(my_id, &unmatched_state);
-	add_hook(&match_function_def, FUNC_DEF_HOOK);
-	add_hook(&match_declarations, DECLARATION_HOOK);
-	add_hook(&match_function_call, FUNCTION_CALL_HOOK);
-	add_hook(&match_condition, CONDITION_HOOK);
-	add_hook(&match_assign, ASSIGNMENT_HOOK);
-	add_hook(&match_return, RETURN_HOOK);
-	add_hook(&match_end_func, END_FUNC_HOOK);
-	add_hook(&match_after_func, AFTER_FUNC_HOOK);
-	add_modification_hook(my_id, &set_unfree);
-	if (option_project == PROJ_KERNEL) {
-		add_function_hook("kfree", &match_free_func, (void *)0);
-		register_funcs_from_file();
-	} else {
-		add_function_hook("free", &match_free_func, (void *)0);
-	}
-}
--- old/usr/src/tools/smatch/src/check_memset.c	Mon Nov 18 13:18:46 2019
+++ new/usr/src/tools/smatch/src/check_memset.c	Mon Nov 18 13:18:47 2019
@@ -19,16 +19,13 @@
 
 static int my_id;
 
-static void match_memset(const char *fn, struct expression *expr, void *data)
+static void check_size_not_zero(struct expression *expr)
 {
-	struct expression *arg_expr;
 	sval_t sval;
 
-	arg_expr = get_argument_from_call_expr(expr->args, 2);
-
-	if (arg_expr->type != EXPR_VALUE)
+	if (expr->type != EXPR_VALUE)
 		return;
-	if (!get_value(arg_expr, &sval))
+	if (!get_value(expr, &sval))
 		return;
 	if (sval.value != 0)
 		return;
@@ -35,6 +32,26 @@
 	sm_error("calling memset(x, y, 0);");
 }
 
+static void check_size_not_ARRAY_SIZE(struct expression *expr)
+{
+	char *name;
+
+	name = get_macro_name(expr->pos);
+	if (name && strcmp(name, "ARRAY_SIZE") == 0)
+		sm_warning("calling memset(x, y, ARRAY_SIZE());");
+}
+
+static void match_memset(const char *fn, struct expression *expr, void *data)
+{
+	struct expression *arg_expr;
+
+	arg_expr = get_argument_from_call_expr(expr->args, 2);
+	if (!arg_expr)
+		return;
+	check_size_not_zero(arg_expr);
+	check_size_not_ARRAY_SIZE(arg_expr);
+}
+
 void check_memset(int id)
 {
 	my_id = id;
--- old/usr/src/tools/smatch/src/check_nospec.c	Mon Nov 18 13:18:47 2019
+++ new/usr/src/tools/smatch/src/check_nospec.c	Mon Nov 18 13:18:47 2019
@@ -179,6 +179,8 @@
 
 	if (!stmt || stmt->type != STMT_ASM)
 		return 0;
+	if (!stmt->asm_string)
+		return 0;
 	macro = get_macro_name(stmt->asm_string->pos);
 	if (!macro || strcmp(macro, "CALL_NOSPEC") != 0)
 		return 0;
--- old/usr/src/tools/smatch/src/check_readl_infinite_loops.c	Mon Nov 18 13:18:47 2019
+++ new/usr/src/tools/smatch/src/check_readl_infinite_loops.c	Mon Nov 18 13:18:47 2019
@@ -126,7 +126,7 @@
 
 	if (!stmt || stmt->type != STMT_ITERATOR)
 		return;
-	if (ptr_list_empty(state_at_start))
+	if (ptr_list_empty((struct ptr_list *)state_at_start))
 		returned = 0;
 	state = get_state(my_id, "depends on", NULL);
 	push_state_at_start(state);
--- old/usr/src/tools/smatch/src/check_rosenberg.c	Mon Nov 18 13:18:48 2019
+++ new/usr/src/tools/smatch/src/check_rosenberg.c	Mon Nov 18 13:18:48 2019
@@ -28,6 +28,7 @@
 
 static int my_whole_id;
 static int my_member_id;
+static int skb_put_id;
 
 STATE(cleared);
 
@@ -124,19 +125,6 @@
 	return toplevel(sym->scope);
 }
 
-static int was_initialized(struct expression *expr)
-{
-	struct symbol *sym;
-	char *name;
-
-	name = expr_to_var_sym(expr, &sym);
-	if (!name)
-		return 0;
-	if (sym->initializer)
-		return 1;
-	return 0;
-}
-
 static void match_clear(const char *fn, struct expression *expr, void *_arg_no)
 {
 	struct expression *ptr;
@@ -258,8 +246,21 @@
 
 	if (has_global_scope(data))
 		return;
-	if (was_initialized(data))
+	if (was_memset(data))
 		return;
+	if (warn_on_holey_struct(data))
+		return;
+	check_members_initialized(data);
+}
+
+static void check_skb_put(struct expression *data)
+{
+	data = strip_expr(data);
+	if (!data)
+		return;
+	if (data->type == EXPR_PREOP && data->op == '&')
+		data = strip_expr(data->unop);
+
 	if (was_memset(data))
 		return;
 	if (warn_on_holey_struct(data))
@@ -291,16 +292,51 @@
 	match_clear(NULL, expr, INT_PTR(param));
 }
 
-static void match_assign(struct expression *expr)
+static struct smatch_state *alloc_expr_state(struct expression *expr)
 {
+	struct smatch_state *state;
+	char *name;
+
+	name = expr_to_str(expr);
+	if (!name)
+		return NULL;
+
+	state = __alloc_smatch_state(0);
+	expr = strip_expr(expr);
+	state->name = alloc_sname(name);
+	free_string(name);
+	state->data = expr;
+	return state;
+}
+
+static void match_skb_put(const char *fn, struct expression *expr, void *unused)
+{
 	struct symbol *type;
+	struct smatch_state *state;
 
 	type = get_type(expr->left);
+	type = get_real_base_type(type);
 	if (!type || type->type != SYM_STRUCT)
 		return;
-	set_state_expr(my_whole_id, expr->left, &cleared);
+	state = alloc_expr_state(expr->left);
+	set_state_expr(skb_put_id, expr->left, state);
 }
 
+static void match_return_skb_put(struct expression *expr)
+{
+	struct sm_state *sm;
+	struct stree *stree;
+
+	if (is_error_return(expr))
+		return;
+
+	stree = __get_cur_stree();
+
+	FOR_EACH_MY_SM(skb_put_id, stree, sm) {
+		check_skb_put(sm->state->data);
+	} END_FOR_EACH_SM(sm);
+}
+
 static void register_clears_argument(void)
 {
 	struct token *token;
@@ -369,7 +405,6 @@
 	add_function_hook("__builtin_memset", &match_clear, INT_PTR(0));
 	add_function_hook("__builtin_memcpy", &match_clear, INT_PTR(0));
 
-	add_hook(&match_assign, ASSIGNMENT_HOOK);
 	register_clears_argument();
 	select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
 
@@ -386,3 +421,14 @@
 	add_extra_mod_hook(&extra_mod_hook);
 }
 
+void check_rosenberg3(int id)
+{
+	if (option_project != PROJ_KERNEL)
+		return;
+
+	skb_put_id = id;
+	set_dynamic_states(skb_put_id);
+	add_function_assign_hook("skb_put", &match_skb_put, NULL);
+	add_hook(&match_return_skb_put, RETURN_HOOK);
+}
+
--- old/usr/src/tools/smatch/src/check_testing_index_after_use.c	Mon Nov 18 13:18:48 2019
+++ new/usr/src/tools/smatch/src/check_testing_index_after_use.c	Mon Nov 18 13:18:48 2019
@@ -58,7 +58,7 @@
 	if (buf_comparison_index_ok(expr))
 		return;
 
-	if (getting_address())
+	if (getting_address(expr))
 		return;
 	if (is_capped(offset))
 		return;
--- old/usr/src/tools/smatch/src/check_uninitialized.c	Mon Nov 18 13:18:48 2019
+++ new/usr/src/tools/smatch/src/check_uninitialized.c	Mon Nov 18 13:18:48 2019
@@ -24,10 +24,10 @@
 STATE(uninitialized);
 STATE(initialized);
 
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
 	if (is_impossible_path())
-		set_state(my_id, sm->name, sm->sym, &initialized);
+		set_state(my_id, cur->name, cur->sym, &initialized);
 }
 
 static void mark_members_uninitialized(struct symbol *sym)
@@ -113,7 +113,7 @@
 
 	if (expr->type != EXPR_COMPARE || expr->op != '<')
 		return;
-	if (!is_zero(expr->right))
+	if (!expr_is_zero(expr->right))
 		return;
 	if (get_implied_max(expr->left, &max) && max.value == 0)
 		return;
--- old/usr/src/tools/smatch/src/check_unwind.c	Mon Nov 18 13:18:49 2019
+++ new/usr/src/tools/smatch/src/check_unwind.c	Mon Nov 18 13:18:49 2019
@@ -125,7 +125,7 @@
 	if (!type || type->type != SYM_FN)
 		return 0;
 	type = get_base_type(type);
-	if (type->ctype.base_type == &int_type) {
+	if (type && type->ctype.base_type == &int_type) {
 		return 1;
 	}
 	return 0;
--- old/usr/src/tools/smatch/src/compat.h	Mon Nov 18 13:18:49 2019
+++ new/usr/src/tools/smatch/src/compat.h	Mon Nov 18 13:18:49 2019
@@ -10,8 +10,6 @@
  *  - "string to long double" (C99 strtold())
  *	Missing in Solaris and MinGW
  */
-struct stream;
-struct stat;
 
 /*
  * Our "blob" allocator works on chunks that are multiples
--- old/usr/src/tools/smatch/src/compile-i386.c	Mon Nov 18 13:18:49 2019
+++ new/usr/src/tools/smatch/src/compile-i386.c	Mon Nov 18 13:18:49 2019
@@ -193,7 +193,6 @@
 static void emit_comment(const char * fmt, ...) FORMAT_ATTR(1);
 static void emit_move(struct storage *src, struct storage *dest,
 		      struct symbol *ctype, const char *comment);
-static int type_is_signed(struct symbol *sym);
 static struct storage *x86_address_gen(struct expression *expr);
 static struct storage *x86_symbol_expr(struct symbol *sym);
 static void x86_symbol(struct symbol *sym);
@@ -452,7 +451,7 @@
 		strcpy(name, s->reg->name);
 		break;
 	case STOR_VALUE:
-		sprintf(name, "$%Ld", s->value);
+		sprintf(name, "$%lld", s->value);
 		break;
 	case STOR_LABEL:
 		sprintf(name, "%s.L%d", s->flags & STOR_LABEL_VAL ? "$" : "",
@@ -937,7 +936,7 @@
 
 	assert(type != NULL);
 
-	printf("\t.%s\t%Ld\n", type, ll);
+	printf("\t.%s\t%lld\n", type, ll);
 }
 
 static void emit_global_noinit(const char *name, unsigned long modifiers,
@@ -1163,7 +1162,7 @@
 
 	if (ctype) {
 		bits = ctype->bit_size;
-		is_signed = type_is_signed(ctype);
+		is_signed = is_signed_type(ctype);
 	} else {
 		bits = 32;
 		is_signed = 0;
@@ -1355,7 +1354,7 @@
 	if ((expr->op == '/') || (expr->op == '%'))
 		return emit_divide(expr, left, right);
 
-	is_signed = type_is_signed(expr->ctype);
+	is_signed = is_signed_type(expr->ctype);
 
 	switch (expr->op) {
 	case '+':
@@ -1555,7 +1554,7 @@
 
 static struct storage *emit_conditional_expr(struct expression *expr)
 {
-	struct storage *cond, *true = NULL, *false = NULL;
+	struct storage *cond, *stot = NULL, *stof = NULL;
 	struct storage *new = stack_alloc(expr->ctype->bit_size / 8);
 	int target_false, cond_end;
 
@@ -1564,16 +1563,16 @@
 	target_false = emit_conditional_test(cond);
 
 	/* handle if-true part of the expression */
-	true = x86_expression(expr->cond_true);
+	stot = x86_expression(expr->cond_true);
 
-	emit_copy(new, true, expr->ctype);
+	emit_copy(new, stot, expr->ctype);
 
 	cond_end = emit_conditional_end(target_false);
 
 	/* handle if-false part of the expression */
-	false = x86_expression(expr->cond_false);
+	stof = x86_expression(expr->cond_false);
 
-	emit_copy(new, false, expr->ctype);
+	emit_copy(new, stof, expr->ctype);
 
 	/* end of conditional; jump target for if-true branch */
 	emit_label(cond_end, "end conditional");
@@ -1584,15 +1583,15 @@
 static struct storage *emit_select_expr(struct expression *expr)
 {
 	struct storage *cond = x86_expression(expr->conditional);
-	struct storage *true = x86_expression(expr->cond_true);
-	struct storage *false = x86_expression(expr->cond_false);
+	struct storage *stot = x86_expression(expr->cond_true);
+	struct storage *stof = x86_expression(expr->cond_false);
 	struct storage *reg_cond, *reg_true, *reg_false;
 	struct storage *new = stack_alloc(4);
 
 	emit_comment("begin SELECT");
 	reg_cond = get_reg_value(cond, get_regclass(expr->conditional));
-	reg_true = get_reg_value(true, get_regclass(expr));
-	reg_false = get_reg_value(false, get_regclass(expr));
+	reg_true = get_reg_value(stot, get_regclass(expr));
+	reg_false = get_reg_value(stof, get_regclass(expr));
 
 	/*
 	 * Do the actual select: check the conditional for zero,
@@ -2236,7 +2235,7 @@
 		return new;
 	}
 	if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
-		printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, sym->value);
+		printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, 0LL);
 		return new;
 	}
 	printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
@@ -2264,15 +2263,6 @@
 	priv->addr = new;
 }
 
-static int type_is_signed(struct symbol *sym)
-{
-	if (sym->type == SYM_NODE)
-		sym = sym->ctype.base_type;
-	if (sym->type == SYM_PTR)
-		return 0;
-	return !(sym->ctype.modifiers & MOD_UNSIGNED);
-}
-
 static struct storage *x86_label_expr(struct expression *expr)
 {
 	struct storage *new = stack_alloc(4);
--- old/usr/src/tools/smatch/src/compile.c	Mon Nov 18 13:18:50 2019
+++ new/usr/src/tools/smatch/src/compile.c	Mon Nov 18 13:18:50 2019
@@ -59,7 +59,7 @@
 	bits_in_bool = 8;
 
 	clean_up_symbols(sparse_initialize(argc, argv, &filelist));
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		struct symbol_list *list;
 		const char *basename = strrchr(file, '/');
 		basename = basename ?  basename+1 : file;
@@ -70,7 +70,7 @@
 		emit_unit_begin(basename);
 		clean_up_symbols(list);
 		emit_unit_end();
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 #if 0
 	// And show the allocation statistics
--- old/usr/src/tools/smatch/src/cse.c	Mon Nov 18 13:18:50 2019
+++ new/usr/src/tools/smatch/src/cse.c	Mon Nov 18 13:18:50 2019
@@ -14,14 +14,14 @@
 
 #include "parse.h"
 #include "expression.h"
+#include "flowgraph.h"
 #include "linearize.h"
 #include "flow.h"
+#include "cse.h"
 
 #define INSN_HASH_SIZE 256
 static struct instruction_list *insn_hash_table[INSN_HASH_SIZE];
 
-int repeat_phase;
-
 static int phi_compare(pseudo_t phi1, pseudo_t phi2)
 {
 	const struct instruction *def1 = phi1->def;
@@ -35,16 +35,10 @@
 }
 
 
-static void clean_up_one_instruction(struct basic_block *bb, struct instruction *insn)
+void cse_collect(struct instruction *insn)
 {
 	unsigned long hash;
 
-	if (!insn->bb)
-		return;
-	assert(insn->bb == bb);
-	repeat_phase |= simplify_instruction(insn);
-	if (!insn->bb)
-		return;
 	hash = (insn->opcode << 3) + (insn->size >> 3);
 	switch (insn->opcode) {
 	case OP_SEL:
@@ -53,7 +47,7 @@
 
 	/* Binary arithmetic */
 	case OP_ADD: case OP_SUB:
-	case OP_MULU: case OP_MULS:
+	case OP_MUL:
 	case OP_DIVU: case OP_DIVS:
 	case OP_MODU: case OP_MODS:
 	case OP_SHL:
@@ -61,8 +55,7 @@
 	case OP_AND: case OP_OR:
 
 	/* Binary logical */
-	case OP_XOR: case OP_AND_BOOL:
-	case OP_OR_BOOL:
+	case OP_XOR:
 
 	/* Binary comparison */
 	case OP_SET_EQ: case OP_SET_NE:
@@ -70,11 +63,20 @@
 	case OP_SET_LT: case OP_SET_GT:
 	case OP_SET_B:  case OP_SET_A:
 	case OP_SET_BE: case OP_SET_AE:
+
+	/* floating-point arithmetic & comparison */
+	case OP_FPCMP ... OP_FPCMP_END:
+	case OP_FADD:
+	case OP_FSUB:
+	case OP_FMUL:
+	case OP_FDIV:
 		hash += hashval(insn->src2);
 		/* Fall through */
 	
 	/* Unary */
 	case OP_NOT: case OP_NEG:
+	case OP_FNEG:
+	case OP_SYMADDR:
 		hash += hashval(insn->src1);
 		break;
 
@@ -82,21 +84,20 @@
 		hash += hashval(insn->val);
 		break;
 
-	case OP_SYMADDR:
-		hash += hashval(insn->symbol);
+	case OP_SETFVAL:
+		hash += hashval(insn->fvalue);
 		break;
 
-	case OP_CAST:
-	case OP_SCAST:
+	case OP_SEXT: case OP_ZEXT:
+	case OP_TRUNC:
 	case OP_PTRCAST:
-		/*
-		 * This is crap! Many "orig_types" are the
-		 * same as far as casts go, we should generate
-		 * some kind of "type hash" that is identical
-		 * for identical casts
-		 */
-		hash += hashval(insn->orig_type);
+	case OP_UTPTR: case OP_PTRTU:
+		if (!insn->orig_type || insn->orig_type->bit_size < 0)
+			return;
 		hash += hashval(insn->src);
+
+		// Note: see corresponding line in insn_compare()
+		hash += hashval(insn->orig_type->bit_size);
 		break;
 
 	/* Other */
@@ -125,18 +126,6 @@
 	add_instruction(insn_hash_table + hash, insn);
 }
 
-static void clean_up_insns(struct entrypoint *ep)
-{
-	struct basic_block *bb;
-
-	FOR_EACH_PTR(ep->bbs, bb) {
-		struct instruction *insn;
-		FOR_EACH_PTR(bb->insns, insn) {
-			clean_up_one_instruction(bb, insn);
-		} END_FOR_EACH_PTR(insn);
-	} END_FOR_EACH_PTR(bb);
-}
-
 /* Compare two (sorted) phi-lists */
 static int phi_list_compare(struct pseudo_list *l1, struct pseudo_list *l2)
 {
@@ -171,6 +160,8 @@
 {
 	const struct instruction *i1 = _i1;
 	const struct instruction *i2 = _i2;
+	int size1, size2;
+	int diff;
 
 	if (i1->opcode != i2->opcode)
 		return i1->opcode < i2->opcode ? -1 : 1;
@@ -179,8 +170,7 @@
 
 	/* commutative binop */
 	case OP_ADD:
-	case OP_MULU: case OP_MULS:
-	case OP_AND_BOOL: case OP_OR_BOOL:
+	case OP_MUL:
 	case OP_AND: case OP_OR:
 	case OP_XOR:
 	case OP_SET_EQ: case OP_SET_NE:
@@ -205,6 +195,13 @@
 	case OP_SET_LT: case OP_SET_GT:
 	case OP_SET_B:  case OP_SET_A:
 	case OP_SET_BE: case OP_SET_AE:
+
+	/* floating-point arithmetic */
+	case OP_FPCMP ... OP_FPCMP_END:
+	case OP_FADD:
+	case OP_FSUB:
+	case OP_FMUL:
+	case OP_FDIV:
 	case_binops:
 		if (i1->src2 != i2->src2)
 			return i1->src2 < i2->src2 ? -1 : 1;
@@ -212,34 +209,43 @@
 
 	/* Unary */
 	case OP_NOT: case OP_NEG:
+	case OP_FNEG:
+	case OP_SYMADDR:
 		if (i1->src1 != i2->src1)
 			return i1->src1 < i2->src1 ? -1 : 1;
 		break;
 
-	case OP_SYMADDR:
-		if (i1->symbol != i2->symbol)
-			return i1->symbol < i2->symbol ? -1 : 1;
-		break;
-
 	case OP_SETVAL:
 		if (i1->val != i2->val)
 			return i1->val < i2->val ? -1 : 1;
 		break;
 
+	case OP_SETFVAL:
+		diff = memcmp(&i1->fvalue, &i2->fvalue, sizeof(i1->fvalue));
+		if (diff)
+			return diff;
+		break;
+
 	/* Other */
 	case OP_PHI:
 		return phi_list_compare(i1->phi_list, i2->phi_list);
 
-	case OP_CAST:
-	case OP_SCAST:
+	case OP_SEXT: case OP_ZEXT:
+	case OP_TRUNC:
 	case OP_PTRCAST:
-		/*
-		 * This is crap! See the comments on hashing.
-		 */
-		if (i1->orig_type != i2->orig_type)
-			return i1->orig_type < i2->orig_type ? -1 : 1;
+	case OP_UTPTR: case OP_PTRTU:
 		if (i1->src != i2->src)
 			return i1->src < i2->src ? -1 : 1;
+
+		// Note: if it can be guaranted that identical ->src
+		// implies identical orig_type->bit_size, then this
+		// test and the hashing of the original size in
+		// cse_collect() are not needed.
+		// It must be generaly true but it isn't guaranted (yet).
+		size1 = i1->orig_type->bit_size;
+		size2 = i2->orig_type->bit_size;
+		if (size1 != size2)
+			return size1 < size2 ? -1 : 1;
 		break;
 
 	default:
@@ -264,28 +270,6 @@
 	return def;
 }
 
-/*
- * Does "bb1" dominate "bb2"?
- */
-static int bb_dominates(struct entrypoint *ep, struct basic_block *bb1, struct basic_block *bb2, unsigned long generation)
-{
-	struct basic_block *parent;
-
-	/* Nothing dominates the entrypoint.. */
-	if (bb2 == ep->entry->bb)
-		return 0;
-	FOR_EACH_PTR(bb2->parents, parent) {
-		if (parent == bb1)
-			continue;
-		if (parent->generation == generation)
-			continue;
-		parent->generation = generation;
-		if (!bb_dominates(ep, bb1, parent, generation))
-			return 0;
-	} END_FOR_EACH_PTR(parent);
-	return 1;
-}
-
 static struct basic_block *trivial_common_parent(struct basic_block *bb1, struct basic_block *bb2)
 {
 	struct basic_block *parent;
@@ -339,10 +323,10 @@
 		warning(b1->pos, "Whaa? unable to find CSE instructions");
 		return i1;
 	}
-	if (bb_dominates(ep, b1, b2, ++bb_generation))
+	if (domtree_dominates(b1, b2))
 		return cse_one_instruction(i2, i1);
 
-	if (bb_dominates(ep, b2, b1, ++bb_generation))
+	if (domtree_dominates(b2, b1))
 		return cse_one_instruction(i1, i2);
 
 	/* No direct dominance - but we could try to find a common ancestor.. */
@@ -351,21 +335,17 @@
 		i1 = cse_one_instruction(i2, i1);
 		remove_instruction(&b1->insns, i1, 1);
 		add_instruction_to_end(i1, common);
+	} else {
+		i1 = i2;
 	}
 
 	return i1;
 }
 
-void cleanup_and_cse(struct entrypoint *ep)
+void cse_eliminate(struct entrypoint *ep)
 {
 	int i;
 
-	simplify_memops(ep);
-repeat:
-	repeat_phase = 0;
-	clean_up_insns(ep);
-	if (repeat_phase & REPEAT_CFG_CLEANUP)
-		kill_unreachable_bbs(ep);
 	for (i = 0; i < INSN_HASH_SIZE; i++) {
 		struct instruction_list **list = insn_hash_table + i;
 		if (*list) {
@@ -385,13 +365,7 @@
 					last = insn;
 				} END_FOR_EACH_PTR(insn);
 			}
-			free_ptr_list((struct ptr_list **)list);
+			free_ptr_list(list);
 		}
 	}
-
-	if (repeat_phase & REPEAT_SYMBOL_CLEANUP)
-		simplify_memops(ep);
-
-	if (repeat_phase & REPEAT_CSE)
-		goto repeat;
 }
--- /dev/null	Mon Nov 18 13:18:51 2019
+++ new/usr/src/tools/smatch/src/cse.h	Mon Nov 18 13:18:51 2019
@@ -0,0 +1,11 @@
+#ifndef CSE_H
+#define CSE_H
+
+struct instruction;
+struct entrypoint;
+
+/* cse.c */
+void cse_collect(struct instruction *insn);
+void cse_eliminate(struct entrypoint *ep);
+
+#endif
--- old/usr/src/tools/smatch/src/ctags.c	Mon Nov 18 13:18:51 2019
+++ new/usr/src/tools/smatch/src/ctags.c	Mon Nov 18 13:18:51 2019
@@ -135,7 +135,7 @@
 
 	switch (sym->type) {
 	case SYM_NODE:
-		if (base->type == SYM_FN)
+		if (base && base->type == SYM_FN)
 			sym->kind = 'f';
 		examine_symbol(base);
 		break;
@@ -216,10 +216,10 @@
 	char *file;
 
 	examine_symbol_list(sparse_initialize(argc, argv, &filelist));
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		sparse(file);
 		examine_symbol_list(file_scope->symbols);
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 	examine_symbol_list(global_scope->symbols);
 	sort_list((struct ptr_list **)&taglist, cmp_sym);
 	show_tags(taglist);
--- /dev/null	Mon Nov 18 13:18:51 2019
+++ new/usr/src/tools/smatch/src/dominate.c	Mon Nov 18 13:18:51 2019
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: MIT
+//
+// dominate.c - compute the (iterated) dominance frontier of (a set of) nodes.
+//
+// Copyright (C) 2017 - Luc Van Oostenryck
+//
+// The algorithm used is the one described in:
+//	"A Linear Time Algorithm for Placing phi-nodes"
+//	by Vugranam C. Sreedhar and Guang R. Gao
+//
+
+#include "dominate.h"
+#include "flowgraph.h"
+#include "linearize.h"
+#include "flow.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+struct piggy {
+	unsigned int max;
+	struct basic_block_list *lists[0];
+};
+
+static struct piggy *bank_init(unsigned levels)
+{
+	struct piggy *bank;
+	bank = calloc(1, sizeof(*bank) + levels * sizeof(bank->lists[0]));
+	bank->max = levels - 1;
+	return bank;
+}
+
+static void bank_free(struct piggy *bank, unsigned int levels)
+{
+	for (; levels-- ;)
+		free_ptr_list(&bank->lists[levels]);
+	free(bank);
+}
+
+static void bank_put(struct piggy *bank, struct basic_block *bb)
+{
+	unsigned int level = bb->dom_level;
+	assert(level <= bank->max);
+	add_bb(&bank->lists[level], bb);
+}
+
+static inline struct basic_block *pop_bb(struct basic_block_list **list)
+{
+	return delete_ptr_list_last((struct ptr_list **)list);
+}
+
+static struct basic_block *bank_get(struct piggy *bank)
+{
+	int level = bank->max;
+	do {
+		struct basic_block *bb = pop_bb(&bank->lists[level]);
+		if (bb)
+			return bb;
+		if (!level)
+			return NULL;
+		bank->max = --level;
+	} while (1);
+}
+
+
+#define	VISITED	0x1
+#define	INPHI	0x2
+#define	ALPHA	0x4
+#define	FLAGS	0x7
+
+static void visit(struct piggy *bank, struct basic_block_list **idf, struct basic_block *x, int curr_level)
+{
+	struct basic_block *y;
+
+	x->generation |= 1;
+	FOR_EACH_PTR(x->children, y) {
+		unsigned flags = y->generation & FLAGS;
+		if (y->idom == x)	// J-edges will be processed later
+			continue;
+		if (y->dom_level > curr_level)
+			continue;
+		if (flags & INPHI)
+			continue;
+		y->generation |= INPHI;
+		add_bb(idf, y);
+		if (flags & ALPHA)
+			continue;
+		bank_put(bank, y);
+	} END_FOR_EACH_PTR(y);
+
+	FOR_EACH_PTR(x->doms, y) {
+		if (y->generation & VISITED)
+			continue;
+		visit(bank, idf, y, curr_level);
+	} END_FOR_EACH_PTR(y);
+}
+
+void idf_compute(struct entrypoint *ep, struct basic_block_list **idf, struct basic_block_list *alpha)
+{
+	int levels = ep->dom_levels;
+	struct piggy *bank = bank_init(levels);
+	struct basic_block *bb;
+	unsigned long generation = bb_generation;
+
+	generation = bb_generation;
+	generation += -generation & FLAGS;
+	bb_generation = generation + (FLAGS + 1);
+
+	// init all the nodes
+	FOR_EACH_PTR(ep->bbs, bb) {
+		// FIXME: this should be removed and the tests for
+		//	  visited/in_phi/alpha should use a sparse set
+		bb->generation = generation;
+	} END_FOR_EACH_PTR(bb);
+
+	FOR_EACH_PTR(alpha, bb) {
+		bb->generation = generation | ALPHA;
+		bank_put(bank, bb);
+	} END_FOR_EACH_PTR(bb);
+
+	while ((bb = bank_get(bank))) {
+		visit(bank, idf, bb, bb->dom_level);
+	}
+
+	bank_free(bank, levels);
+}
+
+void idf_dump(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+
+	domtree_build(ep);
+
+	printf("%s's IDF:\n", show_ident(ep->name->ident));
+	FOR_EACH_PTR(ep->bbs, bb) {
+		struct basic_block_list *alpha = NULL;
+		struct basic_block_list *idf = NULL;
+		struct basic_block *df;
+
+		add_bb(&alpha, bb);
+		idf_compute(ep, &idf, alpha);
+
+		printf("\t%s\t<-", show_label(bb));
+		FOR_EACH_PTR(idf, df) {
+			printf(" %s", show_label(df));
+		} END_FOR_EACH_PTR(df);
+		printf("\n");
+
+		free_ptr_list(&idf);
+		free_ptr_list(&alpha);
+	} END_FOR_EACH_PTR(bb);
+}
--- /dev/null	Mon Nov 18 13:18:51 2019
+++ new/usr/src/tools/smatch/src/dominate.h	Mon Nov 18 13:18:51 2019
@@ -0,0 +1,13 @@
+#ifndef DOMINATE_H
+#define DOMINATE_H
+
+struct entrypoint;
+struct basic_block_list;
+
+void idf_compute(struct entrypoint *ep, struct basic_block_list **idf, struct basic_block_list *alpha);
+
+
+// For debugging only
+void idf_dump(struct entrypoint *ep);
+
+#endif
--- old/usr/src/tools/smatch/src/evaluate.c	Mon Nov 18 13:18:52 2019
+++ new/usr/src/tools/smatch/src/evaluate.c	Mon Nov 18 13:18:52 2019
@@ -34,6 +34,7 @@
 #include <fcntl.h>
 #include <limits.h>
 
+#include "evaluate.h"
 #include "lib.h"
 #include "allocate.h"
 #include "parse.h"
@@ -44,9 +45,22 @@
 
 struct symbol *current_fn;
 
+struct ident bad_address_space = { .len = 6, .name = "bad AS", };
+
 static struct symbol *degenerate(struct expression *expr);
 static struct symbol *evaluate_symbol(struct symbol *sym);
 
+static inline int valid_expr_type(struct expression *expr)
+{
+	return expr && valid_type(expr->ctype);
+}
+
+static inline int valid_subexpr_type(struct expression *expr)
+{
+	return valid_expr_type(expr->left)
+	    && valid_expr_type(expr->right);
+}
+
 static struct symbol *evaluate_symbol_expression(struct expression *expr)
 {
 	struct expression *addr;
@@ -196,14 +210,14 @@
 	       orig->bit_offset == new->bit_offset;
 }
 
-static struct symbol *base_type(struct symbol *node, unsigned long *modp, unsigned long *asp)
+static struct symbol *base_type(struct symbol *node, unsigned long *modp, struct ident **asp)
 {
-	unsigned long mod, as;
+	unsigned long mod = 0;
+	struct ident *as = NULL;
 
-	mod = 0; as = 0;
 	while (node) {
 		mod |= node->ctype.modifiers;
-		as |= node->ctype.as;
+		combine_address_space(node->pos, &as, node->ctype.as);
 		if (node->type == SYM_NODE) {
 			node = node->ctype.base_type;
 			continue;
@@ -218,7 +232,8 @@
 static int is_same_type(struct expression *expr, struct symbol *new)
 {
 	struct symbol *old = expr->ctype;
-	unsigned long oldmod, newmod, oldas, newas;
+	unsigned long oldmod, newmod;
+	struct ident *oldas, *newas;
 
 	old = base_type(old, &oldmod, &oldas);
 	new = base_type(new, &newmod, &newas);
@@ -393,15 +408,20 @@
 
 static struct symbol *bad_expr_type(struct expression *expr)
 {
-	sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
 	switch (expr->type) {
 	case EXPR_BINOP:
 	case EXPR_COMPARE:
+		if (!valid_subexpr_type(expr))
+			break;
+		sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
 		info(expr->pos, "   left side has type %s", show_typename(expr->left->ctype));
 		info(expr->pos, "   right side has type %s", show_typename(expr->right->ctype));
 		break;
 	case EXPR_PREOP:
 	case EXPR_POSTOP:
+		if (!valid_expr_type(expr->unop))
+			break;
+		sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
 		info(expr->pos, "   argument has type %s", show_typename(expr->unop->ctype));
 		break;
 	default:
@@ -638,12 +658,12 @@
 
 static void examine_fn_arguments(struct symbol *fn);
 
-#define MOD_IGN (MOD_VOLATILE | MOD_CONST | MOD_PURE)
+#define MOD_IGN (MOD_QUALIFIER | MOD_PURE)
 
 const char *type_difference(struct ctype *c1, struct ctype *c2,
 	unsigned long mod1, unsigned long mod2)
 {
-	unsigned long as1 = c1->as, as2 = c2->as;
+	struct ident *as1 = c1->as, *as2 = c2->as;
 	struct symbol *t1 = c1->base_type;
 	struct symbol *t2 = c2->base_type;
 	int move1 = 1, move2 = 1;
@@ -661,7 +681,7 @@
 		if (move1) {
 			if (t1 && t1->type != SYM_PTR) {
 				mod1 |= t1->ctype.modifiers;
-				as1 |= t1->ctype.as;
+				combine_address_space(t1->pos, &as1, t1->ctype.as);
 			}
 			move1 = 0;
 		}
@@ -669,7 +689,7 @@
 		if (move2) {
 			if (t2 && t2->type != SYM_PTR) {
 				mod2 |= t2->ctype.modifiers;
-				as2 |= t2->ctype.as;
+				combine_address_space(t2->pos, &as2, t2->ctype.as);
 			}
 			move2 = 0;
 		}
@@ -847,8 +867,10 @@
 		val->value = value;
 
 		if (value & (value-1)) {
-			if (Wptr_subtraction_blows)
+			if (Wptr_subtraction_blows) {
 				warning(expr->pos, "potentially expensive pointer subtraction");
+				info(expr->pos, "    '%s' has a non-power-of-2 size: %lu", show_typename(lbase), value);
+			}
 		}
 
 		sub->op = '-';
@@ -877,23 +899,23 @@
 		warning(expr->pos, "assignment expression in conditional");
 
 	ctype = evaluate_expression(expr);
-	if (ctype) {
-		if (is_safe_type(ctype))
-			warning(expr->pos, "testing a 'safe expression'");
-		if (is_func_type(ctype)) {
-			if (Waddress)
-				warning(expr->pos, "the address of %s will always evaluate as true", "a function");
-		} else if (is_array_type(ctype)) {
-			if (Waddress)
-				warning(expr->pos, "the address of %s will always evaluate as true", "an array");
-		} else if (!is_scalar_type(ctype)) {
-			sparse_error(expr->pos, "incorrect type in conditional");
-			info(expr->pos, "   got %s", show_typename(ctype));
-			ctype = NULL;
-		}
+	if (!valid_type(ctype))
+		return NULL;
+	if (is_safe_type(ctype))
+		warning(expr->pos, "testing a 'safe expression'");
+	if (is_func_type(ctype)) {
+		if (Waddress)
+			warning(expr->pos, "the address of %s will always evaluate as true", "a function");
+	} else if (is_array_type(ctype)) {
+		if (Waddress)
+			warning(expr->pos, "the address of %s will always evaluate as true", "an array");
+	} else if (!is_scalar_type(ctype)) {
+		sparse_error(expr->pos, "incorrect type in conditional (non-scalar type)");
+		info(expr->pos, "   got %s", show_typename(ctype));
+		return NULL;
 	}
-	ctype = degenerate(expr);
 
+	ctype = degenerate(expr);
 	return ctype;
 }
 
@@ -1005,13 +1027,19 @@
 	return op;
 }
 
+enum null_constant_type {
+	NON_NULL,
+	NULL_PTR,
+	NULL_ZERO,
+};
+
 static inline int is_null_pointer_constant(struct expression *e)
 {
 	if (e->ctype == &null_ctype)
-		return 1;
+		return NULL_PTR;
 	if (!(e->flags & CEF_ICE))
-		return 0;
-	return is_zero_constant(e) ? 2 : 0;
+		return NON_NULL;
+	return is_zero_constant(e) ? NULL_ZERO : NON_NULL;
 }
 
 static struct symbol *evaluate_compare(struct expression *expr)
@@ -1057,9 +1085,9 @@
 	if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) {
 		int is_null1 = is_null_pointer_constant(left);
 		int is_null2 = is_null_pointer_constant(right);
-		if (is_null1 == 2)
+		if (is_null1 == NULL_ZERO)
 			bad_null(left);
-		if (is_null2 == 2)
+		if (is_null2 == NULL_ZERO)
 			bad_null(right);
 		if (is_null1 && is_null2) {
 			int positive = expr->op == SPECIAL_EQUAL;
@@ -1104,7 +1132,9 @@
 	if (!typediff)
 		goto OK;
 
-	expression_error(expr, "incompatible types in comparison expression (%s)", typediff);
+	expression_error(expr, "incompatible types in comparison expression (%s):", typediff);
+	info(expr->pos, "   %s", show_typename(ltype));
+	info(expr->pos, "   %s", show_typename(rtype));
 	return NULL;
 
 OK:
@@ -1122,7 +1152,7 @@
  */
 static struct symbol *evaluate_conditional_expression(struct expression *expr)
 {
-	struct expression **true;
+	struct expression **cond;
 	struct symbol *ctype, *ltype, *rtype, *lbase, *rbase;
 	int lclass, rclass;
 	const char * typediff;
@@ -1136,16 +1166,16 @@
 	ctype = degenerate(expr->conditional);
 	rtype = degenerate(expr->cond_false);
 
-	true = &expr->conditional;
+	cond = &expr->conditional;
 	ltype = ctype;
 	if (expr->cond_true) {
 		if (!evaluate_expression(expr->cond_true))
 			return NULL;
 		ltype = degenerate(expr->cond_true);
-		true = &expr->cond_true;
+		cond = &expr->cond_true;
 	}
 
-	expr->flags = (expr->conditional->flags & (*true)->flags &
+	expr->flags = (expr->conditional->flags & (*cond)->flags &
 			expr->cond_false->flags & ~CEF_CONST_MASK);
 	/*
 	 * A conditional operator yields a particular constant
@@ -1161,37 +1191,37 @@
 	 * address constants, mark the result as an address constant.
 	 */
 	if (expr->conditional->flags & (CEF_ACE | CEF_ADDR))
-		expr->flags = (*true)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
+		expr->flags = (*cond)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
 
 	lclass = classify_type(ltype, &ltype);
 	rclass = classify_type(rtype, &rtype);
 	if (lclass & rclass & TYPE_NUM) {
-		ctype = usual_conversions('?', *true, expr->cond_false,
+		ctype = usual_conversions('?', *cond, expr->cond_false,
 					  lclass, rclass, ltype, rtype);
-		*true = cast_to(*true, ctype);
+		*cond = cast_to(*cond, ctype);
 		expr->cond_false = cast_to(expr->cond_false, ctype);
 		goto out;
 	}
 
 	if ((lclass | rclass) & TYPE_PTR) {
-		int is_null1 = is_null_pointer_constant(*true);
+		int is_null1 = is_null_pointer_constant(*cond);
 		int is_null2 = is_null_pointer_constant(expr->cond_false);
 
 		if (is_null1 && is_null2) {
-			*true = cast_to(*true, &ptr_ctype);
+			*cond = cast_to(*cond, &ptr_ctype);
 			expr->cond_false = cast_to(expr->cond_false, &ptr_ctype);
 			ctype = &ptr_ctype;
 			goto out;
 		}
 		if (is_null1 && (rclass & TYPE_PTR)) {
-			if (is_null1 == 2)
-				bad_null(*true);
-			*true = cast_to(*true, rtype);
+			if (is_null1 == NULL_ZERO)
+				bad_null(*cond);
+			*cond = cast_to(*cond, rtype);
 			ctype = rtype;
 			goto out;
 		}
 		if (is_null2 && (lclass & TYPE_PTR)) {
-			if (is_null2 == 2)
+			if (is_null2 == NULL_ZERO)
 				bad_null(expr->cond_false);
 			expr->cond_false = cast_to(expr->cond_false, ltype);
 			ctype = ltype;
@@ -1240,7 +1270,9 @@
 	typediff = "different base types";
 
 Err:
-	expression_error(expr, "incompatible types in conditional expression (%s)", typediff);
+	expression_error(expr, "incompatible types in conditional expression (%s):", typediff);
+	info(expr->pos, "   %s", show_typename(ltype));
+	info(expr->pos, "   %s", show_typename(rtype));
 	/*
 	 * if the condition is constant, the type is in fact known
 	 * so use it, as gcc & clang do.
@@ -1266,7 +1298,7 @@
 		sym->ctype.modifiers |= qual;
 		ctype = sym;
 	}
-	*true = cast_to(*true, ctype);
+	*cond = cast_to(*cond, ctype);
 	expr->cond_false = cast_to(expr->cond_false, ctype);
 	goto out;
 }
@@ -1306,6 +1338,11 @@
 				goto Cast;
 			if (!restricted_value(expr->right, t))
 				return 1;
+		} else if (op == SPECIAL_SHR_ASSIGN || op == SPECIAL_SHL_ASSIGN) {
+			// shifts do integer promotions, but that's it.
+			unrestrict(expr->right, sclass, &s);
+			target = integer_promotion(s);
+			goto Cast;
 		} else if (!(sclass & TYPE_RESTRICT))
 			goto usual;
 		/* source and target would better be identical restricted */
@@ -1394,7 +1431,7 @@
 		// NULL pointer is always OK
 		int is_null = is_null_pointer_constant(*rp);
 		if (is_null) {
-			if (is_null == 2)
+			if (is_null == NULL_ZERO)
 				bad_null(*rp);
 			goto Cast;
 		}
@@ -1544,7 +1581,6 @@
 static struct symbol *evaluate_assignment(struct expression *expr)
 {
 	struct expression *left = expr->left;
-	struct expression *where = expr;
 	struct symbol *ltype;
 
 	if (!lvalue_expression(left)) {
@@ -1558,7 +1594,7 @@
 		if (!evaluate_assign_op(expr))
 			return NULL;
 	} else {
-		if (!compatible_assignment_types(where, ltype, &expr->right, "assignment"))
+		if (!compatible_assignment_types(expr, ltype, &expr->right, "assignment"))
 			return NULL;
 	}
 
@@ -1585,11 +1621,11 @@
 					ptr->ctype = arg->ctype;
 				else
 					ptr->ctype.base_type = arg;
-				ptr->ctype.as |= s->ctype.as;
+				combine_address_space(s->pos, &ptr->ctype.as, s->ctype.as);
 				ptr->ctype.modifiers |= s->ctype.modifiers & MOD_PTRINHERIT;
 
 				s->ctype.base_type = ptr;
-				s->ctype.as = 0;
+				s->ctype.as = NULL;
 				s->ctype.modifiers &= ~MOD_PTRINHERIT;
 				s->bit_size = 0;
 				s->examined = 0;
@@ -1603,7 +1639,7 @@
 	} END_FOR_EACH_PTR(s);
 }
 
-static struct symbol *convert_to_as_mod(struct symbol *sym, int as, int mod)
+static struct symbol *convert_to_as_mod(struct symbol *sym, struct ident *as, int mod)
 {
 	/* Take the modifiers of the pointer, and apply them to the member */
 	mod |= sym->ctype.modifiers;
@@ -1635,12 +1671,12 @@
 		sym->ctype.modifiers &= ~MOD_REGISTER;
 	}
 	if (sym->type == SYM_NODE) {
-		ptr->ctype.as |= sym->ctype.as;
+		combine_address_space(sym->pos, &ptr->ctype.as, sym->ctype.as);
 		ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT;
 		sym = sym->ctype.base_type;
 	}
 	if (degenerate && sym->type == SYM_ARRAY) {
-		ptr->ctype.as |= sym->ctype.as;
+		combine_address_space(sym->pos, &ptr->ctype.as, sym->ctype.as);
 		ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT;
 		sym = sym->ctype.base_type;
 	}
@@ -1776,14 +1812,18 @@
 	if (ctype->type == SYM_NODE)
 		ctype = ctype->ctype.base_type;
 
-	node = alloc_symbol(expr->pos, SYM_NODE);
 	target = ctype->ctype.base_type;
+	examine_symbol_type(target);
 
 	switch (ctype->type) {
 	default:
 		expression_error(expr, "cannot dereference this type");
 		return NULL;
+	case SYM_FN:
+		*expr = *op;
+		return expr->ctype;
 	case SYM_PTR:
+		node = alloc_symbol(expr->pos, SYM_NODE);
 		node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER;
 		merge_type(node, ctype);
 		break;
@@ -1801,6 +1841,7 @@
 		 * When an array is dereferenced, we need to pick
 		 * up the attributes of the original node too..
 		 */
+		node = alloc_symbol(expr->pos, SYM_NODE);
 		merge_type(node, op->ctype);
 		merge_type(node, ctype);
 		break;
@@ -1914,6 +1955,7 @@
 		return evaluate_postop(expr);
 
 	case '!':
+		ctype = degenerate(expr->unop);
 		expr->flags = expr->unop->flags & ~CEF_CONST_MASK;
 		/*
 		 * A logical negation never yields an address constant
@@ -2021,8 +2063,8 @@
 	struct symbol *ctype, *member;
 	struct expression *deref = expr->deref, *add;
 	struct ident *ident = expr->member;
+	struct ident *address_space;
 	unsigned int mod;
-	int address_space;
 
 	if (!evaluate_expression(deref))
 		return NULL;
@@ -2037,7 +2079,7 @@
 	mod = ctype->ctype.modifiers;
 	if (ctype->type == SYM_NODE) {
 		ctype = ctype->ctype.base_type;
-		address_space |= ctype->ctype.as;
+		combine_address_space(deref->pos, &address_space, ctype->ctype.as);
 		mod |= ctype->ctype.modifiers;
 	}
 	if (!ctype || (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION)) {
@@ -2174,10 +2216,10 @@
 		size = bits_in_char;
 	}
 
-	if (size == 1 && is_bool_type(type)) {
+	if (is_bool_type(type)) {
 		if (Wsizeof_bool)
-			warning(expr->pos, "expression using sizeof bool");
-		size = bits_in_char;
+			warning(expr->pos, "expression using sizeof _Bool");
+		size = bits_to_bytes(bits_in_bool) * bits_in_char;
 	}
 
 	if (is_function(type->ctype.base_type)) {
@@ -2186,6 +2228,38 @@
 		size = bits_in_char;
 	}
 
+	if (is_array_type(type) && size < 0) {	// VLA, 1-dimension only
+		struct expression *base, *size;
+		struct symbol *base_type;
+
+		if (type->type == SYM_NODE)
+			type = type->ctype.base_type;	// strip the SYM_NODE
+		base_type = get_base_type(type);
+		if (!base_type)
+			goto error;
+		if (base_type->bit_size <= 0) {
+			base = alloc_expression(expr->pos, EXPR_SIZEOF);
+			base->cast_type = base_type;
+			if (!evaluate_sizeof(base))
+				goto error;
+		} else {
+			base = alloc_expression(expr->pos, EXPR_VALUE);
+			base->value = bits_to_bytes(base_type->bit_size);
+			base->ctype = size_t_ctype;
+		}
+		size = alloc_expression(expr->pos, EXPR_CAST);
+		size->cast_type = size_t_ctype;
+		size->cast_expression = type->array_size;
+		if (!evaluate_expression(size))
+			goto error;
+		expr->left = size;
+		expr->right = base;
+		expr->type = EXPR_BINOP;
+		expr->op = '*';
+		return expr->ctype = size_t_ctype;
+	}
+
+error:
 	if ((size < 0) || (size & (bits_in_char - 1)))
 		expression_error(expr, "cannot size expression");
 
@@ -2847,13 +2921,13 @@
 
 static struct symbol *evaluate_cast(struct expression *expr)
 {
-	struct expression *target = expr->cast_expression;
+	struct expression *source = expr->cast_expression;
 	struct symbol *ctype;
-	struct symbol *t1, *t2;
-	int class1, class2;
-	int as1 = 0, as2 = 0;
+	struct symbol *ttype, *stype;
+	int tclass, sclass;
+	struct ident *tas = NULL, *sas = NULL;
 
-	if (!target)
+	if (!source)
 		return NULL;
 
 	/*
@@ -2866,11 +2940,11 @@
 	 * dereferenced as part of a post-fix expression.
 	 * We need to produce an expression that can be dereferenced.
 	 */
-	if (target->type == EXPR_INITIALIZER) {
+	if (source->type == EXPR_INITIALIZER) {
 		struct symbol *sym = expr->cast_type;
 		struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
 
-		sym->initializer = target;
+		sym->initializer = source;
 		evaluate_symbol(sym);
 
 		addr->ctype = &lazy_ptr_ctype;	/* Lazy eval */
@@ -2890,12 +2964,12 @@
 	expr->ctype = ctype;
 	expr->cast_type = ctype;
 
-	evaluate_expression(target);
-	degenerate(target);
+	evaluate_expression(source);
+	degenerate(source);
 
-	class1 = classify_type(ctype, &t1);
+	tclass = classify_type(ctype, &ttype);
 
-	expr->flags = cast_flags(expr, target);
+	expr->flags = cast_flags(expr, source);
 
 	/*
 	 * You can always throw a value away by casting to
@@ -2902,72 +2976,72 @@
 	 * "void" - that's an implicit "force". Note that
 	 * the same is _not_ true of "void *".
 	 */
-	if (t1 == &void_ctype)
+	if (ttype == &void_ctype)
 		goto out;
 
-	if (class1 & (TYPE_COMPOUND | TYPE_FN))
-		warning(expr->pos, "cast to non-scalar");
-
-	t2 = target->ctype;
-	if (!t2) {
+	stype = source->ctype;
+	if (!stype) {
 		expression_error(expr, "cast from unknown type");
 		goto out;
 	}
-	class2 = classify_type(t2, &t2);
+	sclass = classify_type(stype, &stype);
 
-	if (class2 & TYPE_COMPOUND)
-		warning(expr->pos, "cast from non-scalar");
-
 	if (expr->type == EXPR_FORCE_CAST)
 		goto out;
 
+	if (tclass & (TYPE_COMPOUND | TYPE_FN))
+		warning(expr->pos, "cast to non-scalar");
+
+	if (sclass & TYPE_COMPOUND)
+		warning(expr->pos, "cast from non-scalar");
+
 	/* allowed cast unfouls */
-	if (class2 & TYPE_FOULED)
-		t2 = unfoul(t2);
+	if (sclass & TYPE_FOULED)
+		stype = unfoul(stype);
 
-	if (t1 != t2) {
-		if ((class1 & TYPE_RESTRICT) && restricted_value(target, t1))
+	if (ttype != stype) {
+		if ((tclass & TYPE_RESTRICT) && restricted_value(source, ttype))
 			warning(expr->pos, "cast to %s",
-				show_typename(t1));
-		if (class2 & TYPE_RESTRICT) {
-			if (t1 == &bool_ctype) {
-				if (class2 & TYPE_FOULED)
+				show_typename(ttype));
+		if (sclass & TYPE_RESTRICT) {
+			if (ttype == &bool_ctype) {
+				if (sclass & TYPE_FOULED)
 					warning(expr->pos, "%s degrades to integer",
-						show_typename(t2));
+						show_typename(stype));
 			} else {
 				warning(expr->pos, "cast from %s",
-					show_typename(t2));
+					show_typename(stype));
 			}
 		}
 	}
 
-	if (t1 == &ulong_ctype)
-		as1 = -1;
-	else if (class1 == TYPE_PTR) {
-		examine_pointer_target(t1);
-		as1 = t1->ctype.as;
+	if ((ttype == &ulong_ctype || ttype == uintptr_ctype) && !Wcast_from_as)
+		tas = &bad_address_space;
+	else if (tclass == TYPE_PTR) {
+		examine_pointer_target(ttype);
+		tas = ttype->ctype.as;
 	}
 
-	if (t2 == &ulong_ctype)
-		as2 = -1;
-	else if (class2 == TYPE_PTR) {
-		examine_pointer_target(t2);
-		as2 = t2->ctype.as;
+	if ((stype == &ulong_ctype || stype == uintptr_ctype))
+		sas = &bad_address_space;
+	else if (sclass == TYPE_PTR) {
+		examine_pointer_target(stype);
+		sas = stype->ctype.as;
 	}
 
-	if (!as1 && as2 > 0)
-		warning(expr->pos, "cast removes address space of expression");
-	if (as1 > 0 && as2 > 0 && as1 != as2)
-		warning(expr->pos, "cast between address spaces (<asn:%d>-><asn:%d>)", as2, as1);
-	if (as1 > 0 && !as2 &&
-	    !is_null_pointer_constant(target) && Wcast_to_as)
+	if (!tas && valid_as(sas))
+		warning(expr->pos, "cast removes address space '%s' of expression", show_as(sas));
+	if (valid_as(tas) && valid_as(sas) && tas != sas)
+		warning(expr->pos, "cast between address spaces (%s -> %s)", show_as(sas), show_as(tas));
+	if (valid_as(tas) && !sas &&
+	    !is_null_pointer_constant(source) && Wcast_to_as)
 		warning(expr->pos,
-			"cast adds address space to expression (<asn:%d>)", as1);
+			"cast adds address space '%s' to expression", show_as(tas));
 
-	if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR &&
-	    !as1 && (target->flags & CEF_ICE)) {
-		if (t1->ctype.base_type == &void_ctype) {
-			if (is_zero_constant(target)) {
+	if (!(ttype->ctype.modifiers & MOD_PTRINHERIT) && tclass == TYPE_PTR &&
+	    !tas && (source->flags & CEF_ICE)) {
+		if (ttype->ctype.base_type == &void_ctype) {
+			if (is_zero_constant(source)) {
 				/* NULL */
 				expr->type = EXPR_VALUE;
 				expr->ctype = &null_ctype;
@@ -2977,9 +3051,28 @@
 		}
 	}
 
-	if (t1 == &bool_ctype)
+	if (ttype == &bool_ctype)
 		cast_to_bool(expr);
 
+	// checks pointers to restricted
+	while (Wbitwise_pointer && tclass == TYPE_PTR && sclass == TYPE_PTR) {
+		tclass = classify_type(ttype->ctype.base_type, &ttype);
+		sclass = classify_type(stype->ctype.base_type, &stype);
+		if (ttype == stype)
+			break;
+		if (!ttype || !stype)
+			break;
+		if (ttype == &void_ctype || stype == &void_ctype)
+			break;
+		if (tclass & TYPE_RESTRICT) {
+			warning(expr->pos, "cast to %s", show_typename(ctype));
+			break;
+		}
+		if (sclass & TYPE_RESTRICT) {
+			warning(expr->pos, "cast from %s", show_typename(source->ctype));
+			break;
+		}
+	}
 out:
 	return ctype;
 }
@@ -3183,10 +3276,10 @@
 	case EXPR_SYMBOL:
 		return evaluate_symbol_expression(expr);
 	case EXPR_BINOP:
-		if (!evaluate_expression(expr->left))
+		evaluate_expression(expr->left);
+		evaluate_expression(expr->right);
+		if (!valid_subexpr_type(expr))
 			return NULL;
-		if (!evaluate_expression(expr->right))
-			return NULL;
 		return evaluate_binop(expr);
 	case EXPR_LOGICAL:
 		return evaluate_logical(expr);
@@ -3196,16 +3289,16 @@
 			return NULL;
 		return evaluate_comma(expr);
 	case EXPR_COMPARE:
-		if (!evaluate_expression(expr->left))
+		evaluate_expression(expr->left);
+		evaluate_expression(expr->right);
+		if (!valid_subexpr_type(expr))
 			return NULL;
-		if (!evaluate_expression(expr->right))
-			return NULL;
 		return evaluate_compare(expr);
 	case EXPR_ASSIGNMENT:
-		if (!evaluate_expression(expr->left))
+		evaluate_expression(expr->left);
+		evaluate_expression(expr->right);
+		if (!valid_subexpr_type(expr))
 			return NULL;
-		if (!evaluate_expression(expr->right))
-			return NULL;
 		return evaluate_assignment(expr);
 	case EXPR_PREOP:
 		if (!evaluate_expression(expr->unop))
@@ -3260,11 +3353,14 @@
 	case EXPR_SLICE:
 		expression_error(expr, "internal front-end error: SLICE re-evaluated");
 		return NULL;
+	case EXPR_ASM_OPERAND:
+		expression_error(expr, "internal front-end error: ASM_OPERAND evaluated");
+		return NULL;
 	}
 	return NULL;
 }
 
-static void check_duplicates(struct symbol *sym)
+void check_duplicates(struct symbol *sym)
 {
 	int declared = 0;
 	struct symbol *next = sym;
@@ -3291,7 +3387,7 @@
 	}
 	if (!declared) {
 		unsigned long mod = sym->ctype.modifiers;
-		if (mod & (MOD_STATIC | MOD_REGISTER))
+		if (mod & (MOD_STATIC | MOD_REGISTER | MOD_EXT_VISIBLE))
 			return;
 		if (!(mod & MOD_TOPLEVEL))
 			return;
@@ -3422,8 +3518,8 @@
 static void evaluate_asm_statement(struct statement *stmt)
 {
 	struct expression *expr;
+	struct expression *op;
 	struct symbol *sym;
-	int state;
 
 	expr = stmt->asm_string;
 	if (!expr || expr->type != EXPR_STRING) {
@@ -3431,58 +3527,41 @@
 		return;
 	}
 
-	state = 0;
-	FOR_EACH_PTR(stmt->asm_outputs, expr) {
-		switch (state) {
-		case 0: /* Identifier */
-			state = 1;
-			continue;
+	FOR_EACH_PTR(stmt->asm_outputs, op) {
+		/* Identifier */
 
-		case 1: /* Constraint */
-			state = 2;
-			if (!expr || expr->type != EXPR_STRING) {
-				sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string");
-				*THIS_ADDRESS(expr) = NULL;
-				continue;
-			}
+		/* Constraint */
+		expr = op->constraint;
+		if (!expr || expr->type != EXPR_STRING) {
+			sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string");
+			op->constraint = NULL;
+		} else
 			verify_output_constraint(expr, expr->string->data);
-			continue;
 
-		case 2: /* Expression */
-			state = 0;
-			if (!evaluate_expression(expr))
-				return;
-			if (!lvalue_expression(expr))
-				warning(expr->pos, "asm output is not an lvalue");
-			evaluate_assign_to(expr, expr->ctype);
-			continue;
-		}
-	} END_FOR_EACH_PTR(expr);
+		/* Expression */
+		expr = op->expr;
+		if (!evaluate_expression(expr))
+			return;
+		if (!lvalue_expression(expr))
+			warning(expr->pos, "asm output is not an lvalue");
+		evaluate_assign_to(expr, expr->ctype);
+	} END_FOR_EACH_PTR(op);
 
-	state = 0;
-	FOR_EACH_PTR(stmt->asm_inputs, expr) {
-		switch (state) {
-		case 0: /* Identifier */
-			state = 1;
-			continue;
+	FOR_EACH_PTR(stmt->asm_inputs, op) {
+		/* Identifier */
 
-		case 1:	/* Constraint */
-			state = 2;
-			if (!expr || expr->type != EXPR_STRING) {
-				sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string");
-				*THIS_ADDRESS(expr) = NULL;
-				continue;
-			}
+		/* Constraint */
+		expr = op->constraint;
+		if (!expr || expr->type != EXPR_STRING) {
+			sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string");
+			op->constraint = NULL;
+		} else
 			verify_input_constraint(expr, expr->string->data);
-			continue;
 
-		case 2: /* Expression */
-			state = 0;
-			if (!evaluate_expression(expr))
-				return;
-			continue;
-		}
-	} END_FOR_EACH_PTR(expr);
+		/* Expression */
+		if (!evaluate_expression(op->expr))
+			return;
+	} END_FOR_EACH_PTR(op);
 
 	FOR_EACH_PTR(stmt->asm_clobbers, expr) {
 		if (!expr) {
@@ -3582,7 +3661,7 @@
 {
 	struct symbol *label = stmt->goto_label;
 
-	if (label && !label->stmt && !lookup_keyword(label->ident, NS_KEYWORD))
+	if (label && !label->stmt && label->ident && !lookup_keyword(label->ident, NS_KEYWORD))
 		sparse_error(stmt->pos, "label '%s' was not declared", show_ident(label->ident));
 
 	evaluate_expression(stmt->goto_expression);
--- /dev/null	Mon Nov 18 13:18:52 2019
+++ new/usr/src/tools/smatch/src/evaluate.h	Mon Nov 18 13:18:52 2019
@@ -0,0 +1,28 @@
+#ifndef EVALUATE_H
+#define EVALUATE_H
+
+struct expression;
+struct statement;
+struct symbol;
+struct symbol_list;
+
+///
+// evaluate the type of an expression
+// @expr: the expression to be evaluated
+// @return: the type of the expression or ``NULL``
+//	if the expression can't be evaluated
+struct symbol *evaluate_expression(struct expression *expr);
+
+///
+// evaluate the type of a statement
+// @stmt: the statement to be evaluated
+// @return: the type of the statement or ``NULL``
+//	if it can't be evaluated
+struct symbol *evaluate_statement(struct statement *stmt);
+
+///
+// evaluate the type of a set of symbols
+// @list: the list of the symbol to be evaluated
+void evaluate_symbol_list(struct symbol_list *list);
+
+#endif
--- old/usr/src/tools/smatch/src/example.c	Mon Nov 18 13:18:53 2019
+++ new/usr/src/tools/smatch/src/example.c	Mon Nov 18 13:18:53 2019
@@ -25,15 +25,12 @@
 	[OP_BR] = "br",
 	[OP_CBR] = "cbr",
 	[OP_SWITCH] = "switch",
-	[OP_INVOKE] = "invoke",
 	[OP_COMPUTEDGOTO] = "jmp *",
-	[OP_UNWIND] = "unwind",
 	
 	/* Binary */
 	[OP_ADD] = "add",
 	[OP_SUB] = "sub",
-	[OP_MULU] = "mulu",
-	[OP_MULS] = "muls",
+	[OP_MUL] = "mul",
 	[OP_DIVU] = "divu",
 	[OP_DIVS] = "divs",
 	[OP_MODU] = "modu",
@@ -46,8 +43,6 @@
 	[OP_AND] = "and",
 	[OP_OR] = "or",
 	[OP_XOR] = "xor",
-	[OP_AND_BOOL] = "and-bool",
-	[OP_OR_BOOL] = "or-bool",
 
 	/* Binary comparison */
 	[OP_SET_EQ] = "seteq",
@@ -69,28 +64,27 @@
 	[OP_SEL] = "select",
 	
 	/* Memory */
-	[OP_MALLOC] = "malloc",
-	[OP_FREE] = "free",
-	[OP_ALLOCA] = "alloca",
 	[OP_LOAD] = "load",
 	[OP_STORE] = "store",
 	[OP_SETVAL] = "set",
-	[OP_GET_ELEMENT_PTR] = "getelem",
 
 	/* Other */
 	[OP_PHI] = "phi",
 	[OP_PHISOURCE] = "phisrc",
 	[OP_COPY] = "copy",
-	[OP_CAST] = "cast",
-	[OP_SCAST] = "scast",
-	[OP_FPCAST] = "fpcast",
+	[OP_SEXT] = "sext",
+	[OP_ZEXT] = "zext",
+	[OP_TRUNC] = "trunc",
+	[OP_FCVTU] = "fcvtu",
+	[OP_FCVTS] = "fcvts",
+	[OP_UCVTF] = "ucvtf",
+	[OP_SCVTF] = "scvtf",
+	[OP_FCVTF] = "fcvtf",
+	[OP_UTPTR] = "utptr",
+	[OP_PTRTU] = "utptr",
 	[OP_PTRCAST] = "ptrcast",
 	[OP_CALL] = "call",
-	[OP_VANEXT] = "va_next",
-	[OP_VAARG] = "va_arg",
 	[OP_SLICE] = "slice",
-	[OP_SNOP] = "snop",
-	[OP_LNOP] = "lnop",
 	[OP_NOP] = "nop",
 	[OP_DEATHNOTE] = "dead",
 	[OP_ASM] = "asm",
@@ -394,7 +388,7 @@
 		return;
 	reg->dead = 0;
 	reg->used = 1;
-	FOR_EACH_PTR(reg->contains, pseudo) {
+	FOR_EACH_PTR_TAG(reg->contains, pseudo) {
 		if (CURRENT_TAG(pseudo) & TAG_DEAD)
 			continue;
 		if (!(CURRENT_TAG(pseudo) & TAG_DIRTY))
@@ -447,7 +441,7 @@
 {
 	pseudo_t p;
 
-	FOR_EACH_PTR(reg->contains, p) {
+	FOR_EACH_PTR_TAG(reg->contains, p) {
 		if (p != pseudo)
 			continue;
 		if (CURRENT_TAG(p) & TAG_DEAD)
@@ -532,7 +526,7 @@
 		pseudo_t p;
 
 		reg = hardregs + i;
-		FOR_EACH_PTR(reg->contains, p) {
+		FOR_EACH_PTR_TAG(reg->contains, p) {
 			if (p == pseudo) {
 				last_reg = i;
 				output_comment(state, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo), reg->name, reg->busy);
@@ -872,7 +866,7 @@
 	if (reg->dead) {
 		pseudo_t p;
 		
-		FOR_EACH_PTR(reg->contains, p) {
+		FOR_EACH_PTR_TAG(reg->contains, p) {
 			if (CURRENT_TAG(p) & TAG_DEAD) {
 				DELETE_CURRENT_PTR(p);
 				reg->dead--;
@@ -912,7 +906,7 @@
 static int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
 {
 	pseudo_t p;
-	FOR_EACH_PTR(reg->contains, p) {
+	FOR_EACH_PTR_TAG(reg->contains, p) {
 		if (p == pseudo)
 			return CURRENT_TAG(p) & TAG_DEAD;
 	} END_FOR_EACH_PTR(p);
@@ -1007,7 +1001,7 @@
 		pseudo_t p;
 
 		reg = hardregs + i;
-		FOR_EACH_PTR(reg->contains, p) {
+		FOR_EACH_PTR_TAG(reg->contains, p) {
 			if (p != pseudo)
 				continue;
 			if (CURRENT_TAG(p) & TAG_DEAD)
@@ -1404,9 +1398,8 @@
 		generate_copy(state, insn);
 		break;
 
-	case OP_ADD: case OP_MULU: case OP_MULS:
+	case OP_ADD: case OP_MUL:
 	case OP_AND: case OP_OR: case OP_XOR:
-	case OP_AND_BOOL: case OP_OR_BOOL:
 		generate_commutative_binop(state, insn);
 		break;
 
@@ -1420,7 +1413,14 @@
 		generate_compare(state, insn);
 		break;
 
-	case OP_CAST: case OP_SCAST: case OP_FPCAST: case OP_PTRCAST:
+	case OP_SEXT: case OP_ZEXT:
+	case OP_TRUNC:
+	case OP_PTRCAST:
+	case OP_UTPTR:
+	case OP_PTRTU:
+	case OP_FCVTU: case OP_FCVTS:
+	case OP_UCVTF: case OP_SCVTF:
+	case OP_FCVTF:
 		generate_cast(state, insn);
 		break;
 
@@ -1544,7 +1544,7 @@
 		struct hardreg *reg = hardregs + i;
 		pseudo_t p;
 
-		FOR_EACH_PTR(reg->contains, p) {
+		FOR_EACH_PTR_TAG(reg->contains, p) {
 			if (p == pseudo) {
 				write_reg_to_storage(state, reg, pseudo, out);
 				return;
@@ -1652,7 +1652,7 @@
 			int flushme = 0;
 
 			reg->busy = REG_FIXED;
-			FOR_EACH_PTR(reg->contains, p) {
+			FOR_EACH_PTR_TAG(reg->contains, p) {
 				if (p == entry->pseudo) {
 					flushme = -100;
 					continue;
@@ -1949,9 +1949,9 @@
 
 	compile(sparse_initialize(argc, argv, &filelist));
 	dbg_dead = 1;
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		compile(sparse(file));
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 	return 0;
 }
 
--- old/usr/src/tools/smatch/src/expand.c	Mon Nov 18 13:18:53 2019
+++ new/usr/src/tools/smatch/src/expand.c	Mon Nov 18 13:18:53 2019
@@ -41,11 +41,17 @@
 #include "symbol.h"
 #include "target.h"
 #include "expression.h"
+#include "evaluate.h"
 #include "expand.h"
 
 
 static int expand_expression(struct expression *);
 static int expand_statement(struct statement *);
+
+// If set, don't issue a warning on divide-by-0, invalid shift, ...
+// and don't mark the expression as erroneous but leave it as-is.
+// This allows testing some characteristics of the expression
+// without creating any side-effects (e.g.: is_zero_constant()).
 static int conservative;
 
 static int expand_symbol_expression(struct expression *expr)
@@ -157,13 +163,35 @@
 	expr->type = EXPR_FVALUE;
 }
 
-static int check_shift_count(struct expression *expr, struct symbol *ctype, unsigned int count)
+static void warn_shift_count(struct expression *expr, struct symbol *ctype, long long count)
 {
-	warning(expr->pos, "shift too big (%u) for type %s", count, show_typename(ctype));
-	count &= ctype->bit_size-1;
-	return count;
+	if (count < 0) {
+		if (!Wshift_count_negative)
+			return;
+		warning(expr->pos, "shift count is negative (%lld)", count);
+		return;
+	}
+	if (ctype->type == SYM_NODE)
+		ctype = ctype->ctype.base_type;
+
+	if (!Wshift_count_overflow)
+		return;
+	warning(expr->pos, "shift too big (%llu) for type %s", count, show_typename(ctype));
 }
 
+/* Return true if constant shift size is valid */
+static bool check_shift_count(struct expression *expr, struct expression *right)
+{
+	struct symbol *ctype = expr->ctype;
+	long long count = get_longlong(right);
+
+	if (count >= 0 && count < ctype->bit_size)
+		return true;
+	if (!conservative)
+		warn_shift_count(expr, ctype, count);
+	return false;
+}
+
 /*
  * CAREFUL! We need to get the size and sign of the
  * result right!
@@ -182,12 +210,8 @@
 		return 0;
 	r = right->value;
 	if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
-		if (r >= ctype->bit_size) {
-			if (conservative)
-				return 0;
-			r = check_shift_count(expr, ctype, r);
-			right->value = r;
-		}
+		if (!check_shift_count(expr, right))
+			return 0;
 	}
 	if (left->type != EXPR_VALUE)
 		return 0;
@@ -478,7 +502,7 @@
 	return cost;
 }
 
-#define MOD_IGN (MOD_VOLATILE | MOD_CONST)
+#define MOD_IGN (MOD_QUALIFIER)
 
 static int compare_types(int op, struct symbol *left, struct symbol *right)
 {
@@ -529,8 +553,8 @@
 static int expand_conditional(struct expression *expr)
 {
 	struct expression *cond = expr->conditional;
-	struct expression *true = expr->cond_true;
-	struct expression *false = expr->cond_false;
+	struct expression *valt = expr->cond_true;
+	struct expression *valf = expr->cond_false;
 	int cost, cond_cost;
 
 	cond_cost = expand_expression(cond);
@@ -537,11 +561,11 @@
 	if (cond->type == EXPR_VALUE) {
 		unsigned flags = expr->flags;
 		if (!cond->value)
-			true = false;
-		if (!true)
-			true = cond;
-		cost = expand_expression(true);
-		*expr = *true;
+			valt = valf;
+		if (!valt)
+			valt = cond;
+		cost = expand_expression(valt);
+		*expr = *valt;
 		expr->flags = flags;
 		if (expr->type == EXPR_VALUE)
 			expr->taint |= cond->taint;
@@ -548,8 +572,8 @@
 		return cost;
 	}
 
-	cost = expand_expression(true);
-	cost += expand_expression(false);
+	cost = expand_expression(valt);
+	cost += expand_expression(valf);
 
 	if (cost < SELECT_COST) {
 		expr->type = EXPR_SELECT;
@@ -558,11 +582,30 @@
 
 	return cost + cond_cost + BRANCH_COST;
 }
-		
+
+static void check_assignment(struct expression *expr)
+{
+	struct expression *right;
+
+	switch (expr->op) {
+	case SPECIAL_SHL_ASSIGN:
+	case SPECIAL_SHR_ASSIGN:
+		right = expr->right;
+		if (right->type != EXPR_VALUE)
+			break;
+		check_shift_count(expr, right);
+		break;
+	}
+	return;
+}
+
 static int expand_assignment(struct expression *expr)
 {
 	expand_expression(expr->left);
 	expand_expression(expr->right);
+
+	if (!conservative)
+		check_assignment(expr);
 	return SIDE_EFFECTS;
 }
 
@@ -582,7 +625,7 @@
 {
 	struct expression *value;
 
-	if (sym->ctype.modifiers & (MOD_ASSIGNED | MOD_ADDRESSABLE))
+	if (sym->ctype.modifiers & MOD_ACCESS)
 		return NULL;
 	value = sym->initializer;
 	if (!value)
@@ -644,6 +687,8 @@
 		if (value) {
 			/* FIXME! We should check that the size is right! */
 			if (value->type == EXPR_VALUE) {
+				if (is_bitfield_type(value->ctype))
+					return UNSAFE;
 				expr->type = EXPR_VALUE;
 				expr->value = value->value;
 				expr->taint = 0;
@@ -788,6 +833,8 @@
 	struct expression *fn = expr->fn;
 	struct symbol *ctype = fn->ctype;
 
+	expand_expression(fn);
+
 	if (fn->type != EXPR_PREOP)
 		return SIDE_EFFECTS;
 
@@ -1048,6 +1095,9 @@
 	case EXPR_OFFSETOF:
 		expression_error(expr, "internal front-end error: sizeof in expansion?");
 		return UNSAFE;
+	case EXPR_ASM_OPERAND:
+		expression_error(expr, "internal front-end error: ASM_OPERAND in expansion?");
+		return UNSAFE;
 	}
 	return SIDE_EFFECTS;
 }
@@ -1248,10 +1298,12 @@
 			expression_error(expr, "bad constant expression");
 		return 0;
 	}
+#if 0	// This complains about "1 ? 1 :__bits_per()" which the kernel use
 	if ((strict == 1) && bad_integer_constant_expression(expr)) {
 		expression_error(expr, "bad integer constant expression");
 		return 0;
 	}
+#endif
 
 	value = expr->value;
 	mask = 1ULL << (ctype->bit_size-1);
--- old/usr/src/tools/smatch/src/expression.c	Mon Nov 18 13:18:54 2019
+++ new/usr/src/tools/smatch/src/expression.c	Mon Nov 18 13:18:54 2019
@@ -62,7 +62,10 @@
 
 struct token *parens_expression(struct token *token, struct expression **expr, const char *where)
 {
+	struct token *p;
+
 	token = expect(token, '(', where);
+	p = token;
 	if (match_op(token, '{')) {
 		struct expression *e = alloc_expression(token->pos, EXPR_STATEMENT);
 		struct statement *stmt = alloc_statement(token->pos, STMT_COMPOUND);
@@ -74,6 +77,9 @@
 		token = expect(token, '}', "at end of statement expression");
 	} else
 		token = parse_expression(token, expr);
+
+	if (token == p)
+		sparse_error(token->pos, "an expression is expected before ')'");
 	return expect(token, ')', where);
 }
 
--- old/usr/src/tools/smatch/src/expression.h	Mon Nov 18 13:18:54 2019
+++ new/usr/src/tools/smatch/src/expression.h	Mon Nov 18 13:18:54 2019
@@ -64,6 +64,7 @@
 	EXPR_FVALUE,
 	EXPR_SLICE,
 	EXPR_OFFSETOF,
+	EXPR_ASM_OPERAND,
 };
 
 
@@ -194,7 +195,8 @@
 			struct expression *base;
 			unsigned r_bitpos, r_nrbits;
 		};
-		// EXPR_CAST and EXPR_SIZEOF
+		// EXPR_CAST, EXPR_FORCE_CAST, EXPR_IMPLIED_CAST,
+		// EXPR_SIZEOF, EXPR_ALIGNOF and EXPR_PTRSIZEOF
 		struct /* cast_arg */ {
 			struct symbol *cast_type;
 			struct expression *cast_expression;
@@ -241,12 +243,32 @@
 				struct expression *index;
 			};
 		};
+		// EXPR_ASM_OPERAND
+		struct {
+			struct ident *name;
+			struct expression *constraint;
+			struct expression *expr;
+		};
 	};
 };
 
-/* Constant expression values */
-int is_zero_constant(struct expression *);
+///
+// Constant expression values
+// --------------------------
+
+///
+// test if an expression evaluates to the constant ``0``.
+// @return: ``1`` if @expr evaluate to ``0``,
+//	``0`` otherwise.
+int is_zero_constant(struct expression *expr);
+
+///
+// test the compile time truth value of an expression
+// @return:
+//	* ``-1`` if @expr is not constant,
+//	* ``0`` or ``1`` depending on the truth value of @expr.
 int expr_truth_value(struct expression *expr);
+
 long long get_expression_value(struct expression *);
 long long const_expression_value(struct expression *);
 long long get_expression_value_silent(struct expression *expr);
--- old/usr/src/tools/smatch/src/flow.c	Mon Nov 18 13:18:54 2019
+++ new/usr/src/tools/smatch/src/flow.c	Mon Nov 18 13:18:55 2019
@@ -131,7 +131,7 @@
 		struct basic_block *source, *target;
 		pseudo_t pseudo;
 		struct instruction *br;
-		int true;
+		int cond;
 
 		if (!def)
 			continue;
@@ -144,10 +144,10 @@
 			continue;
 		if (br->opcode != OP_CBR && br->opcode != OP_BR)
 			continue;
-		true = pseudo_truth_value(pseudo);
-		if (true < 0)
+		cond = pseudo_truth_value(pseudo);
+		if (cond < 0)
 			continue;
-		target = true ? second->bb_true : second->bb_false;
+		target = cond ? second->bb_true : second->bb_false;
 		if (bb_depends_on(target, bb))
 			continue;
 		if (bb_depends_on_phi(target, bb))
@@ -164,11 +164,20 @@
 {
 	struct instruction *insn;
 	FOR_EACH_PTR(bb->insns, insn) {
+		if (!insn->bb)
+			continue;
 		switch (insn->opcode) {
 		case OP_CALL:
 			/* FIXME! This should take "const" etc into account */
 			return 1;
 
+		case OP_LOAD:
+			if (!insn->type)
+				return 1;
+			if (insn->is_volatile)
+				return 1;
+			continue;
+
 		case OP_STORE:
 		case OP_CONTEXT:
 			return 1;
@@ -200,7 +209,7 @@
 }
 
 static int simplify_branch_branch(struct basic_block *bb, struct instruction *br,
-	struct basic_block **target_p, int true)
+	struct basic_block **target_p, int bb_true)
 {
 	struct basic_block *target = *target_p, *final;
 	struct instruction *insn;
@@ -216,7 +225,7 @@
 	 * Now we just need to see if we can rewrite the branch..
 	 */
 	retval = 0;
-	final = true ? insn->bb_true : insn->bb_false;
+	final = bb_true ? insn->bb_true : insn->bb_false;
 	if (bb_has_side_effects(target))
 		goto try_to_rewrite_target;
 	if (bb_depends_on(final, target))
@@ -269,7 +278,7 @@
 
 static inline void concat_user_list(struct pseudo_user_list *src, struct pseudo_user_list **dst)
 {
-	concat_ptr_list((struct ptr_list *)src, (struct ptr_list **)dst);
+	copy_ptr_list((struct ptr_list **)dst, (struct ptr_list *)src);
 }
 
 void convert_instruction_target(struct instruction *insn, pseudo_t src)
@@ -296,9 +305,8 @@
 void convert_load_instruction(struct instruction *insn, pseudo_t src)
 {
 	convert_instruction_target(insn, src);
-	/* Turn the load into a no-op */
-	insn->opcode = OP_LNOP;
-	insn->bb = NULL;
+	kill_instruction(insn);
+	repeat_phase |= REPEAT_SYMBOL_CLEANUP;
 }
 
 static int overlapping_memop(struct instruction *a, struct instruction *b)
@@ -362,66 +370,6 @@
 	return 1;
 }
 
-static int phisrc_in_bb(struct pseudo_list *list, struct basic_block *bb)
-{
-	pseudo_t p;
-	FOR_EACH_PTR(list, p) {
-		if (p->def->bb == bb)
-			return 1;
-	} END_FOR_EACH_PTR(p);
-
-	return 0;
-}
-
-static int find_dominating_parents(pseudo_t pseudo, struct instruction *insn,
-	struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators,
-	int local)
-{
-	struct basic_block *parent;
-
-	if (!bb->parents)
-		return !!local;
-
-	FOR_EACH_PTR(bb->parents, parent) {
-		struct instruction *one;
-		struct instruction *br;
-		pseudo_t phi;
-
-		FOR_EACH_PTR_REVERSE(parent->insns, one) {
-			int dominance;
-			if (one == insn)
-				goto no_dominance;
-			dominance = dominates(pseudo, insn, one, local);
-			if (dominance < 0) {
-				if (one->opcode == OP_LOAD)
-					continue;
-				return 0;
-			}
-			if (!dominance)
-				continue;
-			goto found_dominator;
-		} END_FOR_EACH_PTR_REVERSE(one);
-no_dominance:
-		if (parent->generation == generation)
-			continue;
-		parent->generation = generation;
-
-		if (!find_dominating_parents(pseudo, insn, parent, generation, dominators, local))
-			return 0;
-		continue;
-
-found_dominator:
-		if (dominators && phisrc_in_bb(*dominators, parent))
-			continue;
-		br = delete_last_instruction(&parent->insns);
-		phi = alloc_phi(parent, one->target, one->size);
-		phi->ident = phi->ident ? : pseudo->ident;
-		add_instruction(&parent->insns, br);
-		use_pseudo(insn, phi, add_pseudo(dominators, phi));
-	} END_FOR_EACH_PTR(parent);
-	return 1;
-}		
-
 /*
  * We should probably sort the phi list just to make it easier to compare
  * later for equality. 
@@ -434,9 +382,9 @@
 	 * Check for somewhat common case of duplicate
 	 * phi nodes.
 	 */
-	new = first_pseudo(dominators)->def->src1;
+	new = first_pseudo(dominators)->def->phi_src;
 	FOR_EACH_PTR(dominators, phi) {
-		if (new != phi->def->src1)
+		if (new != phi->def->phi_src)
 			goto complex_phi;
 		new->ident = new->ident ? : phi->ident;
 	} END_FOR_EACH_PTR(phi);
@@ -446,11 +394,11 @@
 	 * and convert the load into a LNOP and replace the
 	 * pseudo.
 	 */
+	convert_load_instruction(insn, new);
 	FOR_EACH_PTR(dominators, phi) {
 		kill_instruction(phi->def);
 	} END_FOR_EACH_PTR(phi);
-	convert_load_instruction(insn, new);
-	return;
+	goto end;
 
 complex_phi:
 	/* We leave symbol pseudos with a bogus usage list here */
@@ -458,90 +406,27 @@
 		kill_use(&insn->src);
 	insn->opcode = OP_PHI;
 	insn->phi_list = dominators;
-}
 
-static int find_dominating_stores(pseudo_t pseudo, struct instruction *insn,
-	unsigned long generation, int local)
-{
-	struct basic_block *bb = insn->bb;
-	struct instruction *one, *dom = NULL;
-	struct pseudo_list *dominators;
-	int partial;
-
-	/* Unreachable load? Undo it */
-	if (!bb) {
-		insn->opcode = OP_LNOP;
-		return 1;
-	}
-
-	partial = 0;
-	FOR_EACH_PTR(bb->insns, one) {
-		int dominance;
-		if (one == insn)
-			goto found;
-		dominance = dominates(pseudo, insn, one, local);
-		if (dominance < 0) {
-			/* Ignore partial load dominators */
-			if (one->opcode == OP_LOAD)
-				continue;
-			dom = NULL;
-			partial = 1;
-			continue;
-		}
-		if (!dominance)
-			continue;
-		dom = one;
-		partial = 0;
-	} END_FOR_EACH_PTR(one);
-	/* Whaa? */
-	warning(pseudo->sym->pos, "unable to find symbol read");
-	return 0;
-found:
-	if (partial)
-		return 0;
-
-	if (dom) {
-		convert_load_instruction(insn, dom->target);
-		return 1;
-	}
-
-	/* OK, go find the parents */
-	bb->generation = generation;
-
-	dominators = NULL;
-	if (!find_dominating_parents(pseudo, insn, bb, generation, &dominators, local))
-		return 0;
-
-	/* This happens with initial assignments to structures etc.. */
-	if (!dominators) {
-		if (!local)
-			return 0;
-		check_access(insn);
-		convert_load_instruction(insn, value_pseudo(insn->type, 0));
-		return 1;
-	}
-
-	/*
-	 * If we find just one dominating instruction, we
-	 * can turn it into a direct thing. Otherwise we'll
-	 * have to turn the load into a phi-node of the
-	 * dominators.
-	 */
-	rewrite_load_instruction(insn, dominators);
-	return 1;
+end:
+	repeat_phase |= REPEAT_SYMBOL_CLEANUP;
 }
 
-static void kill_store(struct instruction *insn)
-{
-	if (insn) {
-		insn->bb = NULL;
-		insn->opcode = OP_SNOP;
-		kill_use(&insn->target);
-	}
-}
-
 /* Kill a pseudo that is dead on exit from the bb */
-static void kill_dead_stores(pseudo_t pseudo, unsigned long generation, struct basic_block *bb, int local)
+// The context is:
+// * the variable is not global but may have its address used (local/non-local)
+// * the stores are only needed by others functions which would do some
+//   loads via the escaped address
+// We start by the terminating BB (normal exit BB + no-return/unreachable)
+// We walkup the BB' intruction backward
+// * we're only concerned by loads, stores & calls
+// * if we reach a call			-> we have to stop if var is non-local
+// * if we reach a load of our var	-> we have to stop
+// * if we reach a store of our var	-> we can kill it, it's dead
+// * we can ignore other stores & loads if the var is local
+// * if we reach another store or load done via non-symbol access
+//   (so done via some address calculation) -> we have to stop
+// If we reach the top of the BB we can recurse into the parents BBs.
+static void kill_dead_stores_bb(pseudo_t pseudo, unsigned long generation, struct basic_block *bb, int local)
 {
 	struct instruction *insn;
 	struct basic_block *parent;
@@ -550,85 +435,33 @@
 		return;
 	bb->generation = generation;
 	FOR_EACH_PTR_REVERSE(bb->insns, insn) {
-		int opcode = insn->opcode;
-
-		if (opcode != OP_LOAD && opcode != OP_STORE) {
-			if (local)
+		if (!insn->bb)
+			continue;
+		switch (insn->opcode) {
+		case OP_LOAD:
+			if (insn->src == pseudo)
+				return;
+			break;
+		case OP_STORE:
+			if (insn->src == pseudo) {
+				kill_instruction_force(insn);
 				continue;
-			if (opcode == OP_CALL)
+			}
+			break;
+		case OP_CALL:
+			if (!local)
 				return;
+		default:
 			continue;
 		}
-		if (insn->src == pseudo) {
-			if (opcode == OP_LOAD)
-				return;
-			kill_store(insn);
-			continue;
-		}
-		if (local)
-			continue;
-		if (insn->src->type != PSEUDO_SYM)
+		if (!local && insn->src->type != PSEUDO_SYM)
 			return;
 	} END_FOR_EACH_PTR_REVERSE(insn);
 
 	FOR_EACH_PTR(bb->parents, parent) {
-		struct basic_block *child;
-		FOR_EACH_PTR(parent->children, child) {
-			if (child && child != bb)
-				return;
-		} END_FOR_EACH_PTR(child);
-		kill_dead_stores(pseudo, generation, parent, local);
-	} END_FOR_EACH_PTR(parent);
-}
-
-/*
- * This should see if the "insn" trivially dominates some previous store, and kill the
- * store if unnecessary.
- */
-static void kill_dominated_stores(pseudo_t pseudo, struct instruction *insn, 
-	unsigned long generation, struct basic_block *bb, int local, int found)
-{
-	struct instruction *one;
-	struct basic_block *parent;
-
-	/* Unreachable store? Undo it */
-	if (!bb) {
-		kill_store(insn);
-		return;
-	}
-	if (bb->generation == generation)
-		return;
-	bb->generation = generation;
-	FOR_EACH_PTR_REVERSE(bb->insns, one) {
-		int dominance;
-		if (!found) {
-			if (one != insn)
-				continue;
-			found = 1;
+		if (bb_list_size(parent->children) > 1)
 			continue;
-		}
-		dominance = dominates(pseudo, insn, one, local);
-		if (!dominance)
-			continue;
-		if (dominance < 0)
-			return;
-		if (one->opcode == OP_LOAD)
-			return;
-		kill_store(one);
-	} END_FOR_EACH_PTR_REVERSE(one);
-
-	if (!found) {
-		warning(bb->pos, "Unable to find instruction");
-		return;
-	}
-
-	FOR_EACH_PTR(bb->parents, parent) {
-		struct basic_block *child;
-		FOR_EACH_PTR(parent->children, child) {
-			if (child && child != bb)
-				return;
-		} END_FOR_EACH_PTR(child);
-		kill_dominated_stores(pseudo, insn, generation, parent, local, found);
+		kill_dead_stores_bb(pseudo, generation, parent, local);
 	} END_FOR_EACH_PTR(parent);
 }
 
@@ -640,104 +473,56 @@
 		int offset = insn->offset, bit = bytes_to_bits(offset) + insn->size;
 		struct symbol *sym = pseudo->sym;
 
-		if (sym->bit_size > 0 && (offset < 0 || bit > sym->bit_size))
+		if (sym->bit_size > 0 && (offset < 0 || bit > sym->bit_size)) {
+			if (insn->tainted)
+				return;
 			warning(insn->pos, "invalid access %s '%s' (%d %d)",
 				offset < 0 ? "below" : "past the end of",
 				show_ident(sym->ident), offset,
 				bits_to_bytes(sym->bit_size));
+			insn->tainted = 1;
+		}
 	}
 }
 
-static void simplify_one_symbol(struct entrypoint *ep, struct symbol *sym)
+static struct pseudo_user *first_user(pseudo_t p)
 {
-	pseudo_t pseudo;
 	struct pseudo_user *pu;
-	unsigned long mod;
-	int all;
-
-	/* Never used as a symbol? */
-	pseudo = sym->pseudo;
-	if (!pseudo)
-		return;
-
-	/* We don't do coverage analysis of volatiles.. */
-	if (sym->ctype.modifiers & MOD_VOLATILE)
-		return;
-
-	/* ..and symbols with external visibility need more care */
-	mod = sym->ctype.modifiers & (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE);
-	if (mod)
-		goto external_visibility;
-
-	FOR_EACH_PTR(pseudo->users, pu) {
-		/* We know that the symbol-pseudo use is the "src" in the instruction */
-		struct instruction *insn = pu->insn;
-
-		switch (insn->opcode) {
-		case OP_STORE:
-			break;
-		case OP_LOAD:
-			break;
-		case OP_SYMADDR:
-			if (!insn->bb)
-				continue;
-			mod |= MOD_ADDRESSABLE;
-			goto external_visibility;
-		case OP_NOP:
-		case OP_SNOP:
-		case OP_LNOP:
-		case OP_PHI:
+	FOR_EACH_PTR(p->users, pu) {
+		if (!pu)
 			continue;
-		default:
-			warning(sym->pos, "symbol '%s' pseudo used in unexpected way", show_ident(sym->ident));
-		}
+		return pu;
 	} END_FOR_EACH_PTR(pu);
+	return NULL;
+}
 
-external_visibility:
-	all = 1;
-	FOR_EACH_PTR_REVERSE(pseudo->users, pu) {
-		struct instruction *insn = pu->insn;
-		if (insn->opcode == OP_LOAD)
-			all &= find_dominating_stores(pseudo, insn, ++bb_generation, !mod);
-	} END_FOR_EACH_PTR_REVERSE(pu);
+void kill_dead_stores(struct entrypoint *ep, pseudo_t addr, int local)
+{
+	unsigned long generation;
+	struct basic_block *bb;
 
-	/* If we converted all the loads, remove the stores. They are dead */
-	if (all && !mod) {
-		FOR_EACH_PTR(pseudo->users, pu) {
+	switch (pseudo_user_list_size(addr->users)) {
+	case 0:
+		return;
+	case 1:
+		if (local) {
+			struct pseudo_user *pu = first_user(addr);
 			struct instruction *insn = pu->insn;
-			if (insn->opcode == OP_STORE)
-				kill_store(insn);
-		} END_FOR_EACH_PTR(pu);
-	} else {
-		/*
-		 * If we couldn't take the shortcut, see if we can at least kill some
-		 * of them..
-		 */
-		FOR_EACH_PTR(pseudo->users, pu) {
-			struct instruction *insn = pu->insn;
-			if (insn->opcode == OP_STORE)
-				kill_dominated_stores(pseudo, insn, ++bb_generation, insn->bb, !mod, 0);
-		} END_FOR_EACH_PTR(pu);
-
-		if (!(mod & (MOD_NONLOCAL | MOD_STATIC))) {
-			struct basic_block *bb;
-			FOR_EACH_PTR(ep->bbs, bb) {
-				if (!bb->children)
-					kill_dead_stores(pseudo, ++bb_generation, bb, !mod);
-			} END_FOR_EACH_PTR(bb);
+			if (insn->opcode == OP_STORE) {
+				kill_instruction_force(insn);
+				return;
+			}
 		}
+	default:
+		break;
 	}
-			
-	return;
-}
 
-void simplify_symbol_usage(struct entrypoint *ep)
-{
-	pseudo_t pseudo;
-
-	FOR_EACH_PTR(ep->accesses, pseudo) {
-		simplify_one_symbol(ep, pseudo->sym);
-	} END_FOR_EACH_PTR(pseudo);
+	generation = ++bb_generation;
+	FOR_EACH_PTR(ep->bbs, bb) {
+		if (bb->children)
+			continue;
+		kill_dead_stores_bb(addr, generation, bb, local);
+	} END_FOR_EACH_PTR(bb);
 }
 
 static void mark_bb_reachable(struct basic_block *bb, unsigned long generation)
@@ -770,6 +555,8 @@
 	struct basic_block *child, *parent;
 
 	FOR_EACH_PTR(bb->insns, insn) {
+		if (!insn->bb)
+			continue;
 		kill_instruction_force(insn);
 		kill_defs(insn);
 		/*
@@ -844,13 +631,12 @@
 {
 	struct basic_block *parent;
 	struct basic_block *target = br->bb_true;
-	struct basic_block *false = br->bb_false;
 
 	if (br->opcode == OP_CBR) {
 		pseudo_t cond = br->cond;
 		if (cond->type != PSEUDO_VAL)
 			return NULL;
-		target = cond->value ? target : false;
+		target = cond->value ? target : br->bb_false;
 	}
 
 	/*
@@ -956,7 +742,8 @@
 			if (!first->bb)
 				continue;
 			switch (first->opcode) {
-			case OP_NOP: case OP_LNOP: case OP_SNOP:
+			case OP_NOP:
+			case OP_INLINED_CALL:
 				continue;
 			case OP_CBR:
 			case OP_BR: {
@@ -1002,7 +789,7 @@
 		/*
 		 * Merge the two.
 		 */
-		repeat_phase |= REPEAT_CSE;
+		repeat_phase |= REPEAT_CFG_CLEANUP;
 
 		parent->children = bb->children;
 		bb->children = NULL;
@@ -1014,10 +801,10 @@
 
 		kill_instruction(delete_last_instruction(&parent->insns));
 		FOR_EACH_PTR(bb->insns, insn) {
-			if (insn->bb) {
-				assert(insn->bb == bb);
-				insn->bb = parent;
-			}
+			if (!insn->bb)
+				continue;
+			assert(insn->bb == bb);
+			insn->bb = parent;
 			add_instruction(&parent->insns, insn);
 		} END_FOR_EACH_PTR(insn);
 		bb->insns = NULL;
--- old/usr/src/tools/smatch/src/flow.h	Mon Nov 18 13:18:55 2019
+++ new/usr/src/tools/smatch/src/flow.h	Mon Nov 18 13:18:55 2019
@@ -5,9 +5,9 @@
 
 extern unsigned long bb_generation;
 
-#define REPEAT_CSE		1
-#define REPEAT_SYMBOL_CLEANUP	2
-#define REPEAT_CFG_CLEANUP	3
+#define REPEAT_CSE		(1 << 0)
+#define REPEAT_SYMBOL_CLEANUP	(1 << 1)
+#define REPEAT_CFG_CLEANUP	(1 << 2)
 
 struct entrypoint;
 struct instruction;
@@ -14,26 +14,28 @@
 
 extern int simplify_flow(struct entrypoint *ep);
 
+extern void kill_dead_stores(struct entrypoint *ep, pseudo_t addr, int local);
 extern void simplify_symbol_usage(struct entrypoint *ep);
 extern void simplify_memops(struct entrypoint *ep);
 extern void pack_basic_blocks(struct entrypoint *ep);
 
 extern void convert_instruction_target(struct instruction *insn, pseudo_t src);
-extern void cleanup_and_cse(struct entrypoint *ep);
+extern void remove_dead_insns(struct entrypoint *);
 extern int simplify_instruction(struct instruction *);
 
 extern void kill_bb(struct basic_block *);
 extern void kill_use(pseudo_t *);
+extern void remove_use(pseudo_t *);
 extern void kill_unreachable_bbs(struct entrypoint *ep);
 
-extern void kill_insn(struct instruction *, int force);
-static inline void kill_instruction(struct instruction *insn)
+extern int kill_insn(struct instruction *, int force);
+static inline int kill_instruction(struct instruction *insn)
 {
-	kill_insn(insn, 0);
+	return kill_insn(insn, 0);
 }
-static inline void kill_instruction_force(struct instruction *insn)
+static inline int kill_instruction_force(struct instruction *insn)
 {
-	kill_insn(insn, 1);
+	return kill_insn(insn, 1);
 }
 
 void check_access(struct instruction *insn);
@@ -41,11 +43,6 @@
 void rewrite_load_instruction(struct instruction *, struct pseudo_list *);
 int dominates(pseudo_t pseudo, struct instruction *insn, struct instruction *dom, int local);
 
-extern void clear_liveness(struct entrypoint *ep);
-extern void track_pseudo_liveness(struct entrypoint *ep);
-extern void track_pseudo_death(struct entrypoint *ep);
-extern void track_phi_uses(struct instruction *insn);
-
 extern void vrfy_flow(struct entrypoint *ep);
 extern int pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo);
 
--- /dev/null	Mon Nov 18 13:18:55 2019
+++ new/usr/src/tools/smatch/src/flowgraph.c	Mon Nov 18 13:18:55 2019
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: MIT
+//
+// Various utilities for flowgraphs.
+//
+// Copyright (c) 2017 Luc Van Oostenryck.
+//
+
+#include "flowgraph.h"
+#include "linearize.h"
+#include "flow.h"			// for bb_generation
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+struct cfg_info {
+	struct basic_block_list *list;
+	unsigned long gen;
+	unsigned int nr;
+};
+
+
+static void label_postorder(struct basic_block *bb, struct cfg_info *info)
+{
+	struct basic_block *child;
+
+	if (bb->generation == info->gen)
+		return;
+
+	bb->generation = info->gen;
+	FOR_EACH_PTR_REVERSE(bb->children, child) {
+		label_postorder(child, info);
+	} END_FOR_EACH_PTR_REVERSE(child);
+
+	bb->postorder_nr = info->nr++;
+	add_bb(&info->list, bb);
+}
+
+static void reverse_bbs(struct basic_block_list **dst, struct basic_block_list *src)
+{
+	struct basic_block *bb;
+	FOR_EACH_PTR_REVERSE(src, bb) {
+		add_bb(dst, bb);
+	} END_FOR_EACH_PTR_REVERSE(bb);
+}
+
+static void debug_postorder(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+
+	printf("%s's reverse postorder:\n", show_ident(ep->name->ident));
+	FOR_EACH_PTR(ep->bbs, bb) {
+		printf("\t.L%u: %u\n", bb->nr, bb->postorder_nr);
+	} END_FOR_EACH_PTR(bb);
+}
+
+//
+// cfg_postorder - Set the BB's reverse postorder links
+//
+// Do a postorder DFS walk and set the links
+// (which will do the reverse part).
+//
+int cfg_postorder(struct entrypoint *ep)
+{
+	struct cfg_info info = {
+		.gen = ++bb_generation,
+	};
+
+	label_postorder(ep->entry->bb, &info);
+
+	// OK, now info.list contains the node in postorder
+	// Reuse ep->bbs for the reverse postorder.
+	free_ptr_list(&ep->bbs);
+	ep->bbs = NULL;
+	reverse_bbs(&ep->bbs, info.list);
+	free_ptr_list(&info.list);
+	if (dbg_postorder)
+		debug_postorder(ep);
+	return info.nr;
+}
+
+//
+// Calculate the dominance tree following:
+//	"A simple, fast dominance algorithm"
+//	by K. D. Cooper, T. J. Harvey, and K. Kennedy.
+//	cfr. http://www.cs.rice.edu/∼keith/EMBED/dom.pdf
+//
+static struct basic_block *intersect_dom(struct basic_block *doms[],
+		struct basic_block *b1, struct basic_block *b2)
+{
+	int f1 = b1->postorder_nr, f2 = b2->postorder_nr;
+	while (f1 != f2) {
+		while (f1 < f2) {
+			b1 = doms[f1];
+			f1 = b1->postorder_nr;
+		}
+		while (f2 < f1) {
+			b2 = doms[f2];
+			f2 = b2->postorder_nr;
+		}
+	}
+	return b1;
+}
+
+static void debug_domtree(struct entrypoint *ep)
+{
+	struct basic_block *bb = ep->entry->bb;
+
+	printf("%s's idoms:\n", show_ident(ep->name->ident));
+	FOR_EACH_PTR(ep->bbs, bb) {
+		if (bb == ep->entry->bb)
+			continue;	// entry node has no idom
+		printf("\t%s	<- %s\n", show_label(bb), show_label(bb->idom));
+	} END_FOR_EACH_PTR(bb);
+}
+
+void domtree_build(struct entrypoint *ep)
+{
+	struct basic_block *entry = ep->entry->bb;
+	struct basic_block **doms;
+	struct basic_block *bb;
+	unsigned int size;
+	int max_level = 0;
+	int changed;
+
+	// First calculate the (reverse) postorder.
+	// This will give use us:
+	//	- the links to do a reverse postorder traversal
+	//	- the order number for each block
+	size = cfg_postorder(ep);
+
+	// initialize the dominators array
+	doms = calloc(size, sizeof(*doms));
+	assert(entry->postorder_nr == size-1);
+	doms[size-1] = entry;
+
+	do {
+		struct basic_block *b;
+
+		changed = 0;
+		FOR_EACH_PTR(ep->bbs, b) {
+			struct basic_block *p;
+			int bnr = b->postorder_nr;
+			struct basic_block *new_idom = NULL;
+
+			if (b == entry)
+				continue;	// ignore entry node
+
+			FOR_EACH_PTR(b->parents, p) {
+				unsigned int pnr = p->postorder_nr;
+				if (!doms[pnr])
+					continue;
+				if (!new_idom) {
+					new_idom = p;
+					continue;
+				}
+
+				new_idom = intersect_dom(doms, p, new_idom);
+			} END_FOR_EACH_PTR(p);
+
+			assert(new_idom);
+			if (doms[bnr] != new_idom) {
+				doms[bnr] = new_idom;
+				changed = 1;
+			}
+		} END_FOR_EACH_PTR(b);
+	} while (changed);
+
+	// set the idom links
+	FOR_EACH_PTR(ep->bbs, bb) {
+		struct basic_block *idom = doms[bb->postorder_nr];
+
+		if (bb == entry)
+			continue;	// ignore entry node
+
+		bb->idom = idom;
+		add_bb(&idom->doms, bb);
+	} END_FOR_EACH_PTR(bb);
+	entry->idom = NULL;
+
+	// set the dominance levels
+	FOR_EACH_PTR(ep->bbs, bb) {
+		struct basic_block *idom = bb->idom;
+		int level = idom ? idom->dom_level + 1 : 0;
+
+		bb->dom_level = level;
+		if (max_level < level)
+			max_level = level;
+	} END_FOR_EACH_PTR(bb);
+	ep->dom_levels = max_level + 1;
+
+	free(doms);
+	if (dbg_domtree)
+		debug_domtree(ep);
+}
+
+// dt_dominates - does BB a dominates BB b?
+bool domtree_dominates(struct basic_block *a, struct basic_block *b)
+{
+	if (a == b)			// dominance is reflexive
+		return true;
+	if (a == b->idom)
+		return true;
+	if (b == a->idom)
+		return false;
+
+	// can't dominate if deeper in the DT
+	if (a->dom_level >= b->dom_level)
+		return false;
+
+	// FIXME: can be faster if we have the DFS in-out numbers
+
+	// walk up the dominator tree
+	for (b = b->idom; b; b = b->idom) {
+		if (b == a)
+			return true;
+	}
+	return false;
+}
--- /dev/null	Mon Nov 18 13:18:55 2019
+++ new/usr/src/tools/smatch/src/flowgraph.h	Mon Nov 18 13:18:55 2019
@@ -0,0 +1,13 @@
+#ifndef FLOWGRAPH_H
+#define FLOWGRAPH_H
+
+#include <stdbool.h>
+
+struct entrypoint;
+struct basic_block;
+
+int cfg_postorder(struct entrypoint *ep);
+void domtree_build(struct entrypoint *ep);
+bool domtree_dominates(struct basic_block *a, struct basic_block *b);
+
+#endif
--- old/usr/src/tools/smatch/src/gcc-attr-list.h	Mon Nov 18 13:18:56 2019
+++ new/usr/src/tools/smatch/src/gcc-attr-list.h	Mon Nov 18 13:18:56 2019
@@ -6,7 +6,6 @@
 GCC_ATTR(absdata)
 GCC_ATTR(address)
 GCC_ATTR(alias)
-GCC_ATTR(aligned)
 GCC_ATTR(alloc_align)
 GCC_ATTR(alloc_size)
 GCC_ATTR(altivec)
@@ -31,12 +30,9 @@
 GCC_ATTR(cold)
 GCC_ATTR(common)
 GCC_ATTR(common_object)
-GCC_ATTR(const)
 GCC_ATTR(constructor)
 GCC_ATTR(critical)
-GCC_ATTR(default)
 GCC_ATTR(deprecated)
-GCC_ATTR(designated_init)
 GCC_ATTR(destructor)
 GCC_ATTR(disinterrupt)
 GCC_ATTR(dllexport)
@@ -46,8 +42,6 @@
 GCC_ATTR(error)
 GCC_ATTR(exception)
 GCC_ATTR(exception_handler)
-GCC_ATTR(externally_visible)
-GCC_ATTR(fallthrough)
 GCC_ATTR(far)
 GCC_ATTR(fast_interrupt)
 GCC_ATTR(fastcall)
@@ -98,7 +92,6 @@
 GCC_ATTR(medium_call)
 GCC_ATTR(micromips)
 GCC_ATTR(mips16)
-GCC_ATTR(mode)
 GCC_ATTR(model)
 GCC_ATTR(monitor)
 GCC_ATTR(ms_abi)
@@ -137,13 +130,11 @@
 GCC_ATTR(nonnull)
 GCC_ATTR(nonstring)
 GCC_ATTR(noplt)
-GCC_ATTR(noreturn)
 GCC_ATTR(nosave_low_regs)
 GCC_ATTR(not_nested)
 GCC_ATTR(nothrow)
 GCC_ATTR(notshared)
 GCC_ATTR(optimize)
-GCC_ATTR(packed)
 GCC_ATTR(partial_save)
 GCC_ATTR(patchable_function_entry)
 GCC_ATTR(pcs)
@@ -150,7 +141,6 @@
 GCC_ATTR(persistent)
 GCC_ATTR(progmem)
 GCC_ATTR(protected)
-GCC_ATTR(pure)
 GCC_ATTR(reentrant)
 GCC_ATTR(regparm)
 GCC_ATTR(renesas)
@@ -195,7 +185,6 @@
 GCC_ATTR(transaction_safe_dynamic)
 GCC_ATTR(transaction_unsafe)
 GCC_ATTR(transaction_wrap)
-GCC_ATTR(transparent_union)
 GCC_ATTR(trap_exit)
 GCC_ATTR(trapa_handler)
 GCC_ATTR(uncached)
--- old/usr/src/tools/smatch/src/gdbhelpers	Mon Nov 18 13:18:56 2019
+++ new/usr/src/tools/smatch/src/gdbhelpers	Mon Nov 18 13:18:56 2019
@@ -107,6 +107,12 @@
 	if ($arg0->modifiers & MOD_VOLATILE)
 		printf "MOD_VOLATILE "
 	end
+	if ($arg0->modifiers & MOD_RESTRICT)
+		printf "MOD_RESTRICT "
+	end
+	if ($arg0->modifiers & MOD_ATOMIC)
+		printf "MOD_ATOMIC "
+	end
 	if ($arg0->modifiers & MOD_SIGNED)
 		printf "MOD_SIGNED "
 	end
@@ -128,9 +134,6 @@
 	if ($arg0->modifiers & MOD_LONGLONGLONG)
 		printf "MOD_LONGLONGLONG "
 	end
-	if ($arg0->modifiers & MOD_TYPEDEF)
-		printf "MOD_TYPEDEF "
-	end
 	if ($arg0->modifiers & MOD_INLINE)
 		printf "MOD_INLINE "
 	end
@@ -143,9 +146,6 @@
 	if ($arg0->modifiers & MOD_NODEREF)
 		printf "MOD_NODEREF "
 	end
-	if ($arg0->modifiers & MOD_ACCESSED)
-		printf "MOD_ACCESSED "
-	end
 	if ($arg0->modifiers & MOD_TOPLEVEL)
 		printf "MOD_TOPLEVEL "
 	end
--- old/usr/src/tools/smatch/src/graph.c	Mon Nov 18 13:18:56 2019
+++ new/usr/src/tools/smatch/src/graph.c	Mon Nov 18 13:18:56 2019
@@ -74,17 +74,19 @@
 
 		/* List loads and stores */
 		FOR_EACH_PTR(bb->insns, insn) {
+			if (!insn->bb)
+				continue;
 			switch(insn->opcode) {
 			case OP_STORE:
-				if (insn->symbol->type == PSEUDO_SYM) {
-				  printf("%s store(%s)", s, show_ident(insn->symbol->sym->ident));
+				if (insn->src->type == PSEUDO_SYM) {
+				  printf("%s store(%s)", s, show_ident(insn->src->sym->ident));
 				  s = ",";
 				}
 				break;
 
 			case OP_LOAD:
-				if (insn->symbol->type == PSEUDO_SYM) {
-				  printf("%s load(%s)", s, show_ident(insn->symbol->sym->ident));
+				if (insn->src->type == PSEUDO_SYM) {
+				  printf("%s load(%s)", s, show_ident(insn->src->sym->ident));
 				  s = ",";
 				}
 				break;
@@ -130,6 +132,8 @@
 			continue;
 
 		FOR_EACH_PTR(bb->insns, insn) {
+			if (!insn->bb)
+				continue;
 			if (insn->opcode == OP_CALL &&
 			    internal == !(insn->func->sym->ctype.modifiers & MOD_EXTERN)) {
 
@@ -172,7 +176,7 @@
 
 	/* Linearize all symbols, graph internal basic block
 	 * structures and intra-file calls */
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 
 		fsyms = sparse(file);
 		concat_symbol_list(fsyms, &all_syms);
@@ -187,15 +191,15 @@
 				graph_ep(sym->ep);
 				graph_calls(sym->ep, 1);
 			}
-		} END_FOR_EACH_PTR_NOTAG(sym);
+		} END_FOR_EACH_PTR(sym);
 
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 	/* Graph inter-file calls */
 	FOR_EACH_PTR(all_syms, sym) {
 		if (sym->ep)
 			graph_calls(sym->ep, 0);
-	} END_FOR_EACH_PTR_NOTAG(sym);
+	} END_FOR_EACH_PTR(sym);
 
 	printf("}\n");
 	return 0;
--- old/usr/src/tools/smatch/src/ident-list.h	Mon Nov 18 13:18:57 2019
+++ new/usr/src/tools/smatch/src/ident-list.h	Mon Nov 18 13:18:57 2019
@@ -37,7 +37,7 @@
 /* C11 keywords */
 IDENT(_Alignas);
 IDENT_RESERVED(_Alignof);
-IDENT_RESERVED(_Atomic);
+IDENT(_Atomic);
 IDENT_RESERVED(_Generic);
 IDENT(_Noreturn);
 IDENT_RESERVED(_Static_assert);
@@ -59,17 +59,14 @@
  * sparse. */
 IDENT(defined);
 IDENT(once);
+IDENT(__has_attribute);
+IDENT(__has_builtin);
 __IDENT(pragma_ident, "__pragma__", 0);
 __IDENT(_Pragma_ident, "_Pragma", 0);
 __IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
-__IDENT(__LINE___ident, "__LINE__", 0);
-__IDENT(__FILE___ident, "__FILE__", 0);
-__IDENT(__DATE___ident, "__DATE__", 0);
-__IDENT(__TIME___ident, "__TIME__", 0);
 __IDENT(__func___ident, "__func__", 0);
 __IDENT(__FUNCTION___ident, "__FUNCTION__", 0);
 __IDENT(__PRETTY_FUNCTION___ident, "__PRETTY_FUNCTION__", 0);
-__IDENT(__COUNTER___ident, "__COUNTER__", 0);
 
 /* Sparse commands */
 IDENT_RESERVED(__context__);
--- old/usr/src/tools/smatch/src/inline.c	Mon Nov 18 13:18:57 2019
+++ new/usr/src/tools/smatch/src/inline.c	Mon Nov 18 13:18:57 2019
@@ -32,7 +32,10 @@
 #include "parse.h"
 #include "symbol.h"
 #include "expression.h"
+#include "evaluate.h"
 
+static void copy_statement(struct statement *src, struct statement *dst);
+
 static struct expression * dup_expression(struct expression *expr)
 {
 	struct expression *dup = alloc_expression(expr->pos, expr->type);
@@ -178,14 +181,14 @@
 	case EXPR_SELECT:
 	case EXPR_CONDITIONAL: {
 		struct expression *cond = copy_expression(expr->conditional);
-		struct expression *true = copy_expression(expr->cond_true);
-		struct expression *false = copy_expression(expr->cond_false);
-		if (cond == expr->conditional && true == expr->cond_true && false == expr->cond_false)
+		struct expression *valt = copy_expression(expr->cond_true);
+		struct expression *valf = copy_expression(expr->cond_false);
+		if (cond == expr->conditional && valt == expr->cond_true && valf == expr->cond_false)
 			break;
 		expr = dup_expression(expr);
 		expr->conditional = cond;
-		expr->cond_true = true;
-		expr->cond_false = false;
+		expr->cond_true = valt;
+		expr->cond_false = valf;
 		break;
 	}
 
@@ -271,6 +274,12 @@
 		}
 		break;
 	}
+	case EXPR_ASM_OPERAND: {
+		expr = dup_expression(expr);
+		expr->constraint = copy_expression(expr->constraint);
+		expr->expr = copy_expression(expr->expr);
+		break;
+	}
 	default:
 		warning(expr->pos, "trying to copy expression type %d", expr->type);
 	}
@@ -281,20 +290,9 @@
 {
 	struct expression_list *out = NULL;
 	struct expression *expr;
-	int state = 0;
 
 	FOR_EACH_PTR(in, expr) {
-		switch (state) {
-		case 0: /* identifier */
-		case 1: /* constraint */
-			state++;
-			add_expression(&out, expr);
-			continue;
-		case 2: /* expression */
-			state = 0;
-			add_expression(&out, copy_expression(expr));
-			continue;
-		}
+		add_expression(&out, copy_expression(expr));
 	} END_FOR_EACH_PTR(expr);
 	return out;
 }
@@ -369,20 +367,20 @@
 	}
 	case STMT_IF: {
 		struct expression *cond = stmt->if_conditional;
-		struct statement *true = stmt->if_true;
-		struct statement *false = stmt->if_false;
+		struct statement *valt = stmt->if_true;
+		struct statement *valf = stmt->if_false;
 
 		cond = copy_expression(cond);
-		true = copy_one_statement(true);
-		false = copy_one_statement(false);
+		valt = copy_one_statement(valt);
+		valf = copy_one_statement(valf);
 		if (stmt->if_conditional == cond &&
-		    stmt->if_true == true &&
-		    stmt->if_false == false)
+		    stmt->if_true == valt &&
+		    stmt->if_false == valf)
 			break;
 		stmt = dup_statement(stmt);
 		stmt->if_conditional = cond;
-		stmt->if_true = true;
-		stmt->if_false = false;
+		stmt->if_true = valt;
+		stmt->if_false = valf;
 		break;
 	}
 	case STMT_RETURN: {
@@ -468,7 +466,7 @@
  * This doesn't do the symbol replacement right: it's not
  * re-entrant.
  */
-void copy_statement(struct statement *src, struct statement *dst)
+static void copy_statement(struct statement *src, struct statement *dst)
 {
 	struct statement *stmt;
 
--- /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;
+}
--- /dev/null	Mon Nov 18 13:18:58 2019
+++ new/usr/src/tools/smatch/src/ir.h	Mon Nov 18 13:18:58 2019
@@ -0,0 +1,8 @@
+#ifndef	_IR_H
+#define	_IR_H
+
+#include "linearize.h"
+
+int ir_validate(struct entrypoint *ep);
+
+#endif
--- old/usr/src/tools/smatch/src/lib.c	Mon Nov 18 13:18:58 2019
+++ new/usr/src/tools/smatch/src/lib.c	Mon Nov 18 13:18:58 2019
@@ -23,6 +23,7 @@
  * THE SOFTWARE.
  */
 #include <ctype.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -40,20 +41,19 @@
 #include "parse.h"
 #include "symbol.h"
 #include "expression.h"
+#include "evaluate.h"
 #include "scope.h"
 #include "linearize.h"
 #include "target.h"
+#include "machine.h"
 #include "version.h"
+#include "bits.h"
 
-static const char *progname;
-
-int sparse_errors = 0;
-int sparse_warnings = 0;
-
-int verbose, optimize, optimize_size, preprocessing;
+int verbose, optimize_level, optimize_size, preprocessing;
 int die_if_error = 0;
 int parse_error;
 int has_error = 0;
+int do_output = 0;
 
 #ifndef __GNUC__
 # define __GNUC__ 2
@@ -65,8 +65,12 @@
 int gcc_minor = __GNUC_MINOR__;
 int gcc_patchlevel = __GNUC_PATCHLEVEL__;
 
+const char *base_filename;
+
+static const char *diag_prefix = "";
 static const char *gcc_base_dir = GCC_BASE;
 static const char *multiarch_dir = MULTIARCH_TRIPLET;
+static const char *outfile = NULL;
 
 struct token *skip_to(struct token *token, int op)
 {
@@ -75,10 +79,10 @@
 	return token;
 }
 
+static struct token bad_token = { .pos.type = TOKEN_BAD };
 struct token *expect(struct token *token, int op, const char *where)
 {
 	if (!match_op(token, op)) {
-		static struct token bad_token;
 		if (token != &bad_token) {
 			bad_token.next = token;
 			sparse_error(token->pos, "Expected %s %s", show_special(op), where);
@@ -91,6 +95,21 @@
 	return token->next;
 }
 
+///
+// issue an error message on new parsing errors
+// @token: the current token
+// @errmsg: the error message
+// If the current token is from a previous error, an error message
+// has already been issued, so nothing more is done.
+// Otherwise, @errmsg is displayed followed by the current token.
+void unexpected(struct token *token, const char *errmsg)
+{
+	if (token == &bad_token)
+		return;
+	sparse_error(token->pos, "%s", errmsg);
+	sparse_error(token->pos, "got %s", show_token(token));
+}
+
 unsigned int hexval(unsigned int c)
 {
 	int retval = 256;
@@ -113,14 +132,19 @@
 	static char buffer[512];
 	const char *name;
 
+	/* Shut up warnings if position is bad_token.pos */
+	if (pos.type == TOKEN_BAD)
+		return;
+
 	vsprintf(buffer, fmt, args);	
 	name = stream_name(pos.stream);
 		
+	fflush(stdout);
 	fprintf(stderr, "%s: %s:%d:%d: %s%s\n",
-		progname, name, pos.line, pos.pos, type, buffer);
+		diag_prefix, name, pos.line, pos.pos, type, buffer);
 }
 
-static int max_warnings = 100;
+unsigned int fmax_warnings = 100;
 static int show_info = 1;
 
 void info(struct position pos, const char * fmt, ...)
@@ -141,6 +165,9 @@
 	parse_error = 1;
         die_if_error = 1;
 	show_info = 1;
+	/* Shut up warnings if position is bad_token.pos */
+	if (pos.type == TOKEN_BAD)
+		return;
 	/* Shut up warnings after an error */
 	has_error |= ERROR_CURR_PHASE;
 	if (errors > 100) {
@@ -167,12 +194,12 @@
 		return;
 	}
 
-	if (!max_warnings || has_error) {
+	if (!fmax_warnings || has_error) {
 		show_info = 0;
 		return;
 	}
 
-	if (!--max_warnings) {
+	if (!--fmax_warnings) {
 		show_info = 0;
 		fmt = "too many warnings";
 	}
@@ -219,7 +246,7 @@
 	vsnprintf(buffer, sizeof(buffer), fmt, args);
 	va_end(args);
 
-	fprintf(stderr, "%s: %s\n", progname, buffer);
+	fprintf(stderr, "%s: %s\n", diag_prefix, buffer);
 	exit(1);
 }
 
@@ -229,6 +256,8 @@
 int Waddress = 0;
 int Waddress_space = 1;
 int Wbitwise = 1;
+int Wbitwise_pointer = 0;
+int Wcast_from_as = 0;
 int Wcast_to_as = 0;
 int Wcast_truncate = 1;
 int Wconstant_suffix = 0;
@@ -241,6 +270,7 @@
 int Wdo_while = 0;
 int Wimplicit_int = 1;
 int Winit_cstring = 0;
+int Wint_to_pointer_cast = 1;
 int Wenum_mismatch = 1;
 int Wexternal_function_has_definition = 1;
 int Wsparse_error = 0;
@@ -254,9 +284,12 @@
 int Woverride_init_whole_range = 0;
 int Wparen_string = 0;
 int Wpointer_arith = 0;
+int Wpointer_to_int_cast = 1;
 int Wptr_subtraction_blows = 0;
 int Wreturn_void = 0;
 int Wshadow = 0;
+int Wshift_count_negative = 1;
+int Wshift_count_overflow = 1;
 int Wsizeof_bool = 0;
 int Wstrict_prototypes = 1;
 int Wtautological_compare = 0;
@@ -268,13 +301,20 @@
 int Wvla = 1;
 
 int dump_macro_defs = 0;
+int dump_macros_only = 0;
 
-int dbg_entry = 0;
+int dbg_compound = 0;
 int dbg_dead = 0;
+int dbg_domtree = 0;
+int dbg_entry = 0;
+int dbg_ir = 0;
+int dbg_postorder = 0;
 
+unsigned long fdump_ir;
 int fmem_report = 0;
-int fdump_linearize;
 unsigned long long fmemcpy_max_count = 100000;
+unsigned long fpasses = ~0UL;
+int funsigned_char = UNSIGNED_CHAR;
 
 int preprocess_only;
 
@@ -286,25 +326,10 @@
               STANDARD_GNU89,
               STANDARD_GNU99, } standard = STANDARD_GNU89;
 
-#define ARCH_LP32  0
-#define ARCH_LP64  1
-#define ARCH_LLP64 2
-
-#ifdef __x86_64__
-#define ARCH_M64_DEFAULT ARCH_LP64
-#else
-#define ARCH_M64_DEFAULT ARCH_LP32
-#endif
-
 int arch_m64 = ARCH_M64_DEFAULT;
 int arch_msize_long = 0;
-
-#ifdef __BIG_ENDIAN__
-#define ARCH_BIG_ENDIAN 1
-#else
-#define ARCH_BIG_ENDIAN 0
-#endif
 int arch_big_endian = ARCH_BIG_ENDIAN;
+int arch_mach = MACH_NATIVE;
 
 
 #define CMDLINE_INCLUDE 20
@@ -433,8 +458,10 @@
 {
 	if (!strcmp(arg, "m64")) {
 		arch_m64 = ARCH_LP64;
-	} else if (!strcmp(arg, "m32")) {
+	} else if (!strcmp(arg, "m32") || !strcmp(arg, "m16")) {
 		arch_m64 = ARCH_LP32;
+	} else if (!strcmp(arg, "mx32")) {
+		arch_m64 = ARCH_X32;
 	} else if (!strcmp(arg, "msize-llp64")) {
 		arch_m64 = ARCH_LLP64;
 	} else if (!strcmp(arg, "msize-long")) {
@@ -449,44 +476,6 @@
 	return next;
 }
 
-static void handle_arch_m64_finalize(void)
-{
-	switch (arch_m64) {
-	case ARCH_LP32:
-		/* default values */
-#if defined(__x86_64__) || defined (__i386)
- 		add_pre_buffer("#weak_define __i386__ 1\n");
- 		add_pre_buffer("#weak_define __i386 1\n");
- 		add_pre_buffer("#weak_define i386 1\n");
-#endif
-		return;
-	case ARCH_LP64:
-		bits_in_long = 64;
-		max_int_alignment = 8;
-		size_t_ctype = &ulong_ctype;
-		ssize_t_ctype = &long_ctype;
-		add_pre_buffer("#weak_define __LP64__ 1\n");
-		add_pre_buffer("#weak_define __LP64 1\n");
-		add_pre_buffer("#weak_define _LP64 1\n");
-		goto case_64bit_common;
-	case ARCH_LLP64:
-		bits_in_long = 32;
-		max_int_alignment = 4;
-		size_t_ctype = &ullong_ctype;
-		ssize_t_ctype = &llong_ctype;
-		add_pre_buffer("#weak_define __LLP64__ 1\n");
-		goto case_64bit_common;
-	case_64bit_common:
-		bits_in_pointer = 64;
-		pointer_alignment = 8;
-#if defined(__x86_64__) || defined (__i386)
-		add_pre_buffer("#weak_define __x86_64__ 1\n");
-		add_pre_buffer("#weak_define __x86_64 1\n");
-#endif
-		break;
-	}
-}
-
 static void handle_arch_msize_long_finalize(void)
 {
 	if (arch_msize_long) {
@@ -497,13 +486,80 @@
 
 static void handle_arch_finalize(void)
 {
-	handle_arch_m64_finalize();
 	handle_arch_msize_long_finalize();
 }
 
+static const char *match_option(const char *arg, const char *prefix)
+{
+	unsigned int n = strlen(prefix);
+	if (strncmp(arg, prefix, n) == 0)
+		return arg + n;
+	return NULL;
+}
 
-static int handle_simple_switch(const char *arg, const char *name, int *flag)
+
+struct mask_map {
+	const char *name;
+	unsigned long mask;
+};
+
+static int apply_mask(unsigned long *val, const char *str, unsigned len, const struct mask_map *map, int neg)
 {
+	const char *name;
+
+	for (;(name = map->name); map++) {
+		if (!strncmp(name, str, len) && !name[len]) {
+			if (neg == 0)
+				*val |= map->mask;
+			else
+				*val &= ~map->mask;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int handle_suboption_mask(const char *arg, const char *opt, const struct mask_map *map, unsigned long *flag)
+{
+	if (*opt == '\0') {
+		apply_mask(flag, "", 0, map, 0);
+		return 1;
+	}
+	if (*opt++ != '=')
+		return 0;
+	while (1) {
+		unsigned int len = strcspn(opt, ",+");
+		int neg = 0;
+		if (len == 0)
+			goto end;
+		if (!strncmp(opt, "no-", 3)) {
+			opt += 3;
+			len -= 3;
+			neg = 1;
+		}
+		if (apply_mask(flag, opt, len, map, neg))
+			die("error: wrong option '%.*s' for \'%s\'", len, opt, arg);
+
+end:
+		opt += len;
+		if (*opt++ == '\0')
+			break;
+	}
+	return 1;
+}
+
+
+#define OPT_INVERSE	1
+struct flag {
+	const char *name;
+	int *flag;
+	int (*fun)(const char *arg, const char *opt, const struct flag *, int options);
+	unsigned long mask;
+};
+
+static int handle_switches(const char *ori, const char *opt, const struct flag *flags)
+{
+	const char *arg = opt;
 	int val = 1;
 
 	// Prefixe "no-" mean to turn flag off.
@@ -512,9 +568,28 @@
 		val = 0;
 	}
 
-	if (strcmp(arg, name) == 0) {
-		*flag = val;
-		return 1;
+	for (; flags->name; flags++) {
+		const char *opt = match_option(arg, flags->name);
+		int rc;
+
+		if (!opt)
+			continue;
+
+		if (flags->fun) {
+			int options = 0;
+			if (!val)
+				options |= OPT_INVERSE;
+			if ((rc = flags->fun(ori, opt, flags, options)))
+				return rc;
+		}
+
+		// boolean flag
+		if (opt[0] == '\0' && flags->flag) {
+			if (flags->mask & OPT_INVERSE)
+				val = !val;
+			*flags->flag = val;
+			return 1;
+		}
 	}
 
 	// not handled
@@ -521,11 +596,39 @@
 	return 0;
 }
 
+
+#define	OPTNUM_ZERO_IS_INF		1
+#define	OPTNUM_UNLIMITED		2
+
+#define OPT_NUMERIC(NAME, TYPE, FUNCTION)	\
+static int opt_##NAME(const char *arg, const char *opt, TYPE *ptr, int flag)	\
+{									\
+	char *end;							\
+	TYPE val;							\
+									\
+	val = FUNCTION(opt, &end, 0);					\
+	if (*end != '\0' || end == opt) {				\
+		if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited"))	\
+			val = ~val;					\
+		else							\
+			die("error: wrong argument to \'%s\'", arg);	\
+	}								\
+	if ((flag & OPTNUM_ZERO_IS_INF) && val == 0)			\
+		val = ~val;						\
+	*ptr = val;							\
+	return 1;							\
+}
+
+OPT_NUMERIC(ullong, unsigned long long, strtoull)
+OPT_NUMERIC(uint, unsigned int, strtoul)
+
+
 static char **handle_switch_o(char *arg, char **next)
 {
 	if (!strcmp (arg, "o")) {       // "-o foo"
 		if (!*++next)
 			die("argument to '-o' is missing");
+		outfile = *next;
 	}
 	// else "-ofoo"
 
@@ -532,13 +635,12 @@
 	return next;
 }
 
-static const struct warning {
-	const char *name;
-	int *flag;
-} warnings[] = {
+static const struct flag warnings[] = {
 	{ "address", &Waddress },
 	{ "address-space", &Waddress_space },
 	{ "bitwise", &Wbitwise },
+	{ "bitwise-pointer", &Wbitwise_pointer},
+	{ "cast-from-as", &Wcast_from_as },
 	{ "cast-to-as", &Wcast_to_as },
 	{ "cast-truncate", &Wcast_truncate },
 	{ "constant-suffix", &Wconstant_suffix },
@@ -553,6 +655,7 @@
 	{ "external-function-has-definition", &Wexternal_function_has_definition },
 	{ "implicit-int", &Wimplicit_int },
 	{ "init-cstring", &Winit_cstring },
+	{ "int-to-pointer-cast", &Wint_to_pointer_cast },
 	{ "memcpy-max-count", &Wmemcpy_max_count },
 	{ "non-pointer-null", &Wnon_pointer_null },
 	{ "old-initializer", &Wold_initializer },
@@ -561,9 +664,12 @@
 	{ "override-init", &Woverride_init },
 	{ "override-init-all", &Woverride_init_all },
 	{ "paren-string", &Wparen_string },
+	{ "pointer-to-int-cast", &Wpointer_to_int_cast },
 	{ "ptr-subtraction-blows", &Wptr_subtraction_blows },
 	{ "return-void", &Wreturn_void },
 	{ "shadow", &Wshadow },
+	{ "shift-count-negative", &Wshift_count_negative },
+	{ "shift-count-overflow", &Wshift_count_overflow },
 	{ "sizeof-bool", &Wsizeof_bool },
 	{ "strict-prototypes", &Wstrict_prototypes },
 	{ "pointer-arith", &Wpointer_arith },
@@ -584,7 +690,7 @@
 };
 
 
-static char **handle_onoff_switch(char *arg, char **next, const struct warning warnings[], int n)
+static char **handle_onoff_switch(char *arg, char **next, const struct flag warnings[], int n)
 {
 	int flag = WARNING_ON;
 	char *p = arg + 1;
@@ -595,6 +701,7 @@
 			if (*warnings[i].flag != WARNING_FORCE_OFF && warnings[i].flag != &Wsparse_error)
 				*warnings[i].flag = WARNING_ON;
 		}
+		return NULL;
 	}
 
 	// Prefixes "no" and "no-" mean to turn warning off.
@@ -626,9 +733,13 @@
 	return next;
 }
 
-static struct warning debugs[] = {
-	{ "entry", &dbg_entry},
+static struct flag debugs[] = {
+	{ "compound", &dbg_compound},
 	{ "dead", &dbg_dead},
+	{ "domtree", &dbg_domtree},
+	{ "entry", &dbg_entry},
+	{ "ir", &dbg_ir},
+	{ "postorder", &dbg_postorder},
 };
 
 
@@ -645,21 +756,39 @@
 	return next;
 }
 
-static struct warning dumps[] = {
-	{ "D", &dump_macro_defs},
-};
-
 static char **handle_switch_d(char *arg, char **next)
 {
-	char ** ret = handle_onoff_switch(arg, next, dumps, ARRAY_SIZE(dumps));
-	if (ret)
-		return ret;
+	char *arg_char = arg + 1;
 
+	/*
+	 * -d<CHARS>, where <CHARS> is a sequence of characters, not preceded
+	 * by a space. If you specify characters whose behaviour conflicts,
+	 * the result is undefined.
+	 */
+	while (*arg_char) {
+		switch (*arg_char) {
+		case 'M': /* dump just the macro definitions */
+			dump_macros_only = 1;
+			dump_macro_defs = 0;
+			break;
+		case 'D': /* like 'M', but also output pre-processed text */
+			dump_macro_defs = 1;
+			dump_macros_only = 0;
+			break;
+		case 'N': /* like 'D', but only output macro names not bodies */
+			break;
+		case 'I': /* like 'D', but also output #include directives */
+			break;
+		case 'U': /* like 'D', but only output expanded macros */
+			break;
+		}
+		arg_char++;
+	}
 	return next;
 }
 
 
-static void handle_onoff_switch_finalize(const struct warning warnings[], int n)
+static void handle_onoff_switch_finalize(const struct flag warnings[], int n)
 {
 	unsigned i;
 
@@ -717,88 +846,115 @@
 	int level = 1;
 	if (arg[1] >= '0' && arg[1] <= '9')
 		level = arg[1] - '0';
-	optimize = level;
+	optimize_level = level;
 	optimize_size = arg[1] == 's';
 	return next;
 }
 
-static char **handle_switch_fmemcpy_max_count(char *arg, char **next)
+static int handle_ftabstop(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-	unsigned long long val;
+	unsigned long val;
 	char *end;
 
-	val = strtoull(arg, &end, 0);
-	if (*end != '\0' || end == arg)
-		die("error: missing argument to \"-fmemcpy-max-count=\"");
+	if (*opt == '\0')
+		die("error: missing argument to \"%s\"", arg);
 
-	if (val == 0)
-		val = ~0ULL;
-	fmemcpy_max_count = val;
-	return next;
-}
-
-static char **handle_switch_ftabstop(char *arg, char **next)
-{
-	char *end;
-	unsigned long val;
-
-	if (*arg == '\0')
-		die("error: missing argument to \"-ftabstop=\"");
-
 	/* we silently ignore silly values */
-	val = strtoul(arg, &end, 10);
+	val = strtoul(opt, &end, 10);
 	if (*end == '\0' && 1 <= val && val <= 100)
 		tabstop = val;
 
-	return next;
+	return 1;
 }
 
-static int funsigned_char;
-static void handle_funsigned_char(void)
+static int handle_fpasses(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-	if (funsigned_char) {
-		char_ctype.ctype.modifiers &= ~MOD_SIGNED;
-		char_ctype.ctype.modifiers |= MOD_UNSIGNED;
+	unsigned long mask;
+
+	mask = flag->mask;
+	if (*opt == '\0') {
+		if (options & OPT_INVERSE)
+			fpasses &= ~mask;
+		else
+			fpasses |=  mask;
+		return 1;
 	}
+	if (options & OPT_INVERSE)
+		return 0;
+	if (!strcmp(opt, "-enable")) {
+		fpasses |= mask;
+		return 1;
+	}
+	if (!strcmp(opt, "-disable")) {
+		fpasses &= ~mask;
+		return 1;
+	}
+	if (!strcmp(opt, "=last")) {
+		// clear everything above
+		mask |= mask - 1;
+		fpasses &= mask;
+		return 1;
+	}
+	return 0;
 }
 
-	static char **handle_switch_fdump(char *arg, char **next)
+static int handle_fdiagnostic_prefix(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-	if (!strncmp(arg, "linearize", 9)) {
-		arg += 9;
-		if (*arg == '\0')
-			fdump_linearize = 1;
-		else if (!strcmp(arg, "=only"))
-			fdump_linearize = 2;
-		else
-			goto err;
+	switch (*opt) {
+	case '\0':
+		diag_prefix = "sparse";
+		return 1;
+	case '=':
+		diag_prefix = xasprintf("%s", opt+1);
+		return 1;
+	default:
+		return 0;
 	}
+}
 
-	/* ignore others flags */
-	return next;
+static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options)
+{
+	static const struct mask_map dump_ir_options[] = {
+		{ "",			PASS_LINEARIZE },
+		{ "linearize",		PASS_LINEARIZE },
+		{ "mem2reg",		PASS_MEM2REG },
+		{ "final",		PASS_FINAL },
+		{ },
+	};
 
-err:
-	die("error: unknown flag \"-fdump-%s\"", arg);
+	return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir);
 }
 
-static char **handle_switch_f(char *arg, char **next)
+static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-	arg++;
+	opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED);
+	return 1;
+}
 
-	if (!strncmp(arg, "tabstop=", 8))
-		return handle_switch_ftabstop(arg+8, next);
-	if (!strncmp(arg, "dump-", 5))
-		return handle_switch_fdump(arg+5, next);
-	if (!strncmp(arg, "memcpy-max-count=", 17))
-		return handle_switch_fmemcpy_max_count(arg+17, next);
+static int handle_fmax_warnings(const char *arg, const char *opt, const struct flag *flag, int options)
+{
+	opt_uint(arg, opt, &fmax_warnings, OPTNUM_UNLIMITED);
+	return 1;
+}
 
-	if (!strcmp(arg, "unsigned-char")) {
-		funsigned_char = 1;
-		return next;
-	}
+static struct flag fflags[] = {
+	{ "diagnostic-prefix",	NULL,	handle_fdiagnostic_prefix },
+	{ "dump-ir",		NULL,	handle_fdump_ir },
+	{ "linearize",		NULL,	handle_fpasses,	PASS_LINEARIZE },
+	{ "max-warnings=",	NULL,	handle_fmax_warnings },
+	{ "mem-report",		&fmem_report },
+	{ "memcpy-max-count=",	NULL,	handle_fmemcpy_max_count },
+	{ "tabstop=",		NULL,	handle_ftabstop },
+	{ "mem2reg",		NULL,	handle_fpasses,	PASS_MEM2REG },
+	{ "optim",		NULL,	handle_fpasses,	PASS_OPTIM },
+	{ "signed-char",	&funsigned_char, NULL,	OPT_INVERSE },
+	{ "unsigned-char",	&funsigned_char, NULL, },
+	{ },
+};
 
-	/* handle switches w/ arguments above, boolean and only boolean below */
-	if (handle_simple_switch(arg, "mem-report", &fmem_report))
+static char **handle_switch_f(char *arg, char **next)
+{
+	if (handle_switches(arg-1, arg+1, fflags))
 		return next;
 
 	return next;
@@ -820,12 +976,9 @@
 	return next;
 }
 
-static char **handle_switch_s(char *arg, char **next)
+static char **handle_switch_s(const char *arg, char **next)
 {
-	if (!strncmp (arg, "std=", 4))
-	{
-		arg += 4;
-
+	if ((arg = match_option(arg, "std="))) {
 		if (!strcmp (arg, "c89") ||
 		    !strcmp (arg, "iso9899:1990"))
 			standard = STANDARD_C89;
@@ -896,6 +1049,13 @@
 	return next;
 }
 
+static char **handle_switch_x(char *arg, char **next)
+{
+	if (!*++next)
+		die("missing argument for -x option");
+	return next;
+}
+
 static char **handle_version(char *arg, char **next)
 {
 	printf("%s\n", SPARSE_VERSION);
@@ -910,7 +1070,6 @@
 	if (strcmp(arg, "-mapper") == 0)
 		return next;
 
-
 	/* For now just skip any '--param=*' or '--param *' */
 	if (*arg == '\0') {
 		value = *++next;
@@ -972,6 +1131,7 @@
 	case 'U': return handle_switch_U(arg, next);
 	case 'v': return handle_switch_v(arg, next);
 	case 'W': return handle_switch_W(arg, next);
+	case 'x': return handle_switch_x(arg, next);
 	case '-': return handle_long_options(arg + 1, next);
 	default:
 		break;
@@ -984,246 +1144,283 @@
 	return next;
 }
 
-static void predefined_sizeof(const char *name, unsigned bits)
+#define	PTYPE_SIZEOF	(1U << 0)
+#define	PTYPE_T		(1U << 1)
+#define	PTYPE_MAX	(1U << 2)
+#define	PTYPE_MIN	(1U << 3)
+#define	PTYPE_WIDTH	(1U << 4)
+#define	PTYPE_TYPE	(1U << 5)
+#define	PTYPE_ALL	(PTYPE_MAX|PTYPE_SIZEOF|PTYPE_WIDTH)
+#define	PTYPE_ALL_T	(PTYPE_MAX|PTYPE_SIZEOF|PTYPE_WIDTH|PTYPE_T)
+
+static void predefined_sizeof(const char *name, const char *suffix, unsigned bits)
 {
-	add_pre_buffer("#weak_define __SIZEOF_%s__ %d\n", name, bits/8);
+	char buf[32];
+
+	snprintf(buf, sizeof(buf), "__SIZEOF_%s%s__", name, suffix);
+	predefine(buf, 1, "%d", bits/8);
 }
 
-static void predefined_max(const char *name, const char *suffix, unsigned bits)
+static void predefined_width(const char *name, unsigned bits)
 {
-	unsigned long long max = (1ULL << (bits - 1 )) - 1;
+	char buf[32];
 
-	add_pre_buffer("#weak_define __%s_MAX__ %#llx%s\n", name, max, suffix);
+	snprintf(buf, sizeof(buf), "__%s_WIDTH__", name);
+	predefine(buf, 1, "%d", bits);
 }
 
-static void predefined_type_size(const char *name, const char *suffix, unsigned bits)
+static void predefined_max(const char *name, struct symbol *type)
 {
-	predefined_max(name, suffix, bits);
-	predefined_sizeof(name, bits);
+	const char *suffix = builtin_type_suffix(type);
+	unsigned bits = type->bit_size - is_signed_type(type);
+	unsigned long long max = bits_mask(bits);
+	char buf[32];
+
+	snprintf(buf, sizeof(buf), "__%s_MAX__", name);
+	predefine(buf, 1, "%#llx%s", max, suffix);
 }
 
-static void predefined_macros(void)
+static void predefined_min(const char *name, struct symbol *type)
 {
-	add_pre_buffer("#define __CHECKER__ 1\n");
+	const char *suffix = builtin_type_suffix(type);
+	char buf[32];
 
-	predefined_sizeof("SHORT", bits_in_short);
-	predefined_max("SHRT", "", bits_in_short);
-	predefined_max("SCHAR", "", bits_in_char);
-	predefined_max("WCHAR", "", bits_in_wchar);
-	add_pre_buffer("#weak_define __CHAR_BIT__ %d\n", bits_in_char);
+	snprintf(buf, sizeof(buf), "__%s_MIN__", name);
 
-	predefined_type_size("INT", "", bits_in_int);
-	predefined_type_size("LONG", "L", bits_in_long);
-	predefined_type_size("LONG_LONG", "LL", bits_in_longlong);
+	if (is_signed_type(type))
+		predefine(buf, 1, "(-__%s_MAX__ - 1)", name);
+	else
+		predefine(buf, 1, "0%s", suffix);
+}
 
-	predefined_sizeof("INT128", 128);
+static void predefined_type(const char *name, struct symbol *type)
+{
+	const char *typename = builtin_typename(type);
+	add_pre_buffer("#weak_define __%s_TYPE__ %s\n", name, typename);
+}
 
-	predefined_sizeof("SIZE_T", bits_in_pointer);
-	predefined_sizeof("PTRDIFF_T", bits_in_pointer);
-	predefined_sizeof("POINTER", bits_in_pointer);
+static void predefined_ctype(const char *name, struct symbol *type, int flags)
+{
+	unsigned bits = type->bit_size;
 
-	predefined_sizeof("FLOAT", bits_in_float);
-	predefined_sizeof("DOUBLE", bits_in_double);
-	predefined_sizeof("LONG_DOUBLE", bits_in_longdouble);
+	if (flags & PTYPE_SIZEOF) {
+		const char *suffix = (flags & PTYPE_T) ? "_T" : "";
+		predefined_sizeof(name, suffix, bits);
+	}
+	if (flags & PTYPE_MAX)
+		predefined_max(name, type);
+	if (flags & PTYPE_MIN)
+		predefined_min(name, type);
+	if (flags & PTYPE_TYPE)
+		predefined_type(name, type);
+	if (flags & PTYPE_WIDTH)
+		predefined_width(name, bits);
+}
 
-	add_pre_buffer("#weak_define __%s_ENDIAN__ 1\n",
-		arch_big_endian ? "BIG" : "LITTLE");
+static void predefined_macros(void)
+{
+	predefine("__CHECKER__", 0, "1");
+	predefine("__GNUC__", 1, "%d", gcc_major);
+	predefine("__GNUC_MINOR__", 1, "%d", gcc_minor);
+	predefine("__GNUC_PATCHLEVEL__", 1, "%d", gcc_patchlevel);
 
-	add_pre_buffer("#weak_define __ORDER_LITTLE_ENDIAN__ 1234\n");
-	add_pre_buffer("#weak_define __ORDER_BIG_ENDIAN__ 4321\n");
-	add_pre_buffer("#weak_define __ORDER_PDP_ENDIAN__ 3412\n");
-	add_pre_buffer("#weak_define __BYTE_ORDER__ __ORDER_%s_ENDIAN__\n",
-		arch_big_endian ? "BIG" : "LITTLE");
+	predefine("__STDC__", 1, "1");
+	switch (standard) {
+	case STANDARD_C89:
+		predefine("__STRICT_ANSI__", 1, "1");
+		break;
 
-	add_pre_buffer("#weak_define __PRAGMA_REDEFINE_EXTNAME 1\n");
+	case STANDARD_C94:
+		predefine("__STDC_VERSION__", 1, "199409L");
+		predefine("__STRICT_ANSI__", 1, "1");
+		break;
 
-	/*
-	 * This is far from perfect...
-	 */
-#ifdef	__sun
-	add_pre_buffer("#weak_define __unix__ 1\n");
-	add_pre_buffer("#weak_define __unix 1\n");
-	add_pre_buffer("#weak_define unix 1\n");
-	add_pre_buffer("#weak_define __sun__ 1\n");
-	add_pre_buffer("#weak_define __sun 1\n");
-	add_pre_buffer("#weak_define sun 1\n");
-	add_pre_buffer("#weak_define __svr4__ 1\n");
-#endif
-}
+	case STANDARD_C99:
+		predefine("__STDC_VERSION__", 1, "199901L");
+		predefine("__STRICT_ANSI__", 1, "1");
+		break;
 
-void declare_builtin_functions(void)
-{
-	/* Gaah. gcc knows tons of builtin <string.h> functions */
-	add_pre_buffer("extern void *__builtin_memchr(const void *, int, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void *__builtin_memcpy(void *, const void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void *__builtin_mempcpy(void *, const void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void *__builtin_memmove(void *, const void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void *__builtin_memset(void *, int, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern int __builtin_memcmp(const void *, const void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern char *__builtin_strcat(char *, const char *);\n");
-	add_pre_buffer("extern char *__builtin_strncat(char *, const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern int __builtin_strcmp(const char *, const char *);\n");
-	add_pre_buffer("extern int __builtin_strncmp(const char *, const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern int __builtin_strcasecmp(const char *, const char *);\n");
-	add_pre_buffer("extern int __builtin_strncasecmp(const char *, const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern char *__builtin_strchr(const char *, int);\n");
-	add_pre_buffer("extern char *__builtin_strrchr(const char *, int);\n");
-	add_pre_buffer("extern char *__builtin_strcpy(char *, const char *);\n");
-	add_pre_buffer("extern char *__builtin_strncpy(char *, const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern char *__builtin_strdup(const char *);\n");
-	add_pre_buffer("extern char *__builtin_strndup(const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern __SIZE_TYPE__ __builtin_strspn(const char *, const char *);\n");
-	add_pre_buffer("extern __SIZE_TYPE__ __builtin_strcspn(const char *, const char *);\n");
-	add_pre_buffer("extern char * __builtin_strpbrk(const char *, const char *);\n");
-	add_pre_buffer("extern char* __builtin_stpcpy(const char *, const char*);\n");
-	add_pre_buffer("extern char* __builtin_stpncpy(const char *, const char*, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern __SIZE_TYPE__ __builtin_strlen(const char *);\n");
-	add_pre_buffer("extern char *__builtin_strstr(const char *, const char *);\n");
-	add_pre_buffer("extern char *__builtin_strcasestr(const char *, const char *);\n");
-	add_pre_buffer("extern char *__builtin_strnstr(const char *, const char *, __SIZE_TYPE__);\n");
+	case STANDARD_GNU89:
+	default:
+		break;
 
-	/* And even some from <strings.h> */
-	add_pre_buffer("extern int  __builtin_bcmp(const void *, const void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void __builtin_bcopy(const void *, void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void __builtin_bzero(void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern char*__builtin_index(const char *, int);\n");
-	add_pre_buffer("extern char*__builtin_rindex(const char *, int);\n");
+	case STANDARD_GNU99:
+		predefine("__STDC_VERSION__", 1, "199901L");
+		break;
 
-	/* And bitwise operations.. */
-	add_pre_buffer("extern int __builtin_clrsb(int);\n");
-	add_pre_buffer("extern int __builtin_clrsbl(long);\n");
-	add_pre_buffer("extern int __builtin_clrsbll(long long);\n");
-	add_pre_buffer("extern int __builtin_clz(int);\n");
-	add_pre_buffer("extern int __builtin_clzl(long);\n");
-	add_pre_buffer("extern int __builtin_clzll(long long);\n");
-	add_pre_buffer("extern int __builtin_ctz(int);\n");
-	add_pre_buffer("extern int __builtin_ctzl(long);\n");
-	add_pre_buffer("extern int __builtin_ctzll(long long);\n");
-	add_pre_buffer("extern int __builtin_ffs(int);\n");
-	add_pre_buffer("extern int __builtin_ffsl(long);\n");
-	add_pre_buffer("extern int __builtin_ffsll(long long);\n");
-	add_pre_buffer("extern int __builtin_parity(unsigned int);\n");
-	add_pre_buffer("extern int __builtin_parityl(unsigned long);\n");
-	add_pre_buffer("extern int __builtin_parityll(unsigned long long);\n");
-	add_pre_buffer("extern int __builtin_popcount(unsigned int);\n");
-	add_pre_buffer("extern int __builtin_popcountl(unsigned long);\n");
-	add_pre_buffer("extern int __builtin_popcountll(unsigned long long);\n");
+	case STANDARD_C11:
+		predefine("__STRICT_ANSI__", 1, "1");
+	case STANDARD_GNU11:
+		predefine("__STDC_NO_ATOMICS__", 1, "1");
+		predefine("__STDC_NO_COMPLEX__", 1, "1");
+		predefine("__STDC_NO_THREADS__", 1, "1");
+		predefine("__STDC_VERSION__", 1, "201112L");
+		break;
+	}
 
-	/* And byte swaps.. */
-	add_pre_buffer("extern unsigned short __builtin_bswap16(unsigned short);\n");
-	add_pre_buffer("extern unsigned int __builtin_bswap32(unsigned int);\n");
-	add_pre_buffer("extern unsigned long long __builtin_bswap64(unsigned long long);\n");
+	predefine("__CHAR_BIT__", 1, "%d", bits_in_char);
+	if (funsigned_char)
+		predefine("__CHAR_UNSIGNED__", 1, "1");
 
-	/* And atomic memory access functions.. */
-	add_pre_buffer("extern int __sync_fetch_and_add(void *, ...);\n");
-	add_pre_buffer("extern int __sync_fetch_and_sub(void *, ...);\n");
-	add_pre_buffer("extern int __sync_fetch_and_or(void *, ...);\n");
-	add_pre_buffer("extern int __sync_fetch_and_and(void *, ...);\n");
-	add_pre_buffer("extern int __sync_fetch_and_xor(void *, ...);\n");
-	add_pre_buffer("extern int __sync_fetch_and_nand(void *, ...);\n");
-	add_pre_buffer("extern int __sync_add_and_fetch(void *, ...);\n");
-	add_pre_buffer("extern int __sync_sub_and_fetch(void *, ...);\n");
-	add_pre_buffer("extern int __sync_or_and_fetch(void *, ...);\n");
-	add_pre_buffer("extern int __sync_and_and_fetch(void *, ...);\n");
-	add_pre_buffer("extern int __sync_xor_and_fetch(void *, ...);\n");
-	add_pre_buffer("extern int __sync_nand_and_fetch(void *, ...);\n");
-	add_pre_buffer("extern int __sync_bool_compare_and_swap(void *, ...);\n");
-	add_pre_buffer("extern int __sync_val_compare_and_swap(void *, ...);\n");
-	add_pre_buffer("extern void __sync_synchronize();\n");
-	add_pre_buffer("extern int __sync_lock_test_and_set(void *, ...);\n");
-	add_pre_buffer("extern void __sync_lock_release(void *, ...);\n");
+	predefined_ctype("SHORT",     &short_ctype, PTYPE_SIZEOF);
+	predefined_ctype("SHRT",      &short_ctype, PTYPE_MAX|PTYPE_WIDTH);
+	predefined_ctype("SCHAR",     &schar_ctype, PTYPE_MAX|PTYPE_WIDTH);
+	predefined_ctype("WCHAR",      wchar_ctype, PTYPE_ALL_T|PTYPE_MIN|PTYPE_TYPE);
+	predefined_ctype("WINT",        wint_ctype, PTYPE_ALL_T|PTYPE_MIN|PTYPE_TYPE);
+	predefined_ctype("CHAR16",   &ushort_ctype, PTYPE_TYPE);
+	predefined_ctype("CHAR32",     &uint_ctype, PTYPE_TYPE);
 
-	/* And some random ones.. */
-	add_pre_buffer("extern void *__builtin_return_address(unsigned int);\n");
-	add_pre_buffer("extern void *__builtin_extract_return_addr(void *);\n");
-	add_pre_buffer("extern void *__builtin_frame_address(unsigned int);\n");
-	add_pre_buffer("extern void __builtin_trap(void);\n");
-	add_pre_buffer("extern void *__builtin_alloca(__SIZE_TYPE__);\n");
-	add_pre_buffer("extern void __builtin_prefetch (const void *, ...);\n");
-	add_pre_buffer("extern long __builtin_alpha_extbl(long, long);\n");
-	add_pre_buffer("extern long __builtin_alpha_extwl(long, long);\n");
-	add_pre_buffer("extern long __builtin_alpha_insbl(long, long);\n");
-	add_pre_buffer("extern long __builtin_alpha_inswl(long, long);\n");
-	add_pre_buffer("extern long __builtin_alpha_insql(long, long);\n");
-	add_pre_buffer("extern long __builtin_alpha_inslh(long, long);\n");
-	add_pre_buffer("extern long __builtin_alpha_cmpbge(long, long);\n");
-	add_pre_buffer("extern int  __builtin_abs(int);\n");
-	add_pre_buffer("extern long __builtin_labs(long);\n");
-	add_pre_buffer("extern long long __builtin_llabs(long long);\n");
-	add_pre_buffer("extern double __builtin_fabs(double);\n");
-	add_pre_buffer("extern __SIZE_TYPE__ __builtin_va_arg_pack_len(void);\n");
+	predefined_ctype("INT",         &int_ctype, PTYPE_ALL);
+	predefined_ctype("LONG",       &long_ctype, PTYPE_ALL);
+	predefined_ctype("LONG_LONG", &llong_ctype, PTYPE_ALL);
 
-	/* Add Blackfin-specific stuff */
-	add_pre_buffer(
-		"#ifdef __bfin__\n"
-		"extern void __builtin_bfin_csync(void);\n"
-		"extern void __builtin_bfin_ssync(void);\n"
-		"extern int __builtin_bfin_norm_fr1x32(int);\n"
-		"#endif\n"
-	);
+	predefined_ctype("INT8",      &schar_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("UINT8",     &uchar_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("INT16",     &short_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("UINT16",   &ushort_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("INT32",      int32_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("UINT32",    uint32_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("INT64",      int64_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("UINT64",    uint64_ctype, PTYPE_MAX|PTYPE_TYPE);
 
-	/* And some floating point stuff.. */
-	add_pre_buffer("extern int __builtin_isgreater(float, float);\n");
-	add_pre_buffer("extern int __builtin_isgreaterequal(float, float);\n");
-	add_pre_buffer("extern int __builtin_isless(float, float);\n");
-	add_pre_buffer("extern int __builtin_islessequal(float, float);\n");
-	add_pre_buffer("extern int __builtin_islessgreater(float, float);\n");
-	add_pre_buffer("extern int __builtin_isunordered(float, float);\n");
+	predefined_sizeof("INT128", "", 128);
 
-	/* And some INFINITY / NAN stuff.. */
-	add_pre_buffer("extern double __builtin_huge_val(void);\n");
-	add_pre_buffer("extern float __builtin_huge_valf(void);\n");
-	add_pre_buffer("extern long double __builtin_huge_vall(void);\n");
-	add_pre_buffer("extern double __builtin_inf(void);\n");
-	add_pre_buffer("extern float __builtin_inff(void);\n");
-	add_pre_buffer("extern long double __builtin_infl(void);\n");
-	add_pre_buffer("extern double __builtin_nan(const char *);\n");
-	add_pre_buffer("extern float __builtin_nanf(const char *);\n");
-	add_pre_buffer("extern long double __builtin_nanl(const char *);\n");
-	add_pre_buffer("extern int __builtin_isinf_sign(float);\n");
-	add_pre_buffer("extern int __builtin_isfinite(float);\n");
-	add_pre_buffer("extern int __builtin_isnan(float);\n");
+	predefined_ctype("INTMAX",    intmax_ctype, PTYPE_MAX|PTYPE_TYPE|PTYPE_WIDTH);
+	predefined_ctype("UINTMAX",  uintmax_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("INTPTR",   ssize_t_ctype, PTYPE_MAX|PTYPE_TYPE|PTYPE_WIDTH);
+	predefined_ctype("UINTPTR",   size_t_ctype, PTYPE_MAX|PTYPE_TYPE);
+	predefined_ctype("PTRDIFF",  ssize_t_ctype, PTYPE_ALL_T|PTYPE_TYPE);
+	predefined_ctype("SIZE",      size_t_ctype, PTYPE_ALL_T|PTYPE_TYPE);
+	predefined_ctype("POINTER",     &ptr_ctype, PTYPE_SIZEOF);
 
-	/* And some __FORTIFY_SOURCE ones.. */
-	add_pre_buffer ("extern __SIZE_TYPE__ __builtin_object_size(const void *, int);\n");
-	add_pre_buffer ("extern void * __builtin___memcpy_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern void * __builtin___memmove_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern void * __builtin___mempcpy_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern void * __builtin___memset_chk(void *, int, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern int __builtin___sprintf_chk(char *, int, __SIZE_TYPE__, const char *, ...);\n");
-	add_pre_buffer ("extern int __builtin___snprintf_chk(char *, __SIZE_TYPE__, int , __SIZE_TYPE__, const char *, ...);\n");
-	add_pre_buffer ("extern char * __builtin___stpcpy_chk(char *, const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern char * __builtin___strcat_chk(char *, const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern char * __builtin___strcpy_chk(char *, const char *, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern char * __builtin___strncat_chk(char *, const char *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern char * __builtin___strncpy_chk(char *, const char *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-	add_pre_buffer ("extern int __builtin___vsprintf_chk(char *, int, __SIZE_TYPE__, const char *, __builtin_va_list);\n");
-	add_pre_buffer ("extern int __builtin___vsnprintf_chk(char *, __SIZE_TYPE__, int, __SIZE_TYPE__, const char *, __builtin_va_list ap);\n");
-	add_pre_buffer ("extern void __builtin_unreachable(void);\n");
+	predefined_sizeof("FLOAT", "", bits_in_float);
+	predefined_sizeof("DOUBLE", "", bits_in_double);
+	predefined_sizeof("LONG_DOUBLE", "", bits_in_longdouble);
 
-	/* And some from <stdlib.h> */
-	add_pre_buffer("extern void __builtin_abort(void);\n");
-	add_pre_buffer("extern void *__builtin_calloc(__SIZE_TYPE__, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void __builtin_exit(int);\n");
-	add_pre_buffer("extern void *__builtin_malloc(__SIZE_TYPE__);\n");
-	add_pre_buffer("extern void *__builtin_realloc(void *, __SIZE_TYPE__);\n");
-	add_pre_buffer("extern void __builtin_free(void *);\n");
+	predefine("__ORDER_LITTLE_ENDIAN__", 1, "1234");
+	predefine("__ORDER_BIG_ENDIAN__", 1, "4321");
+	predefine("__ORDER_PDP_ENDIAN__", 1, "3412");
+	if (arch_big_endian) {
+		predefine("__BIG_ENDIAN__", 1, "1");
+		predefine("__BYTE_ORDER__", 1, "__ORDER_BIG_ENDIAN__");
+	} else {
+		predefine("__LITTLE_ENDIAN__", 1, "1");
+		predefine("__BYTE_ORDER__", 1, "__ORDER_LITTLE_ENDIAN__");
+	}
 
-	/* And some from <stdio.h> */
-	add_pre_buffer("extern int __builtin_printf(const char *, ...);\n");
-	add_pre_buffer("extern int __builtin_sprintf(char *, const char *, ...);\n");
-	add_pre_buffer("extern int __builtin_snprintf(char *, __SIZE_TYPE__, const char *, ...);\n");
-	add_pre_buffer("extern int __builtin_puts(const char *);\n");
-	add_pre_buffer("extern int __builtin_vprintf(const char *, __builtin_va_list);\n");
-	add_pre_buffer("extern int __builtin_vsprintf(char *, const char *, __builtin_va_list);\n");
-	add_pre_buffer("extern int __builtin_vsnprintf(char *, __SIZE_TYPE__, const char *, __builtin_va_list ap);\n");
+	if (optimize_level)
+		predefine("__OPTIMIZE__", 0, "1");
+	if (optimize_size)
+		predefine("__OPTIMIZE_SIZE__", 0, "1");
+
+	// Temporary hacks
+	predefine("__extension__", 0, NULL);
+	predefine("__pragma__", 0, NULL);
+
+	switch (arch_m64) {
+	case ARCH_LP32:
+		break;
+	case ARCH_X32:
+		predefine("__ILP32__", 1, "1");
+		predefine("_ILP32", 1, "1");
+		break;
+	case ARCH_LP64:
+		predefine("__LP64__", 1, "1");
+		predefine("__LP64", 1, "1");
+		predefine("_LP64", 1, "1");
+		break;
+	case ARCH_LLP64:
+		predefine("__LLP64__", 1, "1");
+		break;
+	}
+
+	switch (arch_mach) {
+	case MACH_ARM64:
+		predefine("__aarch64__", 1, "1");
+		break;
+	case MACH_ARM:
+		predefine("__arm__", 1, "1");
+		break;
+	case MACH_M68K:
+		predefine("__m68k__", 1, "1");
+		break;
+	case MACH_MIPS64:
+		if (arch_m64 == ARCH_LP64)
+			predefine("__mips64", 1, "64");
+		/* fall-through */
+	case MACH_MIPS32:
+		predefine("__mips", 1, "%d", ptr_ctype.bit_size);
+		predefine("_MIPS_SZINT", 1, "%d", int_ctype.bit_size);
+		predefine("_MIPS_SZLONG", 1, "%d", long_ctype.bit_size);
+		predefine("_MIPS_SZPTR", 1, "%d", ptr_ctype.bit_size);
+		break;
+	case MACH_PPC64:
+		if (arch_m64 == ARCH_LP64) {
+			predefine("__powerpc64__", 1, "1");
+			predefine("__ppc64__", 1, "1");
+			predefine("__PPC64__", 1, "1");
+		}
+		/* fall-through */
+	case MACH_PPC32:
+		predefine("__powerpc__", 1, "1");
+		predefine("__powerpc", 1, "1");
+		predefine("__ppc__", 1, "1");
+		predefine("__PPC__", 1, "1");
+		break;
+	case MACH_RISCV64:
+	case MACH_RISCV32:
+		predefine("__riscv", 1, "1");
+		predefine("__riscv_xlen", 1, "%d", ptr_ctype.bit_size);
+		break;
+	case MACH_S390X:
+		predefine("__zarch__", 1, "1");
+		predefine("__s390x__", 1, "1");
+		predefine("__s390__", 1, "1");
+		break;
+	case MACH_SPARC64:
+		if (arch_m64 == ARCH_LP64) {
+			predefine("__sparc_v9__", 1, "1");
+			predefine("__sparcv9__", 1, "1");
+			predefine("__sparcv9", 1, "1");
+			predefine("__sparc64__", 1, "1");
+			predefine("__arch64__", 1, "1");
+		}
+		/* fall-through */
+	case MACH_SPARC32:
+		predefine("__sparc__", 1, "1");
+		predefine("__sparc", 1, "1");
+		break;
+	case MACH_X86_64:
+		if (arch_m64 != ARCH_LP32) {
+			predefine("__x86_64__", 1, "1");
+			predefine("__x86_64", 1, "1");
+			break;
+		}
+		/* fall-through */
+	case MACH_I386:
+		predefine("__i386__", 1, "1");
+		predefine("__i386", 1, "1");
+		predefine("i386", 1, "1");
+		break;
+	}
+
+	predefine("__PRAGMA_REDEFINE_EXTNAME", 1, "1");
+
+#ifdef	__sun
+	predefine("__unix__", 1, "1");
+	predefine("__unix", 1, "1");
+	predefine("unix", 1, "1");
+	predefine("__sun__", 1, "1");
+	predefine("__sun", 1, "1");
+	predefine("sun", 1, "1");
+	predefine("__svr4__", 1, "1");
+#endif
 }
 
-void create_builtin_stream(void)
+static void create_builtin_stream(void)
 {
-	add_pre_buffer("#weak_define __GNUC__ %d\n", gcc_major);
-	add_pre_buffer("#weak_define __GNUC_MINOR__ %d\n", gcc_minor);
-	add_pre_buffer("#weak_define __GNUC_PATCHLEVEL__ %d\n", gcc_patchlevel);
+	// Temporary hack
+	add_pre_buffer("#define _Pragma(x)\n");
 
 	/* add the multiarch include directories, if any */
 	if (multiarch_dir && *multiarch_dir) {
@@ -1236,57 +1433,8 @@
 	add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
 	add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
 
-	add_pre_buffer("#define __extension__\n");
-	add_pre_buffer("#define __pragma__\n");
-	add_pre_buffer("#define _Pragma(x)\n");
-
-	// gcc defines __SIZE_TYPE__ to be size_t.  For linux/i86 and
-	// solaris/sparc that is really "unsigned int" and for linux/x86_64
-	// it is "long unsigned int".  In either case we can probably
-	// get away with this.  We need the #weak_define as cgcc will define
-	// the right __SIZE_TYPE__.
-	if (size_t_ctype == &ulong_ctype)
-		add_pre_buffer("#weak_define __SIZE_TYPE__ long unsigned int\n");
-	else
-		add_pre_buffer("#weak_define __SIZE_TYPE__ unsigned int\n");
-	add_pre_buffer("#weak_define __STDC__ 1\n");
-
-	switch (standard)
-	{
-		case STANDARD_C89:
-			add_pre_buffer("#weak_define __STRICT_ANSI__\n");
-			break;
-
-		case STANDARD_C94:
-			add_pre_buffer("#weak_define __STDC_VERSION__ 199409L\n");
-			add_pre_buffer("#weak_define __STRICT_ANSI__\n");
-			break;
-
-		case STANDARD_C99:
-			add_pre_buffer("#weak_define __STDC_VERSION__ 199901L\n");
-			add_pre_buffer("#weak_define __STRICT_ANSI__\n");
-			break;
-
-		case STANDARD_GNU89:
-			break;
-
-		case STANDARD_GNU99:
-			add_pre_buffer("#weak_define __STDC_VERSION__ 199901L\n");
-			break;
-
-		case STANDARD_C11:
-			add_pre_buffer("#weak_define __STRICT_ANSI__ 1\n");
-		case STANDARD_GNU11:
-			add_pre_buffer("#weak_define __STDC_NO_ATOMICS__ 1\n");
-			add_pre_buffer("#weak_define __STDC_NO_COMPLEX__ 1\n");
-			add_pre_buffer("#weak_define __STDC_NO_THREADS__ 1\n");
-			add_pre_buffer("#weak_define __STDC_VERSION__ 201112L\n");
-			break;
-
-		default:
-			assert (0);
-	}
-
+	add_pre_buffer("#define __has_builtin(x) 0\n");
+	add_pre_buffer("#define __has_attribute(x) 0\n");
 	add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
 	add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
 	add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
@@ -1298,14 +1446,6 @@
 	add_pre_buffer("#define __builtin_va_end(arg)\n");
 	add_pre_buffer("#define __builtin_ms_va_end(arg)\n");
 	add_pre_buffer("#define __builtin_va_arg_pack()\n");
-
-	/* FIXME! We need to do these as special magic macros at expansion time! */
-	add_pre_buffer("#define __BASE_FILE__ \"base_file.c\"\n");
-
-	if (optimize)
-		add_pre_buffer("#define __OPTIMIZE__ 1\n");
-	if (optimize_size)
-		add_pre_buffer("#define __OPTIMIZE_SIZE__ 1\n");
 }
 
 static struct symbol_list *sparse_tokenstream(struct token *token)
@@ -1315,8 +1455,12 @@
 	// Preprocess the stream
 	token = preprocess(token);
 
-	if (dump_macro_defs && !builtin)
-		dump_macro_definitions();
+	if (dump_macro_defs || dump_macros_only) {
+		if (!builtin)
+			dump_macro_definitions();
+		if (dump_macros_only)
+			return NULL;
+	}
 
 	if (preprocess_only) {
 		while (!eof_token(token)) {
@@ -1357,6 +1501,7 @@
 		if (fd < 0)
 			die("No such file: %s", filename);
 	}
+	base_filename = filename;
 
 	// Tokenize the input stream
 	token = tokenize(filename, fd, NULL, includepath);
@@ -1366,12 +1511,6 @@
 	return sparse_tokenstream(token);
 }
 
-static int endswith(const char *str, const char *suffix)
-{
-	const char *found = strstr(str, suffix);
-	return (found && strcmp(found, suffix) == 0);
-}
-
 /*
  * This handles the "-include" directive etc: we're in global
  * scope, and all types/macros etc will affect all the following
@@ -1393,6 +1532,12 @@
 	return sparse_tokenstream(pre_buffer_begin);
 }
 
+static int endswith(const char *str, const char *suffix)
+{
+	const char *found = strstr(str, suffix);
+	return (found && strcmp(found, suffix) == 0);
+}
+
 struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **filelist)
 {
 	char **args;
@@ -1402,7 +1547,7 @@
 	init_symbols();
 	init_include_path();
 
-	progname = argv[0];
+	diag_prefix = argv[0];
 
 	args = argv;
 	for (;;) {
@@ -1419,23 +1564,32 @@
 		    endswith(arg, ".so.1") || endswith(arg, ".o"))
 			continue;
 
-		add_ptr_list_notag(filelist, arg);
+		add_ptr_list(filelist, arg);
 	}
 	handle_switch_W_finalize();
 	handle_switch_v_finalize();
 
-	handle_arch_finalize();
+	// Redirect stdout if needed
+	if (dump_macro_defs || preprocess_only)
+		do_output = 1;
+	if (do_output && outfile && strcmp(outfile, "-")) {
+		if (!freopen(outfile, "w", stdout))
+			die("error: cannot open %s: %s", outfile, strerror(errno));
+	}
 
+	if (fdump_ir == 0)
+		fdump_ir = PASS_FINAL;
+
 	list = NULL;
-	if (!ptr_list_empty(filelist)) {
+	if (filelist) {
 		// Initialize type system
+		init_target();
+		handle_arch_finalize();
 		init_ctype();
-		handle_funsigned_char();
 
-		create_builtin_stream();
 		predefined_macros();
-		if (!preprocess_only)
-			declare_builtin_functions();
+		create_builtin_stream();
+		declare_builtins();
 
 		list = sparse_initial();
 
--- old/usr/src/tools/smatch/src/lib.h	Mon Nov 18 13:18:59 2019
+++ new/usr/src/tools/smatch/src/lib.h	Mon Nov 18 13:18:59 2019
@@ -1,6 +1,7 @@
 #ifndef LIB_H
 #define LIB_H
 
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stddef.h>
 
@@ -32,6 +33,8 @@
 
 #include "compat.h"
 #include "ptrlist.h"
+#include "utils.h"
+#include "bits.h"
 
 #define DO_STRINGIFY(x) #x
 #define STRINGIFY(x) DO_STRINGIFY(x)
@@ -40,12 +43,15 @@
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 #endif
 
-extern int verbose, optimize, optimize_size, preprocessing;
+extern int verbose, optimize_level, optimize_size, preprocessing;
 extern int die_if_error;
 extern int parse_error;
-extern int repeat_phase, merge_phi_sources;
+extern int repeat_phase;
+extern int do_output;
 extern int gcc_major, gcc_minor, gcc_patchlevel;
 
+extern const char *base_filename;
+
 extern unsigned int hexval(unsigned int c);
 
 struct position {
@@ -83,6 +89,8 @@
 
 struct token *skip_to(struct token *, int);
 struct token *expect(struct token *, int, const char *);
+void unexpected(struct token *, const char *errmsg);
+
 #ifdef __GNUC__
 #define FORMAT_ATTR(pos) __attribute__ ((__format__ (__printf__, pos, pos+1)))
 #define NORETURN_ATTR __attribute__ ((__noreturn__))
@@ -108,7 +116,24 @@
 #define	ERROR_PREV_PHASE	(1 << 1)
 extern int has_error;
 
+
+enum phase {
+	PASS__PARSE,
+	PASS__LINEARIZE,
+	PASS__MEM2REG,
+	PASS__OPTIM,
+	PASS__FINAL,
+};
+
+#define	PASS_PARSE		(1UL << PASS__PARSE)
+#define	PASS_LINEARIZE		(1UL << PASS__LINEARIZE)
+#define	PASS_MEM2REG		(1UL << PASS__MEM2REG)
+#define	PASS_OPTIM		(1UL << PASS__OPTIM)
+#define	PASS_FINAL		(1UL << PASS__FINAL)
+
+
 extern void add_pre_buffer(const char *fmt, ...) FORMAT_ATTR(1);
+extern void predefine(const char *name, int weak, const char *fmt, ...) FORMAT_ATTR(3);
 
 extern int preprocess_only;
 
@@ -115,6 +140,8 @@
 extern int Waddress;
 extern int Waddress_space;
 extern int Wbitwise;
+extern int Wbitwise_pointer;
+extern int Wcast_from_as;
 extern int Wcast_to_as;
 extern int Wcast_truncate;
 extern int Wconstant_suffix;
@@ -130,6 +157,7 @@
 extern int Wsparse_error;
 extern int Wimplicit_int;
 extern int Winit_cstring;
+extern int Wint_to_pointer_cast;
 extern int Wmemcpy_max_count;
 extern int Wnon_pointer_null;
 extern int Wold_initializer;
@@ -140,9 +168,12 @@
 extern int Woverride_init_whole_range;
 extern int Wparen_string;
 extern int Wpointer_arith;
+extern int Wpointer_to_int_cast;
 extern int Wptr_subtraction_blows;
 extern int Wreturn_void;
 extern int Wshadow;
+extern int Wshift_count_negative;
+extern int Wshift_count_overflow;
 extern int Wsizeof_bool;
 extern int Wstrict_prototypes;
 extern int Wtautological_compare;
@@ -154,20 +185,27 @@
 extern int Wvla;
 
 extern int dump_macro_defs;
+extern int dump_macros_only;
 
-extern int dbg_entry;
+extern int dbg_compound;
 extern int dbg_dead;
+extern int dbg_domtree;
+extern int dbg_entry;
+extern int dbg_ir;
+extern int dbg_postorder;
 
+extern unsigned int fmax_warnings;
 extern int fmem_report;
-extern int fdump_linearize;
+extern unsigned long fdump_ir;
 extern unsigned long long fmemcpy_max_count;
+extern unsigned long fpasses;
+extern int funsigned_char;
 
 extern int arch_m64;
 extern int arch_msize_long;
 extern int arch_big_endian;
+extern int arch_mach;
 
-extern void declare_builtin_functions(void);
-extern void create_builtin_stream(void);
 extern void dump_macro_definitions(void);
 extern struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **files);
 extern struct symbol_list *__sparse(char *filename);
@@ -207,7 +245,7 @@
 
 static inline void free_instruction_list(struct instruction_list **head)
 {
-	free_ptr_list((struct ptr_list **)head);
+	free_ptr_list(head);
 }
 
 static inline struct instruction * delete_last_instruction(struct instruction_list **head)
@@ -215,11 +253,6 @@
 	return undo_ptr_list_last((struct ptr_list **)head);
 }
 
-static inline struct basic_block * delete_last_basic_block(struct basic_block_list **head)
-{
-	return delete_ptr_list_last((struct ptr_list **)head);
-}
-
 static inline struct basic_block *first_basic_block(struct basic_block_list *head)
 {
 	return first_ptr_list((struct ptr_list *)head);
--- old/usr/src/tools/smatch/src/linearize.c	Mon Nov 18 13:18:59 2019
+++ new/usr/src/tools/smatch/src/linearize.c	Mon Nov 18 13:18:59 2019
@@ -19,12 +19,14 @@
 #include "parse.h"
 #include "expression.h"
 #include "linearize.h"
+#include "optimize.h"
 #include "flow.h"
 #include "target.h"
 
-pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt);
-pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr);
+static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt);
+static pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr);
 
+static pseudo_t add_cast(struct entrypoint *ep, struct symbol *to, struct symbol *from, int op, pseudo_t src);
 static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right);
 static pseudo_t add_setval(struct entrypoint *ep, struct symbol *ctype, struct expression *val);
 static pseudo_t linearize_one_symbol(struct entrypoint *ep, struct symbol *sym);
@@ -70,7 +72,6 @@
 {
 	static int nr;
 	struct basic_block *bb = __alloc_basic_block(0);
-	bb->context = -1;
 	bb->pos = pos;
 	bb->ep = ep;
 	bb->nr = nr++;
@@ -77,7 +78,7 @@
 	return bb;
 }
 
-static struct multijmp *alloc_multijmp(struct basic_block *target, int begin, int end)
+static struct multijmp *alloc_multijmp(struct basic_block *target, long long begin, long long end)
 {
 	struct multijmp *multijmp = __alloc_multijmp(0);
 	multijmp->target = target;
@@ -86,12 +87,16 @@
 	return multijmp;
 }
 
-static inline int regno(pseudo_t n)
+const char *show_label(struct basic_block *bb)
 {
-	int retval = -1;
-	if (n && n->type == PSEUDO_REG)
-		retval = n->nr;
-	return retval;
+	static int n;
+	static char buffer[4][16];
+	char *buf = buffer[3 & ++n];
+
+	if (!bb)
+		return ".L???";
+	snprintf(buf, 64, ".L%u", bb->nr);
+	return buf;
 }
 
 const char *show_pseudo(pseudo_t pseudo)
@@ -111,8 +116,12 @@
 		struct symbol *sym = pseudo->sym;
 		struct expression *expr;
 
+		if (!sym) {
+			snprintf(buf, 64, "<bad symbol>");
+			break;
+		}
 		if (sym->bb_target) {
-			snprintf(buf, 64, ".L%u", sym->bb_target->nr);
+			snprintf(buf, 64, "%s", show_label(sym->bb_target));
 			break;
 		}
 		if (sym->ident) {
@@ -120,7 +129,7 @@
 			break;
 		}
 		expr = sym->initializer;
-		snprintf(buf, 64, "<anon symbol:%p>", sym);
+		snprintf(buf, 64, "<anon symbol:%p>", verbose ? sym : NULL);
 		if (expr) {
 			switch (expr->type) {
 			case EXPR_VALUE:
@@ -155,6 +164,8 @@
 		if (pseudo->ident)
 			sprintf(buf+i, "(%s)", show_ident(pseudo->ident));
 		break;
+	case PSEUDO_UNDEF:
+		return "UNDEF";
 	default:
 		snprintf(buf, 64, "<bad pseudo type %d>", pseudo->type);
 	}
@@ -172,15 +183,12 @@
 	[OP_BR] = "br",
 	[OP_CBR] = "cbr",
 	[OP_SWITCH] = "switch",
-	[OP_INVOKE] = "invoke",
 	[OP_COMPUTEDGOTO] = "jmp *",
-	[OP_UNWIND] = "unwind",
 	
 	/* Binary */
 	[OP_ADD] = "add",
 	[OP_SUB] = "sub",
-	[OP_MULU] = "mulu",
-	[OP_MULS] = "muls",
+	[OP_MUL] = "mul",
 	[OP_DIVU] = "divu",
 	[OP_DIVS] = "divs",
 	[OP_MODU] = "modu",
@@ -189,12 +197,16 @@
 	[OP_LSR] = "lsr",
 	[OP_ASR] = "asr",
 	
+	/* Floating-point Binary */
+	[OP_FADD] = "fadd",
+	[OP_FSUB] = "fsub",
+	[OP_FMUL] = "fmul",
+	[OP_FDIV] = "fdiv",
+
 	/* Logical */
 	[OP_AND] = "and",
 	[OP_OR] = "or",
 	[OP_XOR] = "xor",
-	[OP_AND_BOOL] = "and-bool",
-	[OP_OR_BOOL] = "or-bool",
 
 	/* Binary comparison */
 	[OP_SET_EQ] = "seteq",
@@ -208,37 +220,54 @@
 	[OP_SET_BE] = "setbe",
 	[OP_SET_AE] = "setae",
 
+	/* floating-point comparison */
+	[OP_FCMP_ORD] = "fcmpord",
+	[OP_FCMP_OEQ] = "fcmpoeq",
+	[OP_FCMP_ONE] = "fcmpone",
+	[OP_FCMP_OLE] = "fcmpole",
+	[OP_FCMP_OGE] = "fcmpoge",
+	[OP_FCMP_OLT] = "fcmpolt",
+	[OP_FCMP_OGT] = "fcmpogt",
+	[OP_FCMP_UEQ] = "fcmpueq",
+	[OP_FCMP_UNE] = "fcmpune",
+	[OP_FCMP_ULE] = "fcmpule",
+	[OP_FCMP_UGE] = "fcmpuge",
+	[OP_FCMP_ULT] = "fcmpult",
+	[OP_FCMP_UGT] = "fcmpugt",
+	[OP_FCMP_UNO] = "fcmpuno",
+
 	/* Uni */
 	[OP_NOT] = "not",
 	[OP_NEG] = "neg",
+	[OP_FNEG] = "fneg",
 
 	/* Special three-input */
 	[OP_SEL] = "select",
 	
 	/* Memory */
-	[OP_MALLOC] = "malloc",
-	[OP_FREE] = "free",
-	[OP_ALLOCA] = "alloca",
 	[OP_LOAD] = "load",
 	[OP_STORE] = "store",
 	[OP_SETVAL] = "set",
+	[OP_SETFVAL] = "setfval",
 	[OP_SYMADDR] = "symaddr",
-	[OP_GET_ELEMENT_PTR] = "getelem",
 
 	/* Other */
 	[OP_PHI] = "phi",
 	[OP_PHISOURCE] = "phisrc",
-	[OP_CAST] = "cast",
-	[OP_SCAST] = "scast",
-	[OP_FPCAST] = "fpcast",
+	[OP_SEXT] = "sext",
+	[OP_ZEXT] = "zext",
+	[OP_TRUNC] = "trunc",
+	[OP_FCVTU] = "fcvtu",
+	[OP_FCVTS] = "fcvts",
+	[OP_UCVTF] = "ucvtf",
+	[OP_SCVTF] = "scvtf",
+	[OP_FCVTF] = "fcvtf",
+	[OP_UTPTR] = "utptr",
+	[OP_PTRTU] = "ptrtu",
 	[OP_PTRCAST] = "ptrcast",
 	[OP_INLINED_CALL] = "# call",
 	[OP_CALL] = "call",
-	[OP_VANEXT] = "va_next",
-	[OP_VAARG] = "va_arg",
 	[OP_SLICE] = "slice",
-	[OP_SNOP] = "snop",
-	[OP_LNOP] = "lnop",
 	[OP_NOP] = "nop",
 	[OP_DEATHNOTE] = "dead",
 	[OP_ASM] = "asm",
@@ -307,34 +336,15 @@
 		break;
 
 	case OP_CBR:
-		buf += sprintf(buf, "%s, .L%u, .L%u", show_pseudo(insn->cond), insn->bb_true->nr, insn->bb_false->nr);
+		buf += sprintf(buf, "%s, %s, %s", show_pseudo(insn->cond), show_label(insn->bb_true), show_label(insn->bb_false));
 		break;
 
 	case OP_BR:
-		buf += sprintf(buf, ".L%u", insn->bb_true->nr);
+		buf += sprintf(buf, "%s", show_label(insn->bb_true));
 		break;
 
-	case OP_SYMADDR: {
-		struct symbol *sym = insn->symbol->sym;
-		buf += sprintf(buf, "%s <- ", show_pseudo(insn->target));
-
-		if (!insn->bb && !sym)
-			break;
-		if (sym->bb_target) {
-			buf += sprintf(buf, ".L%u", sym->bb_target->nr);
-			break;
-		}
-		if (sym->ident) {
-			buf += sprintf(buf, "%s", show_ident(sym->ident));
-			break;
-		}
-		buf += sprintf(buf, "<anon symbol:%p>", sym);
-		break;
-	}
-		
 	case OP_SETVAL: {
 		struct expression *expr = insn->val;
-		struct symbol *sym;
 		buf += sprintf(buf, "%s <- ", show_pseudo(insn->target));
 
 		if (!expr) {
@@ -347,7 +357,7 @@
 			buf += sprintf(buf, "%lld", expr->value);
 			break;
 		case EXPR_FVALUE:
-			buf += sprintf(buf, "%Lf", expr->fvalue);
+			buf += sprintf(buf, "%Le", expr->fvalue);
 			break;
 		case EXPR_STRING:
 			buf += sprintf(buf, "%.40s", show_string(expr->string));
@@ -356,9 +366,7 @@
 			buf += sprintf(buf, "%s", show_ident(expr->symbol->ident));
 			break;
 		case EXPR_LABEL:
-			sym = expr->symbol;
-			if (sym->bb_target)
-				buf += sprintf(buf, ".L%u", sym->bb_target->nr);
+			buf += sprintf(buf, "%s", show_label(expr->symbol->bb_target));
 			break;
 		default:
 			buf += sprintf(buf, "SETVAL EXPR TYPE %d", expr->type);
@@ -365,24 +373,29 @@
 		}
 		break;
 	}
+	case OP_SETFVAL:
+		buf += sprintf(buf, "%s <- ", show_pseudo(insn->target));
+		buf += sprintf(buf, "%Le", insn->fvalue);
+		break;
+
 	case OP_SWITCH: {
 		struct multijmp *jmp;
 		buf += sprintf(buf, "%s", show_pseudo(insn->cond));
 		FOR_EACH_PTR(insn->multijmp_list, jmp) {
 			if (jmp->begin == jmp->end)
-				buf += sprintf(buf, ", %d -> .L%u", jmp->begin, jmp->target->nr);
+				buf += sprintf(buf, ", %lld -> %s", jmp->begin, show_label(jmp->target));
 			else if (jmp->begin < jmp->end)
-				buf += sprintf(buf, ", %d ... %d -> .L%u", jmp->begin, jmp->end, jmp->target->nr);
+				buf += sprintf(buf, ", %lld ... %lld -> %s", jmp->begin, jmp->end, show_label(jmp->target));
 			else
-				buf += sprintf(buf, ", default -> .L%u", jmp->target->nr);
+				buf += sprintf(buf, ", default -> %s", show_label(jmp->target));
 		} END_FOR_EACH_PTR(jmp);
 		break;
 	}
 	case OP_COMPUTEDGOTO: {
 		struct multijmp *jmp;
-		buf += sprintf(buf, "%s", show_pseudo(insn->target));
+		buf += sprintf(buf, "%s", show_pseudo(insn->src));
 		FOR_EACH_PTR(insn->multijmp_list, jmp) {
-			buf += sprintf(buf, ", .L%u", jmp->target->nr);
+			buf += sprintf(buf, ", %s", show_label(jmp->target));
 		} END_FOR_EACH_PTR(jmp);
 		break;
 	}
@@ -401,15 +414,17 @@
 		const char *s = " <-";
 		buf += sprintf(buf, "%s", show_pseudo(insn->target));
 		FOR_EACH_PTR(insn->phi_list, phi) {
+			if (phi == VOID && !verbose)
+				continue;
 			buf += sprintf(buf, "%s %s", s, show_pseudo(phi));
 			s = ",";
 		} END_FOR_EACH_PTR(phi);
 		break;
 	}	
-	case OP_LOAD: case OP_LNOP:
+	case OP_LOAD:
 		buf += sprintf(buf, "%s <- %d[%s]", show_pseudo(insn->target), insn->offset, show_pseudo(insn->src));
 		break;
-	case OP_STORE: case OP_SNOP:
+	case OP_STORE:
 		buf += sprintf(buf, "%s -> %d[%s]", show_pseudo(insn->target), insn->offset, show_pseudo(insn->src));
 		break;
 	case OP_INLINED_CALL:
@@ -423,9 +438,13 @@
 		} END_FOR_EACH_PTR(arg);
 		break;
 	}
-	case OP_CAST:
-	case OP_SCAST:
-	case OP_FPCAST:
+	case OP_SEXT: case OP_ZEXT:
+	case OP_TRUNC:
+	case OP_FCVTU: case OP_FCVTS:
+	case OP_UCVTF: case OP_SCVTF:
+	case OP_FCVTF:
+	case OP_UTPTR:
+	case OP_PTRTU:
 	case OP_PTRCAST:
 		buf += sprintf(buf, "%s <- (%d) %s",
 			show_pseudo(insn->target),
@@ -433,6 +452,7 @@
 			show_pseudo(insn->src));
 		break;
 	case OP_BINARY ... OP_BINARY_END:
+	case OP_FPCMP ... OP_FPCMP_END:
 	case OP_BINCMP ... OP_BINCMP_END:
 		buf += sprintf(buf, "%s <- %s, %s", show_pseudo(insn->target), show_pseudo(insn->src1), show_pseudo(insn->src2));
 		break;
@@ -447,6 +467,8 @@
 		break;
 
 	case OP_NOT: case OP_NEG:
+	case OP_FNEG:
+	case OP_SYMADDR:
 		buf += sprintf(buf, "%s <- %s", show_pseudo(insn->target), show_pseudo(insn->src1));
 		break;
 
@@ -483,7 +505,7 @@
 {
 	struct instruction *insn;
 
-	printf(".L%u:\n", bb->nr);
+	printf("%s:\n", show_label(bb));
 	if (verbose) {
 		pseudo_t needs, defines;
 		printf("%s:%d\n", stream_name(bb->pos.stream), bb->pos.line);
@@ -491,7 +513,7 @@
 		FOR_EACH_PTR(bb->needs, needs) {
 			struct instruction *def = needs->def;
 			if (def->opcode != OP_PHI) {
-				printf("  **uses %s (from .L%u)**\n", show_pseudo(needs), def->bb->nr);
+				printf("  **uses %s (from %s)**\n", show_pseudo(needs), show_label(def->bb));
 			} else {
 				pseudo_t phi;
 				const char *sep = " ";
@@ -499,7 +521,7 @@
 				FOR_EACH_PTR(def->phi_list, phi) {
 					if (phi == VOID)
 						continue;
-					printf("%s(%s:.L%u)", sep, show_pseudo(phi), phi->def->bb->nr);
+					printf("%s(%s:%s)", sep, show_pseudo(phi), show_label(phi->def->bb));
 					sep = ", ";
 				} END_FOR_EACH_PTR(phi);		
 				printf(")**\n");
@@ -513,7 +535,7 @@
 		if (bb->parents) {
 			struct basic_block *from;
 			FOR_EACH_PTR(bb->parents, from) {
-				printf("  **from .L%u (%s:%d:%d)**\n", from->nr,
+				printf("  **from %s (%s:%d:%d)**\n", show_label(from),
 					stream_name(from->pos.stream), from->pos.line, from->pos.pos);
 			} END_FOR_EACH_PTR(from);
 		}
@@ -521,7 +543,7 @@
 		if (bb->children) {
 			struct basic_block *to;
 			FOR_EACH_PTR(bb->children, to) {
-				printf("  **to .L%u (%s:%d:%d)**\n", to->nr,
+				printf("  **to %s (%s:%d:%d)**\n", show_label(to),
 					stream_name(to->pos.stream), to->pos.line, to->pos.pos);
 			} END_FOR_EACH_PTR(to);
 		}
@@ -685,7 +707,7 @@
 	/* Remove the 'br' */
 	delete_last_instruction(&bb->insns);
 
-	select = alloc_instruction(OP_SEL, phi_node->size);
+	select = alloc_typed_instruction(OP_SEL, phi_node->type);
 	select->bb = bb;
 
 	assert(br->cond);
@@ -726,7 +748,7 @@
 	return bb;
 }
 
-static void add_branch(struct entrypoint *ep, struct expression *expr, pseudo_t cond, struct basic_block *bb_true, struct basic_block *bb_false)
+static void add_branch(struct entrypoint *ep, pseudo_t cond, struct basic_block *bb_true, struct basic_block *bb_false)
 {
 	struct basic_block *bb = ep->active;
 	struct instruction *br;
@@ -744,7 +766,6 @@
 	}
 }
 
-/* Dummy pseudo allocator */
 pseudo_t alloc_pseudo(struct instruction *def)
 {
 	static int nr = 0;
@@ -755,15 +776,6 @@
 	return pseudo;
 }
 
-static void clear_symbol_pseudos(struct entrypoint *ep)
-{
-	pseudo_t pseudo;
-
-	FOR_EACH_PTR(ep->accesses, pseudo) {
-		pseudo->sym->pseudo = NULL;
-	} END_FOR_EACH_PTR(pseudo);
-}
-
 static pseudo_t symbol_pseudo(struct entrypoint *ep, struct symbol *sym)
 {
 	pseudo_t pseudo;
@@ -781,22 +793,20 @@
 		sym->pseudo = pseudo;
 		add_pseudo(&ep->accesses, pseudo);
 	}
-	/* Symbol pseudos have neither nr, usage nor def */
+	/* Symbol pseudos have neither nr nor def */
 	return pseudo;
 }
 
-pseudo_t value_pseudo(struct symbol *type, long long val)
+pseudo_t value_pseudo(long long val)
 {
 #define MAX_VAL_HASH 64
 	static struct pseudo_list *prev[MAX_VAL_HASH];
 	int hash = val & (MAX_VAL_HASH-1);
 	struct pseudo_list **list = prev + hash;
-	int size = type ? type->bit_size : value_size(val);
 	pseudo_t pseudo;
 
-
 	FOR_EACH_PTR(*list, pseudo) {
-		if (pseudo->value == val && pseudo->size == size)
+		if (pseudo->value == val)
 			return pseudo;
 	} END_FOR_EACH_PTR(pseudo);
 
@@ -803,7 +813,6 @@
 	pseudo = __alloc_pseudo(0);
 	pseudo->type = PSEUDO_VAL;
 	pseudo->value = val;
-	pseudo->size = size;
 	add_pseudo(list, pseudo);
 
 	/* Value pseudos have neither nr, usage nor def */
@@ -810,6 +819,13 @@
 	return pseudo;
 }
 
+pseudo_t undef_pseudo(void)
+{
+	pseudo_t pseudo = __alloc_pseudo(0);
+	pseudo->type = PSEUDO_UNDEF;
+	return pseudo;
+}
+
 static pseudo_t argument_pseudo(struct entrypoint *ep, int nr)
 {
 	pseudo_t pseudo = __alloc_pseudo(0);
@@ -824,28 +840,70 @@
 	return pseudo;
 }
 
-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 *insn;
-	pseudo_t phi;
+	struct instruction *insn = alloc_typed_instruction(OP_PHISOURCE, type);
+	pseudo_t phi = __alloc_pseudo(0);
 	static int nr = 0;
 
-	if (!source)
-		return VOID;
-
-	insn = alloc_instruction(OP_PHISOURCE, size);
-	phi = __alloc_pseudo(0);
 	phi->type = PSEUDO_PHI;
 	phi->nr = ++nr;
 	phi->def = insn;
 
 	use_pseudo(insn, pseudo, &insn->phi_src);
-	insn->bb = source;
 	insn->target = phi;
+	return insn;
+}
+
+pseudo_t alloc_phi(struct basic_block *source, pseudo_t pseudo, struct symbol *type)
+{
+	struct instruction *insn;
+
+	if (!source)
+		return VOID;
+
+	insn = alloc_phisrc(pseudo, type);
+	insn->bb = source;
 	add_instruction(&source->insns, insn);
-	return phi;
+	return insn->target;
 }
 
+struct instruction *alloc_phi_node(struct basic_block *bb, struct symbol *type, struct ident *ident)
+{
+	struct instruction *phi_node = alloc_typed_instruction(OP_PHI, type);
+	pseudo_t phi;
+
+	phi = alloc_pseudo(phi_node);
+	phi->ident = ident;
+	phi->def = phi_node;
+	phi_node->target = phi;
+	phi_node->bb = bb;
+	return phi_node;
+}
+
+void add_phi_node(struct basic_block *bb, struct instruction *phi_node)
+{
+	struct instruction *insn;
+
+	FOR_EACH_PTR(bb->insns, insn) {
+		enum opcode op = insn->opcode;
+		if (op == OP_PHI)
+			continue;
+		INSERT_CURRENT(phi_node, insn);
+		return;
+	} END_FOR_EACH_PTR(insn);
+
+	// FIXME
+	add_instruction(&bb->insns, phi_node);
+}
+
+struct instruction *insert_phi_node(struct basic_block *bb, struct symbol *var)
+{
+	struct instruction *phi_node = alloc_phi_node(bb, var, var->ident);
+	add_phi_node(bb, phi_node);
+	return phi_node;
+}
+
 /*
  * We carry the "access_data" structure around for any accesses,
  * which simplifies things a lot. It contains all the access
@@ -852,17 +910,12 @@
  * information in one place.
  */
 struct access_data {
-	struct symbol *result_type;	// result ctype
-	struct symbol *source_type;	// source ctype
+	struct symbol *type;		// ctype
+	struct symbol *btype;		// base type of bitfields
 	pseudo_t address;		// pseudo containing address ..
 	unsigned int offset;		// byte offset
-	struct position pos;
 };
 
-static void finish_address_gen(struct entrypoint *ep, struct access_data *ad)
-{
-}
-
 static int linearize_simple_address(struct entrypoint *ep,
 	struct expression *addr,
 	struct access_data *ad)
@@ -884,7 +937,7 @@
 	return 1;
 }
 
-static struct symbol *base_type(struct symbol *sym)
+static struct symbol *bitfield_base_type(struct symbol *sym)
 {
 	struct symbol *base = sym;
 
@@ -905,9 +958,7 @@
 
 	if (!ctype)
 		return 0;
-	ad->pos = expr->pos;
-	ad->result_type = ctype;
-	ad->source_type = base_type(ctype);
+	ad->type = ctype;
 	if (expr->type == EXPR_PREOP && expr->op == '*')
 		return linearize_simple_address(ep, expr->unop, ad);
 
@@ -920,11 +971,15 @@
 	struct instruction *insn;
 	pseudo_t new;
 
-	insn = alloc_typed_instruction(OP_LOAD, ad->source_type);
+	if (!ep->active)
+		return VOID;
+
+	insn = alloc_typed_instruction(OP_LOAD, ad->btype);
 	new = alloc_pseudo(insn);
 
 	insn->target = new;
 	insn->offset = ad->offset;
+	insn->is_volatile = ad->type && (ad->type->ctype.modifiers & MOD_VOLATILE);
 	use_pseudo(insn, ad->address, &insn->src);
 	add_one_insn(ep, insn);
 	return new;
@@ -933,14 +988,36 @@
 static void add_store(struct entrypoint *ep, struct access_data *ad, pseudo_t value)
 {
 	struct basic_block *bb = ep->active;
+	struct instruction *store;
 
-	if (bb_reachable(bb)) {
-		struct instruction *store = alloc_typed_instruction(OP_STORE, ad->source_type);
-		store->offset = ad->offset;
-		use_pseudo(store, value, &store->target);
-		use_pseudo(store, ad->address, &store->src);
-		add_one_insn(ep, store);
+	if (!bb)
+		return;
+
+	store = alloc_typed_instruction(OP_STORE, ad->btype);
+	store->offset = ad->offset;
+	store->is_volatile = ad->type && (ad->type->ctype.modifiers & MOD_VOLATILE);
+	use_pseudo(store, value, &store->target);
+	use_pseudo(store, ad->address, &store->src);
+	add_one_insn(ep, store);
+}
+
+static pseudo_t linearize_bitfield_insert(struct entrypoint *ep,
+	pseudo_t ori, pseudo_t val, struct symbol *ctype, struct symbol *btype)
+{
+	unsigned int shift = ctype->bit_offset;
+	unsigned int size = ctype->bit_size;
+	unsigned long long mask = ((1ULL << size) - 1);
+	unsigned long long smask= bits_mask(btype->bit_size);
+
+	val = add_cast(ep, btype, ctype, OP_ZEXT, val);
+	if (shift) {
+		val = add_binary_op(ep, btype, OP_SHL, val, value_pseudo(shift));
+		mask <<= shift;
 	}
+	ori = add_binary_op(ep, btype, OP_AND, ori, value_pseudo(~mask & smask));
+	val = add_binary_op(ep, btype, OP_OR, ori, val);
+
+	return val;
 }
 
 static pseudo_t linearize_store_gen(struct entrypoint *ep,
@@ -947,26 +1024,39 @@
 		pseudo_t value,
 		struct access_data *ad)
 {
+	struct symbol *ctype = ad->type;
+	struct symbol *btype;
 	pseudo_t store = value;
 
-	if (type_size(ad->source_type) != type_size(ad->result_type)) {
-		struct symbol *ctype = ad->result_type;
-		unsigned int shift = ctype->bit_offset;
-		unsigned int size = ctype->bit_size;
-		pseudo_t orig = add_load(ep, ad);
-		unsigned long long mask = (1ULL << size) - 1;
+	if (!ep->active)
+		return VOID;
 
-		if (shift) {
-			store = add_binary_op(ep, ad->source_type, OP_SHL, value, value_pseudo(ctype, shift));
-			mask <<= shift;
-		}
-		orig = add_binary_op(ep, ad->source_type, OP_AND, orig, value_pseudo(ctype, ~mask));
-		store = add_binary_op(ep, ad->source_type, OP_OR, orig, store);
+	btype = ad->btype = bitfield_base_type(ctype);
+	if (type_size(btype) != type_size(ctype)) {
+		pseudo_t orig = add_load(ep, ad);
+		store = linearize_bitfield_insert(ep, orig, value, ctype, btype);
 	}
 	add_store(ep, ad, store);
 	return value;
 }
 
+static void taint_undefined_behaviour(struct instruction *insn)
+{
+	pseudo_t src2;
+
+	switch (insn->opcode) {
+	case OP_LSR:
+	case OP_ASR:
+	case OP_SHL:
+		src2 = insn->src2;
+		if (src2->type != PSEUDO_VAL)
+			break;
+		if ((unsigned long long)src2->value >= insn->size)
+			insn->tainted = 1;
+		break;
+	}
+}
+
 static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right)
 {
 	struct instruction *insn = alloc_typed_instruction(op, ctype);
@@ -988,6 +1078,16 @@
 	return target;
 }
 
+static pseudo_t add_setfval(struct entrypoint *ep, struct symbol *ctype, long double fval)
+{
+	struct instruction *insn = alloc_typed_instruction(OP_SETFVAL, ctype);
+	pseudo_t target = alloc_pseudo(insn);
+	insn->target = target;
+	insn->fvalue = fval;
+	add_one_insn(ep, insn);
+	return target;
+}
+
 static pseudo_t add_symbol_address(struct entrypoint *ep, struct symbol *sym)
 {
 	struct instruction *insn = alloc_instruction(OP_SYMADDR, bits_in_pointer);
@@ -994,23 +1094,37 @@
 	pseudo_t target = alloc_pseudo(insn);
 
 	insn->target = target;
-	use_pseudo(insn, symbol_pseudo(ep, sym), &insn->symbol);
+	use_pseudo(insn, symbol_pseudo(ep, sym), &insn->src);
 	add_one_insn(ep, insn);
 	return target;
 }
 
-static pseudo_t linearize_load_gen(struct entrypoint *ep, struct access_data *ad)
+static pseudo_t linearize_bitfield_extract(struct entrypoint *ep,
+		pseudo_t val, struct symbol *ctype, struct symbol *btype)
 {
-	struct symbol *ctype = ad->result_type;
-	pseudo_t new = add_load(ep, ad);
+	unsigned int off = ctype->bit_offset;
 
-	if (ctype->bit_offset) {
-		pseudo_t shift = value_pseudo(ctype, ctype->bit_offset);
-		pseudo_t newval = add_binary_op(ep, ad->source_type, OP_LSR, new, shift);
-		new = newval;
+	if (off) {
+		pseudo_t shift = value_pseudo(off);
+		val = add_binary_op(ep, btype, OP_LSR, val, shift);
 	}
-	if (ctype->bit_size != type_size(ad->source_type))
-		new = cast_pseudo(ep, new, ad->source_type, ad->result_type);
+	val = cast_pseudo(ep, val, btype, ctype);
+	return val;
+}
+
+static pseudo_t linearize_load_gen(struct entrypoint *ep, struct access_data *ad)
+{
+	struct symbol *ctype = ad->type;
+	struct symbol *btype;
+	pseudo_t new;
+
+	if (!ep->active)
+		return VOID;
+
+	btype = ad->btype = bitfield_base_type(ctype);
+	new = add_load(ep, ad);
+	if (ctype->bit_size != type_size(btype))
+		new = linearize_bitfield_extract(ep, new, ctype, btype);
 	return new;
 }
 
@@ -1022,15 +1136,13 @@
 	if (!linearize_address_gen(ep, expr, &ad))
 		return VOID;
 	value = linearize_load_gen(ep, &ad);
-	finish_address_gen(ep, &ad);
 	return value;
 }
 
-/* FIXME: FP */
 static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr, int postop)
 {
 	struct access_data ad = { NULL, };
-		pseudo_t old, new, one;
+	pseudo_t old, new, one;
 	int op = expr->op == SPECIAL_INCREMENT ? OP_ADD : OP_SUB;
 
 	if (!linearize_address_gen(ep, expr->unop, &ad))
@@ -1037,16 +1149,23 @@
 		return VOID;
 
 	old = linearize_load_gen(ep, &ad);
-	one = value_pseudo(expr->ctype, expr->op_value);
-	new = add_binary_op(ep, expr->ctype, op, old, one);
+	op = opcode_float(op, expr->ctype);
+	if (is_float_type(expr->ctype))
+		one = add_setfval(ep, expr->ctype, expr->op_value);
+	else
+		one = value_pseudo(expr->op_value);
+	if (ad.btype != ad.type)
+		old = cast_pseudo(ep, old, ad.type, ad.btype);
+	new = add_binary_op(ep, ad.btype, op, old, one);
+	if (ad.btype != ad.type)
+		new = cast_pseudo(ep, new, ad.btype, ad.type);
 	linearize_store_gen(ep, new, &ad);
-	finish_address_gen(ep, &ad);
 	return postop ? old : new;
 }
 
-static pseudo_t add_uniop(struct entrypoint *ep, struct expression *expr, int op, pseudo_t src)
+static pseudo_t add_unop(struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t src)
 {
-	struct instruction *insn = alloc_typed_instruction(op, expr->ctype);
+	struct instruction *insn = alloc_typed_instruction(op, ctype);
 	pseudo_t new = alloc_pseudo(insn);
 
 	insn->target = new;
@@ -1055,6 +1174,14 @@
 	return new;
 }
 
+static pseudo_t add_cast(struct entrypoint *ep, struct symbol *to,
+			 struct symbol *from, int op, pseudo_t src)
+{
+	pseudo_t new = add_unop(ep, to, op, src);
+	new->def->orig_type = from;
+	return new;
+}
+
 static pseudo_t linearize_slice(struct entrypoint *ep, struct expression *expr)
 {
 	pseudo_t pre = linearize_expression(ep, expr->base);
@@ -1072,17 +1199,18 @@
 static pseudo_t linearize_regular_preop(struct entrypoint *ep, struct expression *expr)
 {
 	pseudo_t pre = linearize_expression(ep, expr->unop);
+	struct symbol *ctype = expr->ctype;
 	switch (expr->op) {
 	case '+':
 		return pre;
 	case '!': {
-		pseudo_t zero = value_pseudo(expr->ctype, 0);
-		return add_binary_op(ep, expr->ctype, OP_SET_EQ, pre, zero);
+		pseudo_t zero = value_pseudo(0);
+		return add_binary_op(ep, ctype, OP_SET_EQ, pre, zero);
 	}
 	case '~':
-		return add_uniop(ep, expr, OP_NOT, pre);
+		return add_unop(ep, ctype, OP_NOT, pre);
 	case '-':
-		return add_uniop(ep, expr, OP_NEG, pre);
+		return add_unop(ep, ctype, opcode_float(OP_NEG, ctype), pre);
 	}
 	return VOID;
 }
@@ -1112,28 +1240,125 @@
  * case, since you can't access through it anyway without another
  * cast.
  */
-static struct instruction *alloc_cast_instruction(struct symbol *src, struct symbol *ctype)
+enum mtype {
+	MTYPE_UINT,
+	MTYPE_SINT,
+	MTYPE_PTR,
+	MTYPE_VPTR,	// TODO: must be removed ?
+	MTYPE_FLOAT,
+	MTYPE_BAD,
+};
+
+static enum mtype get_mtype(struct symbol *s)
 {
-	int opcode = OP_CAST;
-	struct symbol *base = ctype;
+	int sign = (s->ctype.modifiers & MOD_SIGNED) ? 1 : 0;
 
-	if (src->ctype.modifiers & MOD_SIGNED)
-		opcode = OP_SCAST;
-	if (base->type == SYM_NODE)
-		base = base->ctype.base_type;
-	if (base->type == SYM_PTR) {
-		base = base->ctype.base_type;
-		if (base != &void_ctype)
-			opcode = OP_PTRCAST;
-	} else if (base->ctype.base_type == &fp_type)
-		opcode = OP_FPCAST;
-	return alloc_typed_instruction(opcode, ctype);
+retry:	switch (s->type) {
+	case SYM_NODE:
+		s = s->ctype.base_type;
+		goto retry;
+	case SYM_PTR:
+		if (s->ctype.base_type == &void_ctype)
+			return MTYPE_VPTR;
+		return MTYPE_PTR;
+	case SYM_BITFIELD:
+	case SYM_RESTRICT:
+	case SYM_FOULED:
+	case SYM_ENUM:
+		s = s->ctype.base_type;
+		/* fall-through */
+	case_int:
+		return sign ? MTYPE_SINT : MTYPE_UINT;
+	case SYM_BASETYPE:
+		if (s->ctype.base_type == &fp_type)
+			return MTYPE_FLOAT;
+		if (s->ctype.base_type == &int_type)
+			goto case_int;
+		/* fall-through */
+	default:
+		return MTYPE_BAD;
+	}
 }
 
+static int get_cast_opcode(struct symbol *dst, struct symbol *src)
+{
+	enum mtype stype = get_mtype(src);
+	enum mtype dtype = get_mtype(dst);
+
+	switch (dtype) {
+	case MTYPE_FLOAT:
+		switch (stype) {
+		case MTYPE_FLOAT:
+			if (dst->bit_size == src->bit_size)
+				return OP_NOP;
+			return OP_FCVTF;
+		case MTYPE_UINT:
+			return OP_UCVTF;
+		case MTYPE_SINT:
+			return OP_SCVTF;
+		default:
+			return OP_BADOP;
+		}
+	case MTYPE_PTR:
+		switch (stype) {
+		case MTYPE_UINT:
+		case MTYPE_SINT:
+			return OP_UTPTR;
+		case MTYPE_PTR:
+		case MTYPE_VPTR:
+			return OP_PTRCAST;
+		default:
+			return OP_BADOP;
+		}
+	case MTYPE_VPTR:
+		switch (stype) {
+		case MTYPE_PTR:
+		case MTYPE_VPTR:
+		case MTYPE_UINT:
+			stype = MTYPE_UINT;
+			/* fall through */
+		case MTYPE_SINT:
+			break;
+		default:
+			return OP_BADOP;
+		}
+		/* fall through */
+	case MTYPE_UINT:
+	case MTYPE_SINT:
+		switch (stype) {
+		case MTYPE_FLOAT:
+			return dtype == MTYPE_UINT ? OP_FCVTU : OP_FCVTS;
+		case MTYPE_PTR:
+			return OP_PTRTU;
+		case MTYPE_VPTR:
+		case MTYPE_UINT:
+		case MTYPE_SINT:
+			if (dst->bit_size ==src->bit_size)
+				return OP_NOP;
+			if (dst->bit_size  < src->bit_size)
+				return OP_TRUNC;
+			return stype == MTYPE_SINT ? OP_SEXT : OP_ZEXT;
+		default:
+			return OP_BADOP;
+		}
+		/* fall through */
+	default:
+		if (src->type == SYM_NODE)
+			src = src->ctype.base_type;
+		if (dst->type == SYM_NODE)
+			dst = dst->ctype.base_type;
+		if (src == dst)
+			return OP_NOP;
+		return OP_BADOP;
+	}
+}
+
 static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol *from, struct symbol *to)
 {
+	const struct position pos = current_pos;
 	pseudo_t result;
 	struct instruction *insn;
+	int opcode;
 
 	if (src == VOID)
 		return VOID;
@@ -1141,7 +1366,33 @@
 		return VOID;
 	if (from->bit_size < 0 || to->bit_size < 0)
 		return VOID;
-	insn = alloc_cast_instruction(from, to);
+	opcode = get_cast_opcode(to, from);
+	switch (opcode) {
+	case OP_NOP:
+		return src;
+	case OP_UTPTR:
+		if (from->bit_size == to->bit_size)
+			break;
+		if (src == value_pseudo(0))
+			break;
+		if (Wint_to_pointer_cast)
+			warning(pos, "non size-preserving integer to pointer cast");
+		src = cast_pseudo(ep, src, from, size_t_ctype);
+		from = size_t_ctype;
+		break;
+	case OP_PTRTU:
+		if (from->bit_size == to->bit_size)
+			break;
+		if (Wpointer_to_int_cast)
+			warning(pos, "non size-preserving pointer to integer cast");
+		src = cast_pseudo(ep, src, from, size_t_ctype);
+		return cast_pseudo(ep, src, size_t_ctype, to);
+	case OP_BADOP:
+		return VOID;
+	default:
+		break;
+	}
+	insn = alloc_typed_instruction(opcode, to);
 	result = alloc_pseudo(insn);
 	insn->target = result;
 	insn->orig_type = from;
@@ -1150,11 +1401,13 @@
 	return result;
 }
 
-static int opcode_sign(int opcode, struct symbol *ctype)
+static int map_opcode(int opcode, struct symbol *ctype)
 {
+	if (ctype && is_float_type(ctype))
+		return opcode_table[opcode].to_float;
 	if (ctype && (ctype->ctype.modifiers & MOD_SIGNED)) {
 		switch(opcode) {
-		case OP_MULU: case OP_DIVU: case OP_MODU: case OP_LSR:
+		case OP_DIVU: case OP_MODU: case OP_LSR:
 			opcode++;
 		}
 	}
@@ -1166,10 +1419,19 @@
 	pseudo_t zero;
 	int op;
 
+	if (!type || src == VOID)
+		return VOID;
 	if (is_bool_type(type))
 		return src;
-	zero = value_pseudo(type, 0);
-	op = OP_SET_NE;
+	if (src->type == PSEUDO_VAL && (src->value == 0 || src->value == 1))
+		return src;
+	if (is_float_type(type)) {
+		zero = add_setfval(ep, type, 0.0);
+		op = map_opcode(OP_SET_NE, type);
+	} else {
+		zero = value_pseudo(0);
+		op = OP_SET_NE;
+	}
 	return add_binary_op(ep, &bool_ctype, op, src, zero);
 }
 
@@ -1198,7 +1460,7 @@
 		static const int op_trans[] = {
 			[SPECIAL_ADD_ASSIGN - SPECIAL_BASE] = OP_ADD,
 			[SPECIAL_SUB_ASSIGN - SPECIAL_BASE] = OP_SUB,
-			[SPECIAL_MUL_ASSIGN - SPECIAL_BASE] = OP_MULU,
+			[SPECIAL_MUL_ASSIGN - SPECIAL_BASE] = OP_MUL,
 			[SPECIAL_DIV_ASSIGN - SPECIAL_BASE] = OP_DIVU,
 			[SPECIAL_MOD_ASSIGN - SPECIAL_BASE] = OP_MODU,
 			[SPECIAL_SHL_ASSIGN - SPECIAL_BASE] = OP_SHL,
@@ -1214,12 +1476,12 @@
 
 		ctype = src->ctype;
 		oldvalue = cast_pseudo(ep, oldvalue, target->ctype, ctype);
-		opcode = opcode_sign(op_trans[expr->op - SPECIAL_BASE], ctype);
+		opcode = map_opcode(op_trans[expr->op - SPECIAL_BASE], ctype);
 		dst = add_binary_op(ep, ctype, opcode, oldvalue, value);
+		taint_undefined_behaviour(dst->def);
 		value = cast_pseudo(ep, dst, ctype, expr->ctype);
 	}
 	value = linearize_store_gen(ep, value, &ad);
-	finish_address_gen(ep, &ad);
 	return value;
 }
 
@@ -1232,35 +1494,25 @@
 	struct symbol *fntype;
 	struct context *context;
 
-	if (!expr->ctype) {
-		warning(expr->pos, "call with no type!");
+	if (!expr->ctype)
 		return VOID;
-	}
 
+	fn = expr->fn;
+	fntype = fn->ctype;
+	ctype = &fntype->ctype;
+	if (fntype->type == SYM_NODE)
+		fntype = fntype->ctype.base_type;
+
+	add_symbol(&insn->fntypes, fntype);
 	FOR_EACH_PTR(expr->args, arg) {
 		pseudo_t new = linearize_expression(ep, arg);
 		use_pseudo(insn, new, add_pseudo(&insn->arguments, new));
+		add_symbol(&insn->fntypes, arg->ctype);
 	} END_FOR_EACH_PTR(arg);
 
-	fn = expr->fn;
+	if (fn->type == EXPR_PREOP && fn->op == '*' && is_func_type(fn->ctype))
+		fn = fn->unop;
 
-	if (fn->ctype)
-		ctype = &fn->ctype->ctype;
-
-	fntype = fn->ctype;
-	if (fntype) {
-		if (fntype->type == SYM_NODE)
-			fntype = fntype->ctype.base_type;
-	}
-	insn->fntype = fntype;
-
-	if (fn->type == EXPR_PREOP) {
-		if (fn->unop->type == EXPR_SYMBOL) {
-			struct symbol *sym = fn->unop->symbol;
-			if (sym->ctype.base_type->type == SYM_FN)
-				fn = fn->unop;
-		}
-	}
 	if (fn->type == EXPR_SYMBOL) {
 		call = symbol_pseudo(ep, fn->symbol);
 	} else {
@@ -1304,7 +1556,7 @@
 static pseudo_t linearize_binop_bool(struct entrypoint *ep, struct expression *expr)
 {
 	pseudo_t src1, src2, dst;
-	int op = (expr->op == SPECIAL_LOGICAL_OR) ? OP_OR_BOOL : OP_AND_BOOL;
+	int op = (expr->op == SPECIAL_LOGICAL_OR) ? OP_OR : OP_AND;
 
 	src1 = linearize_expression_to_bool(ep, expr->left);
 	src2 = linearize_expression_to_bool(ep, expr->right);
@@ -1319,7 +1571,7 @@
 	pseudo_t src1, src2, dst;
 	static const int opcode[] = {
 		['+'] = OP_ADD, ['-'] = OP_SUB,
-		['*'] = OP_MULU, ['/'] = OP_DIVU,
+		['*'] = OP_MUL, ['/'] = OP_DIVU,
 		['%'] = OP_MODU, ['&'] = OP_AND,
 		['|'] = OP_OR,  ['^'] = OP_XOR,
 		[SPECIAL_LEFTSHIFT] = OP_SHL,
@@ -1329,30 +1581,31 @@
 
 	src1 = linearize_expression(ep, expr->left);
 	src2 = linearize_expression(ep, expr->right);
-	op = opcode_sign(opcode[expr->op], expr->ctype);
+	op = map_opcode(opcode[expr->op], expr->ctype);
 	dst = add_binary_op(ep, expr->ctype, op, src1, src2);
+	taint_undefined_behaviour(dst->def);
 	return dst;
 }
 
 static pseudo_t linearize_logical_branch(struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false);
 
-pseudo_t linearize_cond_branch(struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false);
+static pseudo_t linearize_cond_branch(struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false);
 
 static pseudo_t linearize_select(struct entrypoint *ep, struct expression *expr)
 {
-	pseudo_t cond, true, false, res;
+	pseudo_t cond, valt, valf, res;
 	struct instruction *insn;
 
-	true = linearize_expression(ep, expr->cond_true);
-	false = linearize_expression(ep, expr->cond_false);
+	valt = linearize_expression(ep, expr->cond_true);
+	valf = linearize_expression(ep, expr->cond_false);
 	cond = linearize_expression(ep, expr->conditional);
 
 	insn = alloc_typed_instruction(OP_SEL, expr->ctype);
 	if (!expr->cond_true)
-		true = cond;
+		valt = cond;
 	use_pseudo(insn, cond, &insn->src1);
-	use_pseudo(insn, true, &insn->src2);
-	use_pseudo(insn, false, &insn->src3);
+	use_pseudo(insn, valt, &insn->src2);
+	use_pseudo(insn, valf, &insn->src3);
 
 	res = alloc_pseudo(insn);
 	insn->target = res;
@@ -1385,21 +1638,22 @@
 {
 	pseudo_t src1, src2;
 	struct basic_block *bb_false;
-	struct basic_block *merge = alloc_basic_block(ep, expr->pos);
+	struct basic_block *merge;
 	pseudo_t phi1, phi2;
-	int size = type_size(expr->ctype);
 
 	if (!expr_false || !ep->active)
 		return VOID;
 
 	bb_false = alloc_basic_block(ep, expr_false->pos);
+	merge = alloc_basic_block(ep, expr->pos);
+
 	src1 = linearize_expression(ep, cond);
-	phi1 = alloc_phi(ep->active, src1, size);
-	add_branch(ep, expr, src1, merge, bb_false);
+	phi1 = alloc_phi(ep->active, src1, expr->ctype);
+	add_branch(ep, src1, merge, bb_false);
 
 	set_activeblock(ep, bb_false);
 	src2 = linearize_expression(ep, expr_false);
-	phi2 = alloc_phi(ep->active, src2, size);
+	phi2 = alloc_phi(ep->active, src2, expr->ctype);
 	set_activeblock(ep, merge);
 
 	return add_join_conditional(ep, expr, phi1, phi2);
@@ -1413,7 +1667,6 @@
 	pseudo_t src1, src2;
 	pseudo_t phi1, phi2;
 	struct basic_block *bb_true, *bb_false, *merge;
-	int size = type_size(expr->ctype);
 
 	if (!cond || !expr_true || !expr_false || !ep->active)
 		return VOID;
@@ -1425,26 +1678,65 @@
 
 	set_activeblock(ep, bb_true);
 	src1 = linearize_expression(ep, expr_true);
-	phi1 = alloc_phi(ep->active, src1, size);
+	phi1 = alloc_phi(ep->active, src1, expr->ctype);
 	add_goto(ep, merge); 
 
 	set_activeblock(ep, bb_false);
 	src2 = linearize_expression(ep, expr_false);
-	phi2 = alloc_phi(ep->active, src2, size);
+	phi2 = alloc_phi(ep->active, src2, expr->ctype);
 	set_activeblock(ep, merge);
 
 	return add_join_conditional(ep, expr, phi1, phi2);
 }
 
+static void insert_phis(struct basic_block *bb, pseudo_t src, struct symbol *ctype,
+	struct instruction *node)
+{
+	struct basic_block *parent;
+
+	FOR_EACH_PTR(bb->parents, parent) {
+		struct instruction *br = delete_last_instruction(&parent->insns);
+		pseudo_t phi = alloc_phi(parent, src, ctype);
+		add_instruction(&parent->insns, br);
+		use_pseudo(node, phi, add_pseudo(&node->phi_list, phi));
+	} END_FOR_EACH_PTR(parent);
+}
+
 static pseudo_t linearize_logical(struct entrypoint *ep, struct expression *expr)
 {
-	struct expression *shortcut;
+	struct symbol *ctype = expr->ctype;
+	struct basic_block *other, *merge;
+	struct instruction *node;
+	pseudo_t src1, src2, phi2;
 
-	shortcut = alloc_const_expression(expr->pos, expr->op == SPECIAL_LOGICAL_OR);
-	shortcut->ctype = expr->ctype;
-	if (expr->op == SPECIAL_LOGICAL_OR)
-		return linearize_conditional(ep, expr, expr->left, shortcut, expr->right);
-	return linearize_conditional(ep, expr, expr->left, expr->right, shortcut);
+	if (!ep->active || !expr->left || !expr->right)
+		return VOID;
+
+	other = alloc_basic_block(ep, expr->right->pos);
+	merge = alloc_basic_block(ep, expr->pos);
+	node = alloc_phi_node(merge, ctype, NULL);
+
+	// LHS and its shortcut
+	if (expr->op == SPECIAL_LOGICAL_OR) {
+		linearize_cond_branch(ep, expr->left, merge, other);
+		src1 = value_pseudo(1);
+	} else {
+		linearize_cond_branch(ep, expr->left, other, merge);
+		src1 = value_pseudo(0);
+	}
+	insert_phis(merge, src1, ctype, node);
+
+	// RHS
+	set_activeblock(ep, other);
+	src2 = linearize_expression_to_bool(ep, expr->right);
+	src2 = cast_pseudo(ep, src2, &bool_ctype, ctype);
+	phi2 = alloc_phi(ep->active, src2, ctype);
+	use_pseudo(node, phi2, add_pseudo(&node->phi_list, phi2));
+
+	// join
+	set_activeblock(ep, merge);
+	add_instruction(&merge->insns, node);
+	return node->target;
 }
 
 static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr)
@@ -1460,15 +1752,15 @@
 		[SPECIAL_UNSIGNED_LTE] = OP_SET_BE,
 		[SPECIAL_UNSIGNED_GTE] = OP_SET_AE,
 	};
-
+	int op = opcode_float(cmpop[expr->op], expr->right->ctype);
 	pseudo_t src1 = linearize_expression(ep, expr->left);
 	pseudo_t src2 = linearize_expression(ep, expr->right);
-	pseudo_t dst = add_binary_op(ep, expr->ctype, cmpop[expr->op], src1, src2);
+	pseudo_t dst = add_binary_op(ep, expr->ctype, op, src1, src2);
 	return dst;
 }
 
 
-pseudo_t linearize_cond_branch(struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false)
+static pseudo_t linearize_cond_branch(struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false)
 {
 	pseudo_t cond;
 
@@ -1492,7 +1784,7 @@
 
 	case EXPR_COMPARE:
 		cond = linearize_compare(ep, expr);
-		add_branch(ep, expr, cond, bb_true, bb_false);
+		add_branch(ep, cond, bb_true, bb_false);
 		break;
 		
 	case EXPR_PREOP:
@@ -1500,8 +1792,8 @@
 			return linearize_cond_branch(ep, expr->unop, bb_false, bb_true);
 		/* fall through */
 	default: {
-		cond = linearize_expression(ep, expr);
-		add_branch(ep, expr, cond, bb_true, bb_false);
+		cond = linearize_expression_to_bool(ep, expr);
+		add_branch(ep, cond, bb_true, bb_false);
 
 		return VOID;
 	}
@@ -1536,16 +1828,6 @@
 	return cast_pseudo(ep, src, orig->ctype, expr->ctype);
 }
 
-static pseudo_t linearize_position(struct entrypoint *ep, struct expression *pos, struct access_data *ad)
-{
-	struct expression *init_expr = pos->init_expr;
-
-	ad->offset = pos->init_offset;
-	ad->source_type = base_type(init_expr->ctype);
-	ad->result_type = init_expr->ctype;
-	return linearize_initializer(ep, init_expr, ad);
-}
-
 static pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *ad)
 {
 	switch (initializer->type) {
@@ -1557,12 +1839,12 @@
 		break;
 	}
 	case EXPR_POS:
-		linearize_position(ep, initializer, ad);
+		ad->offset = initializer->init_offset;
+		linearize_initializer(ep, initializer->init_expr, ad);
 		break;
 	default: {
 		pseudo_t value = linearize_expression(ep, initializer);
-		ad->source_type = base_type(initializer->ctype);
-		ad->result_type = initializer->ctype;
+		ad->type = initializer->ctype;
 		linearize_store_gen(ep, value, ad);
 		return value;
 	}
@@ -1575,14 +1857,12 @@
 {
 	struct access_data ad = { NULL, };
 
-	ad.source_type = arg;
-	ad.result_type = arg;
+	ad.type = arg;
 	ad.address = symbol_pseudo(ep, arg);
 	linearize_store_gen(ep, argument_pseudo(ep, nr), &ad);
-	finish_address_gen(ep, &ad);
 }
 
-pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr)
+static pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr)
 {
 	if (!expr)
 		return VOID;
@@ -1594,11 +1874,15 @@
 		return add_symbol_address(ep, expr->symbol);
 
 	case EXPR_VALUE:
-		return value_pseudo(expr->ctype, expr->value);
+		return value_pseudo(expr->value);
 
-	case EXPR_STRING: case EXPR_FVALUE: case EXPR_LABEL:
+	case EXPR_STRING:
+	case EXPR_LABEL:
 		return add_setval(ep, expr->ctype, expr);
 
+	case EXPR_FVALUE:
+		return add_setfval(ep, expr->ctype, expr->fvalue);
+
 	case EXPR_STATEMENT:
 		return linearize_statement(ep, expr->statement);
 
@@ -1679,16 +1963,12 @@
 		// only the existing fields need to be initialized.
 		// FIXME: this init the whole aggregate even if
 		// all fields arelater  explicitely initialized.
-		struct expression *expr = sym->initializer;
-		ad.pos = expr->pos;
-		ad.result_type = sym;
-		ad.source_type = base_type(sym);
+		ad.type = sym;
 		ad.address = symbol_pseudo(ep, sym);
-		linearize_store_gen(ep, value_pseudo(sym, 0), &ad);
+		linearize_store_gen(ep, value_pseudo(0), &ad);
 	}
 
 	value = linearize_initializer(ep, sym->initializer, &ad);
-	finish_address_gen(ep, &ad);
 	return value;
 }
 
@@ -1696,7 +1976,6 @@
 {
 	pseudo_t pseudo;
 	struct statement *s;
-	struct symbol *ret = stmt->ret;
 
 	pseudo = VOID;
 	FOR_EACH_PTR(stmt->stmts, s) {
@@ -1703,21 +1982,43 @@
 		pseudo = linearize_statement(ep, s);
 	} END_FOR_EACH_PTR(s);
 
-	if (ret) {
-		struct basic_block *bb = add_label(ep, ret);
-		struct instruction *phi_node = first_instruction(bb->insns);
+	return pseudo;
+}
 
-		if (!phi_node)
-			return pseudo;
+static void add_return(struct entrypoint *ep, struct basic_block *bb, struct symbol *ctype, pseudo_t src)
+{
+	struct instruction *phi_node = first_instruction(bb->insns);
+	pseudo_t phi;
+	if (!phi_node) {
+		phi_node = alloc_typed_instruction(OP_PHI, ctype);
+		phi_node->target = alloc_pseudo(phi_node);
+		phi_node->bb = bb;
+		add_instruction(&bb->insns, phi_node);
+	}
+	phi = alloc_phi(ep->active, src, ctype);
+	phi->ident = &return_ident;
+	use_pseudo(phi_node, phi, add_pseudo(&phi_node->phi_list, phi));
+}
 
-		if (pseudo_list_size(phi_node->phi_list)==1) {
-			pseudo = first_pseudo(phi_node->phi_list);
-			assert(pseudo->type == PSEUDO_PHI);
-			return pseudo->def->src1;
+static pseudo_t linearize_fn_statement(struct entrypoint *ep, struct statement *stmt)
+{
+	struct instruction *phi_node;
+	struct basic_block *bb;
+	pseudo_t pseudo;
+
+	pseudo = linearize_compound_statement(ep, stmt);
+	if (!is_void_type(stmt->ret)) {			// non-void function
+		struct basic_block *active = ep->active;
+		if (active && !bb_terminated(active)) {	// missing return
+			struct basic_block *bb_ret;
+			bb_ret = get_bound_block(ep, stmt->ret);
+			add_return(ep, bb_ret, stmt->ret, undef_pseudo());
 		}
-		return phi_node->target;
 	}
-
+	bb = add_label(ep, stmt->ret);
+	phi_node = first_instruction(bb->insns);
+	if (phi_node)
+		pseudo = phi_node->target;
 	return pseudo;
 }
 
@@ -1734,14 +2035,16 @@
 		concat_symbol_list(args->declaration, &ep->syms);
 		FOR_EACH_PTR(args->declaration, sym) {
 			pseudo_t value = linearize_one_symbol(ep, sym);
-			use_pseudo(insn, value, add_pseudo(&insn->arguments, value));
+			add_pseudo(&insn->arguments, value);
 		} END_FOR_EACH_PTR(sym);
 	}
 
-	insn->target = pseudo = linearize_compound_statement(ep, stmt);
+	pseudo = linearize_fn_statement(ep, stmt);
+	insn->target = pseudo;
+
 	use_pseudo(insn, symbol_pseudo(ep, stmt->inline_fn), &insn->func);
 	bb = ep->active;
-	if (bb && !bb->insns)
+	if (!bb->insns)
 		bb->pos = stmt->pos;
 	add_one_insn(ep, insn);
 	return pseudo;
@@ -1751,12 +2054,8 @@
 {
 	struct instruction *insn = alloc_instruction(OP_CONTEXT, 0);
 	struct expression *expr = stmt->expression;
-	int value = 0;
 
-	if (expr->type == EXPR_VALUE)
-		value = expr->value;
-
-	insn->increment = value;
+	insn->increment = get_expression_value(expr);
 	insn->context_expr = stmt->context;
 	add_one_insn(ep, insn);
 	return VOID;
@@ -1798,7 +2097,6 @@
 	if (!expr || !linearize_address_gen(ep, expr, &ad))
 		return;
 	linearize_store_gen(ep, pseudo, &ad);
-	finish_address_gen(ep, &ad);
 	rule = __alloc_asm_constraint(0);
 	rule->ident = ident;
 	rule->constraint = constraint;
@@ -1808,12 +2106,10 @@
 
 static pseudo_t linearize_asm_statement(struct entrypoint *ep, struct statement *stmt)
 {
-	int state;
 	struct expression *expr;
 	struct instruction *insn;
 	struct asm_rules *rules;
 	const char *constraint;
-	struct ident *ident;
 
 	insn = alloc_instruction(OP_ASM, 0);
 	expr = stmt->asm_string;
@@ -1827,49 +2123,17 @@
 	insn->asm_rules = rules;
 
 	/* Gather the inputs.. */
-	state = 0;
-	ident = NULL;
-	constraint = NULL;
 	FOR_EACH_PTR(stmt->asm_inputs, expr) {
-		switch (state) {
-		case 0:	/* Identifier */
-			state = 1;
-			ident = (struct ident *)expr;
-			continue;
-
-		case 1:	/* Constraint */
-			state = 2;
-			constraint = expr ? expr->string->data : "";
-			continue;
-
-		case 2:	/* Expression */
-			state = 0;
-			add_asm_input(ep, insn, expr, constraint, ident);
-		}
+		constraint = expr->constraint ? expr->constraint->string->data : "";
+		add_asm_input(ep, insn, expr->expr, constraint, expr->name);
 	} END_FOR_EACH_PTR(expr);
 
 	add_one_insn(ep, insn);
 
 	/* Assign the outputs */
-	state = 0;
-	ident = NULL;
-	constraint = NULL;
 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
-		switch (state) {
-		case 0:	/* Identifier */
-			state = 1;
-			ident = (struct ident *)expr;
-			continue;
-
-		case 1:	/* Constraint */
-			state = 2;
-			constraint = expr ? expr->string->data : "";
-			continue;
-
-		case 2:
-			state = 0;
-			add_asm_output(ep, insn, expr, constraint, ident);
-		}
+		constraint = expr->constraint ? expr->constraint->string->data : "";
+		add_asm_output(ep, insn, expr->expr, constraint, expr->name);
 	} END_FOR_EACH_PTR(expr);
 
 	return VOID;
@@ -1916,22 +2180,13 @@
 static pseudo_t linearize_return(struct entrypoint *ep, struct statement *stmt)
 {
 	struct expression *expr = stmt->expression;
-	struct basic_block *bb_return = get_bound_block(ep, stmt->ret_target);
+	struct symbol *ret = stmt->ret_target;
+	struct basic_block *bb_return = get_bound_block(ep, ret);
 	struct basic_block *active;
 	pseudo_t src = linearize_expression(ep, expr);
 	active = ep->active;
-	if (active && src != VOID) {
-		struct instruction *phi_node = first_instruction(bb_return->insns);
-		pseudo_t phi;
-		if (!phi_node) {
-			phi_node = alloc_typed_instruction(OP_PHI, expr->ctype);
-			phi_node->target = alloc_pseudo(phi_node);
-			phi_node->bb = bb_return;
-			add_instruction(&bb_return->insns, phi_node);
-		}
-		phi = alloc_phi(active, src, type_size(expr->ctype));
-		phi->ident = &return_ident;
-		use_pseudo(phi_node, phi, add_pseudo(&phi_node->phi_list, phi));
+	if (active && !is_void_type(ret)) {
+		add_return(ep, bb_return, ret, src);
 	}
 	add_goto(ep, bb_return);
 	return VOID;
@@ -1943,16 +2198,20 @@
 	struct instruction *switch_ins;
 	struct basic_block *switch_end = alloc_basic_block(ep, stmt->pos);
 	struct basic_block *active, *default_case;
+	struct expression *expr = stmt->switch_expression;
 	struct multijmp *jmp;
 	pseudo_t pseudo;
 
-	pseudo = linearize_expression(ep, stmt->switch_expression);
-
-	active = ep->active;
-	if (!bb_reachable(active))
+	if (!expr || !expr->ctype)
 		return VOID;
+	pseudo = linearize_expression(ep, expr);
+	active = ep->active;
+	if (!active) {
+		active = alloc_basic_block(ep, stmt->pos);
+		set_activeblock(ep, active);
+	}
 
-	switch_ins = alloc_instruction(OP_SWITCH, 0);
+	switch_ins = alloc_typed_instruction(OP_SWITCH, expr->ctype);
 	use_pseudo(switch_ins, pseudo, &switch_ins->cond);
 	add_one_insn(ep, switch_ins);
 	finish_block(ep);
@@ -1965,12 +2224,15 @@
 		if (!case_stmt->case_expression) {
 			default_case = bb_case;
 			continue;
+		} else if (case_stmt->case_expression->type != EXPR_VALUE) {
+			continue;
 		} else {
-			int begin, end;
+			struct expression *case_to = case_stmt->case_to;
+			long long begin, end;
 
 			begin = end = case_stmt->case_expression->value;
-			if (case_stmt->case_to)
-				end = case_stmt->case_to->value;
+			if (case_to && case_to->type == EXPR_VALUE)
+				end = case_to->value;
 			if (begin > end)
 				jmp = alloc_multijmp(bb_case, end, begin);
 			else
@@ -2047,7 +2309,7 @@
 	return VOID;
 }
 
-pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt)
+static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt)
 {
 	struct basic_block *bb;
 
@@ -2124,7 +2386,7 @@
 
 		pseudo = linearize_expression(ep, expr);
 		goto_ins = alloc_instruction(OP_COMPUTEDGOTO, 0);
-		use_pseudo(goto_ins, pseudo, &goto_ins->target);
+		use_pseudo(goto_ins, pseudo, &goto_ins->src);
 		add_one_insn(ep, goto_ins);
 
 		FOR_EACH_PTR(stmt->target_list, sym) {
@@ -2184,23 +2446,30 @@
 
 static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type)
 {
+	struct statement *stmt = base_type->stmt;
 	struct entrypoint *ep;
 	struct basic_block *bb;
+	struct symbol *ret_type;
 	struct symbol *arg;
 	struct instruction *entry;
+	struct instruction *ret;
 	pseudo_t result;
 	int i;
 
-	if (!base_type->stmt)
+	if (!stmt)
 		return NULL;
 
 	ep = alloc_entrypoint();
-	bb = alloc_basic_block(ep, sym->pos);
-	
 	ep->name = sym;
 	sym->ep = ep;
+	bb = alloc_basic_block(ep, sym->pos);
 	set_activeblock(ep, bb);
 
+	if (stmt->type == STMT_ASM) {	// top-level asm
+		linearize_asm_statement(ep, stmt);
+		return ep;
+	}
+
 	entry = alloc_instruction(OP_ENTRY, 0);
 	add_one_insn(ep, entry);
 	ep->entry = entry;
@@ -2213,67 +2482,14 @@
 		linearize_argument(ep, arg, ++i);
 	} END_FOR_EACH_PTR(arg);
 
-	result = linearize_statement(ep, base_type->stmt);
-	if (bb_reachable(ep->active) && !bb_terminated(ep->active)) {
-		struct symbol *ret_type = base_type->ctype.base_type;
-		struct instruction *insn = alloc_typed_instruction(OP_RET, ret_type);
+	result = linearize_fn_statement(ep, stmt);
+	ret_type = base_type->ctype.base_type;
+	ret = alloc_typed_instruction(OP_RET, ret_type);
+	if (type_size(ret_type) > 0)
+		use_pseudo(ret, result, &ret->src);
+	add_one_insn(ep, ret);
 
-		if (type_size(ret_type) > 0)
-			use_pseudo(insn, result, &insn->src);
-		add_one_insn(ep, insn);
-	}
-
-	if (fdump_linearize) {
-		if (fdump_linearize == 2)
-			return ep;
-		show_entry(ep);
-	}
-
-	/*
-	 * Do trivial flow simplification - branches to
-	 * branches, kill dead basicblocks etc
-	 */
-	kill_unreachable_bbs(ep);
-
-	/*
-	 * Turn symbols into pseudos
-	 */
-	simplify_symbol_usage(ep);
-
-repeat:
-	/*
-	 * Remove trivial instructions, and try to CSE
-	 * the rest.
-	 */
-	do {
-		cleanup_and_cse(ep);
-		pack_basic_blocks(ep);
-	} while (repeat_phase & REPEAT_CSE);
-
-	kill_unreachable_bbs(ep);
-	vrfy_flow(ep);
-
-	/* Cleanup */
-	clear_symbol_pseudos(ep);
-
-	/* And track pseudo register usage */
-	track_pseudo_liveness(ep);
-
-	/*
-	 * Some flow optimizations can only effectively
-	 * be done when we've done liveness analysis. But
-	 * if they trigger, we need to start all over
-	 * again
-	 */
-	if (simplify_flow(ep)) {
-		clear_liveness(ep);
-		goto repeat;
-	}
-
-	/* Finally, add deathnotes to pseudos now that we have them */
-	if (dbg_dead)
-		track_pseudo_death(ep);
-
+	optimize(ep);
 	return ep;
 }
 
--- 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 */
 
--- old/usr/src/tools/smatch/src/liveness.c	Mon Nov 18 13:19:00 2019
+++ new/usr/src/tools/smatch/src/liveness.c	Mon Nov 18 13:19:00 2019
@@ -7,6 +7,7 @@
 
 #include <assert.h>
 
+#include "liveness.h"
 #include "parse.h"
 #include "expression.h"
 #include "linearize.h"
@@ -53,6 +54,7 @@
 
 	switch (insn->opcode) {
 	case OP_RET:
+	case OP_COMPUTEDGOTO:
 		USES(src);
 		break;
 
@@ -61,18 +63,16 @@
 		USES(cond);
 		break;
 
-	case OP_COMPUTEDGOTO:
-		USES(target);
-		break;
-	
 	/* Binary */
 	case OP_BINARY ... OP_BINARY_END:
+	case OP_FPCMP ... OP_FPCMP_END:
 	case OP_BINCMP ... OP_BINCMP_END:
 		USES(src1); USES(src2); DEFINES(target);
 		break;
 
 	/* Uni */
-	case OP_NOT: case OP_NEG:
+	case OP_UNOP ... OP_UNOP_END:
+	case OP_SYMADDR:
 		USES(src1); DEFINES(target);
 		break;
 
@@ -90,13 +90,10 @@
 		break;
 
 	case OP_SETVAL:
+	case OP_SETFVAL:
 		DEFINES(target);
 		break;
 
-	case OP_SYMADDR:
-		USES(symbol); DEFINES(target);
-		break;
-
 	/* Other */
 	case OP_PHI:
 		/* Phi-nodes are "backwards" nodes. Their def doesn't matter */
@@ -111,13 +108,6 @@
 		USES(phi_src);
 		break;
 
-	case OP_CAST:
-	case OP_SCAST:
-	case OP_FPCAST:
-	case OP_PTRCAST:
-		USES(src); DEFINES(target);
-		break;
-
 	case OP_CALL:
 		USES(func);
 		if (insn->target != VOID)
@@ -140,16 +130,6 @@
 		break;
 
 	case OP_BADOP:
-	case OP_INVOKE:
-	case OP_UNWIND:
-	case OP_MALLOC:
-	case OP_FREE:
-	case OP_ALLOCA:
-	case OP_GET_ELEMENT_PTR:
-	case OP_VANEXT:
-	case OP_VAARG:
-	case OP_SNOP:
-	case OP_LNOP:
 	case OP_NOP:
 	case OP_CONTEXT:
 		break;
@@ -156,15 +136,6 @@
 	}
 }
 
-int pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo)
-{
-	pseudo_t old;
-	FOR_EACH_PTR(list,old) {
-		if (old == pseudo)
-			return 1;
-	} END_FOR_EACH_PTR(old);   
-	return 0;
-}
 
 static int liveness_changed;
 
@@ -276,7 +247,7 @@
 	} END_FOR_EACH_PTR(pseudo);
 }
 
-void track_phi_uses(struct instruction *insn)
+static void track_phi_uses(struct instruction *insn)
 {
 	pseudo_t phi;
 	FOR_EACH_PTR(insn->phi_list, phi) {
--- /dev/null	Mon Nov 18 13:19:00 2019
+++ new/usr/src/tools/smatch/src/liveness.h	Mon Nov 18 13:19:00 2019
@@ -0,0 +1,11 @@
+#ifndef LIVENESS_H
+#define LIVENESS_H
+
+struct entrypoint;
+
+/* liveness.c */
+void clear_liveness(struct entrypoint *ep);
+void track_pseudo_liveness(struct entrypoint *ep);
+void track_pseudo_death(struct entrypoint *ep);
+
+#endif
--- /dev/null	Mon Nov 18 13:19:01 2019
+++ new/usr/src/tools/smatch/src/machine.h	Mon Nov 18 13:19:01 2019
@@ -0,0 +1,83 @@
+#ifndef MACHINE_H
+#define MACHINE_H
+
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define ARCH_BIG_ENDIAN 1
+#else
+#define ARCH_BIG_ENDIAN 0
+#endif
+
+
+enum {
+	ARCH_LP32,
+	ARCH_X32,
+	ARCH_LP64,
+	ARCH_LLP64,
+};
+
+#ifdef __LP64__
+#define ARCH_M64_DEFAULT ARCH_LP64
+#elif defined(__x86_64__) || defined(__x86_64)
+#define ARCH_M64_DEFAULT ARCH_X32
+#else
+#define ARCH_M64_DEFAULT ARCH_LP32
+#endif
+
+
+enum machine {
+	MACH_ARM,
+	MACH_ARM64,
+	MACH_I386,
+	MACH_X86_64,
+	MACH_MIPS32,
+	MACH_MIPS64,
+	MACH_PPC32,
+	MACH_PPC64,
+	MACH_RISCV32,
+	MACH_RISCV64,
+	MACH_SPARC32,
+	MACH_SPARC64,
+	MACH_M68K,
+	MACH_S390X,
+	MACH_UNKNOWN
+};
+
+#if defined(__aarch64__)
+#define MACH_NATIVE	MACH_ARM64
+#elif defined(__arm__)
+#define	MACH_NATIVE	MACH_ARM
+#elif defined(__x86_64__) || defined(__x86_64)
+#define	MACH_NATIVE	MACH_X86_64
+#elif defined(__i386__) || defined(__i386)
+#define	MACH_NATIVE	MACH_I386
+#elif defined(__mips64__) || (defined(__mips) && __mips == 64)
+#define	MACH_NATIVE	MACH_MIPS64
+#elif defined(__mips__) || defined(__mips)
+#define	MACH_NATIVE	MACH_MIPS32
+#elif defined(__powerpc64__) || defined(__ppc64__)
+#define	MACH_NATIVE	MACH_PPC64
+#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__)
+#define	MACH_NATIVE	MACH_PPC32
+#elif defined(__riscv) && (__riscv_xlen == 64)
+#define	MACH_NATIVE	MACH_RISCV64
+#elif defined(__riscv) && (__riscv_xlen == 32)
+#define	MACH_NATIVE	MACH_RISCV32
+#elif defined(__sparc_v9__)
+#define	MACH_NATIVE	MACH_SPARC64
+#elif defined(__sparc__) || defined(__sparc)
+#define	MACH_NATIVE	MACH_SPARC32
+#elif defined(__m68k__)
+#define MACH_NATIVE	MACH_M68K
+#elif defined(__s390x__) || defined(__zarch__)
+#define MACH_NATIVE	MACH_S390X
+#else
+#define MACH_NATIVE	MACH_UNKNOWN
+#endif
+
+#if defined(__CHAR_UNSIGNED__)
+#define	UNSIGNED_CHAR	1
+#else
+#define UNSIGNED_CHAR	0
+#endif
+
+#endif
--- old/usr/src/tools/smatch/src/macro_table.c	Mon Nov 18 13:19:01 2019
+++ new/usr/src/tools/smatch/src/macro_table.c	Mon Nov 18 13:19:01 2019
@@ -31,14 +31,14 @@
 
 static struct hashtable *macro_table;
 
-static DEFINE_HASHTABLE_INSERT(do_insert_macro, struct position, char);
-static DEFINE_HASHTABLE_SEARCH(do_search_macro, struct position, char);
+static DEFINE_HASHTABLE_INSERT(do_insert_macro, struct position, struct string_list);
+static DEFINE_HASHTABLE_SEARCH(do_search_macro, struct position, struct string_list);
 
 static inline unsigned int position_hash(void *_pos)
 {
 	struct position *pos = _pos;
 
-	return pos->line | (pos->pos << 22) | (pos->stream << 18); 
+	return pos->line | (pos->pos << 22) | (pos->stream << 18);
 }
 
 static inline int equalkeys(void *_pos1, void *_pos2)
@@ -50,18 +50,47 @@
 		pos1->stream == pos2->stream;
 }
 
+static void insert_macro_string(struct string_list **str_list, char *new)
+{
+	add_ptr_list(str_list, new);
+}
+
 void store_macro_pos(struct token *token)
 {
+	struct string_list *list;
+
 	if (!macro_table)
 		macro_table = create_hashtable(5000, position_hash, equalkeys);
 
-	if (get_macro_name(token->pos))
-		return;
+	list = do_search_macro(macro_table, &token->pos);
+	insert_macro_string(&list, token->ident->name);
 
-	do_insert_macro(macro_table, &token->pos, token->ident->name);
+	do_insert_macro(macro_table, &token->pos, list);
 }
 
 char *get_macro_name(struct position pos)
 {
+	struct string_list *list;
+
+	if (!macro_table)
+		return NULL;
+	list = do_search_macro(macro_table, &pos);
+	return first_ptr_list((struct ptr_list *)list);
+}
+
+char *get_inner_macro(struct position pos)
+{
+	struct string_list *list;
+
+	if (!macro_table)
+		return NULL;
+	list = do_search_macro(macro_table, &pos);
+	return last_ptr_list((struct ptr_list *)list);
+}
+
+struct string_list *get_all_macros(struct position pos)
+{
+	if (!macro_table)
+		return NULL;
 	return do_search_macro(macro_table, &pos);
 }
--- old/usr/src/tools/smatch/src/memops.c	Mon Nov 18 13:19:01 2019
+++ new/usr/src/tools/smatch/src/memops.c	Mon Nov 18 13:19:01 2019
@@ -54,7 +54,7 @@
 
 found_dominator:
 		br = delete_last_instruction(&parent->insns);
-		phi = alloc_phi(parent, one->target, one->size);
+		phi = alloc_phi(parent, one->target, one->type);
 		phi->ident = phi->ident ? : one->target->ident;
 		add_instruction(&parent->insns, br);
 		use_pseudo(insn, phi, add_pseudo(dominators, phi));
@@ -69,6 +69,8 @@
 		struct instruction *insn = pu->insn;
 		if (insn->bb && (insn->opcode != OP_LOAD && insn->opcode != OP_STORE))
 			return 1;
+		if (pu->userp != &insn->src)
+			return 1;
 	} END_FOR_EACH_PTR(pu);
 	return 0;
 }
@@ -97,7 +99,7 @@
 			/* Check for illegal offsets.. */
 			check_access(insn);
 
-			if (insn->type->ctype.modifiers & MOD_VOLATILE)
+			if (insn->is_volatile)
 				continue;
 
 			RECURSE_PTR_REVERSE(insn, dom) {
@@ -127,11 +129,16 @@
 				if (!dominators) {
 					if (local) {
 						assert(pseudo->type != PSEUDO_ARG);
-						convert_load_instruction(insn, value_pseudo(insn->type, 0));
+						convert_load_instruction(insn, value_pseudo(0));
 					}
 					goto next_load;
 				}
 				rewrite_load_instruction(insn, dominators);
+			} else {	// cleanup pending phi-sources
+				pseudo_t phi;
+				FOR_EACH_PTR(dominators, phi) {
+					kill_instruction(phi->def);
+				} END_FOR_EACH_PTR(phi);
 			}
 		}
 next_load:
@@ -139,15 +146,6 @@
 	} END_FOR_EACH_PTR_REVERSE(insn);
 }
 
-static void kill_store(struct instruction *insn)
-{
-	if (insn) {
-		insn->bb = NULL;
-		insn->opcode = OP_SNOP;
-		kill_use(&insn->target);
-	}
-}
-
 static void kill_dominated_stores(struct basic_block *bb)
 {
 	struct instruction *insn;
@@ -158,8 +156,14 @@
 		if (insn->opcode == OP_STORE) {
 			struct instruction *dom;
 			pseudo_t pseudo = insn->src;
-			int local = local_pseudo(pseudo);
+			int local;
 
+			if (!insn->type)
+				continue;
+			if (insn->is_volatile)
+				continue;
+
+			local = local_pseudo(pseudo);
 			RECURSE_PTR_REVERSE(insn, dom) {
 				int dominance;
 				if (!dom->bb)
@@ -172,7 +176,7 @@
 					if (dom->opcode == OP_LOAD)
 						goto next_store;
 					/* Yeehaa! Found one! */
-					kill_store(dom);
+					kill_instruction_force(dom);
 				}
 			} END_FOR_EACH_PTR_REVERSE(dom);
 
@@ -186,6 +190,7 @@
 void simplify_memops(struct entrypoint *ep)
 {
 	struct basic_block *bb;
+	pseudo_t pseudo;
 
 	FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
 		simplify_loads(bb);
@@ -194,4 +199,15 @@
 	FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
 		kill_dominated_stores(bb);
 	} END_FOR_EACH_PTR_REVERSE(bb);
+
+	FOR_EACH_PTR(ep->accesses, pseudo) {
+		struct symbol *var = pseudo->sym;
+		unsigned long mod;
+		if (!var)
+			continue;
+		mod = var->ctype.modifiers;
+		if (mod & (MOD_VOLATILE | MOD_NONLOCAL | MOD_STATIC))
+			continue;
+		kill_dead_stores(ep, pseudo, local_pseudo(pseudo));
+	} END_FOR_EACH_PTR(pseudo);
 }
--- old/usr/src/tools/smatch/src/obfuscate.c	Mon Nov 18 13:19:01 2019
+++ new/usr/src/tools/smatch/src/obfuscate.c	Mon Nov 18 13:19:01 2019
@@ -69,8 +69,8 @@
 	char *file;
 
 	emit_symbol_list(sparse_initialize(argc, argv, &filelist));
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		emit_symbol_list(sparse(file));
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 	return 0;
 }
--- /dev/null	Mon Nov 18 13:19:02 2019
+++ new/usr/src/tools/smatch/src/opcode.c	Mon Nov 18 13:19:02 2019
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 Luc Van Oostenryck
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "opcode.h"
+
+const struct opcode_table opcode_table[OP_LAST] = {
+#define OPCODE(OP,NG,SW,TF,N,FL)	\
+	[OP_##OP] = {			\
+		.negate   = OP_##NG,	\
+		.swap     = OP_##SW,	\
+		.to_float = OP_##TF,	\
+		.arity    = N,		\
+		.flags    = FL,		\
+	},
+#define OPCODE_RANGE(OP,S,E)
+#include "opcode.def"
+#undef OPCODE
+#undef OPCODE_RANGE
+};
--- /dev/null	Mon Nov 18 13:19:02 2019
+++ new/usr/src/tools/smatch/src/opcode.def	Mon Nov 18 13:19:02 2019
@@ -0,0 +1,114 @@
+//      OPCODE          negated   swaped    float  arity, flags
+
+OPCODE(BADOP,           BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+
+/* Entry */
+OPCODE(ENTRY,           BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+
+/* Terminator */
+OPCODE(RET,             BADOP,    BADOP,    BADOP, 1, OPF_NONE)
+OPCODE(BR,              BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+OPCODE(CBR,             BADOP,    BADOP,    BADOP, 1, OPF_NONE)
+OPCODE(SWITCH,          BADOP,    BADOP,    BADOP, 1, OPF_NONE)
+OPCODE(COMPUTEDGOTO,    BADOP,    BADOP,    BADOP, 1, OPF_NONE)
+OPCODE_RANGE(TERMINATOR, RET, COMPUTEDGOTO)
+
+/* Binary */
+OPCODE(ADD,             BADOP,    BADOP,    FADD,  2, OPF_TARGET)
+OPCODE(SUB,             BADOP,    BADOP,    FSUB,  2, OPF_TARGET)
+OPCODE(MUL,             BADOP,    BADOP,    FMUL,  2, OPF_TARGET)
+OPCODE(DIVU,            BADOP,    BADOP,    FDIV,  2, OPF_TARGET)
+OPCODE(DIVS,            BADOP,    BADOP,    FDIV,  2, OPF_TARGET)
+OPCODE(MODU,            BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(MODS,            BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(SHL,             BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(LSR,             BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(ASR,             BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+
+/* Floating-point binops */
+OPCODE(FADD,            BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(FSUB,            BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(FMUL,            BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(FDIV,            BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+
+/* Logical */
+OPCODE(AND_BOOL,        BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(OR_BOOL,         BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(AND,             BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(OR,              BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE(XOR,             BADOP,    BADOP,    BADOP, 2, OPF_TARGET)
+OPCODE_RANGE(BINARY, ADD, XOR)
+
+/* floating-point comparison */
+OPCODE(FCMP_ORD,        FCMP_UNO, FCMP_ORD, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OEQ,        FCMP_UNE, FCMP_OEQ, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_ONE,        FCMP_UEQ, FCMP_ONE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UEQ,        FCMP_ONE, FCMP_UEQ, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UNE,        FCMP_OEQ, FCMP_UNE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OLT,        FCMP_UGE, FCMP_OGT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OLE,        FCMP_UGT, FCMP_OGE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OGE,        FCMP_ULT, FCMP_OLE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_OGT,        FCMP_ULE, FCMP_OLT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_ULT,        FCMP_OGE, FCMP_UGT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_ULE,        FCMP_OGT, FCMP_UGE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UGE,        FCMP_OLT, FCMP_ULE, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UGT,        FCMP_OLE, FCMP_ULT, BADOP, 2, OPF_TARGET)
+OPCODE(FCMP_UNO,        FCMP_ORD, FCMP_UNO, BADOP, 2, OPF_TARGET)
+OPCODE_RANGE(FPCMP, FCMP_ORD, FCMP_UNO)
+
+/* Binary comparison */
+OPCODE(SET_EQ,          SET_NE,   SET_EQ,   FCMP_OEQ, 2, OPF_TARGET)
+OPCODE(SET_LT,          SET_GE,   SET_GT,   FCMP_OLT, 2, OPF_TARGET)
+OPCODE(SET_LE,          SET_GT,   SET_GE,   FCMP_OLE, 2, OPF_TARGET)
+OPCODE(SET_GE,          SET_LT,   SET_LE,   FCMP_OGE, 2, OPF_TARGET)
+OPCODE(SET_GT,          SET_LE,   SET_LT,   FCMP_OGT, 2, OPF_TARGET)
+OPCODE(SET_B,           SET_AE,   SET_A,    FCMP_OLT, 2, OPF_TARGET)
+OPCODE(SET_BE,          SET_A,    SET_AE,   FCMP_OLE, 2, OPF_TARGET)
+OPCODE(SET_AE,          SET_B,    SET_BE,   FCMP_OGE, 2, OPF_TARGET)
+OPCODE(SET_A,           SET_BE,   SET_B,    FCMP_OGT, 2, OPF_TARGET)
+OPCODE(SET_NE,          SET_EQ,   SET_NE,   FCMP_UNE, 2, OPF_TARGET)
+OPCODE_RANGE(BINCMP, SET_EQ, SET_NE)
+
+/* Uni */
+OPCODE(NOT,             BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(NEG,             BADOP,    BADOP,    FNEG,  1, OPF_TARGET)
+OPCODE(FNEG,            BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(TRUNC,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(ZEXT,            BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(SEXT,            BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(FCVTU,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(FCVTS,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(UCVTF,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(SCVTF,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(FCVTF,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(UTPTR,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(PTRTU,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(PTRCAST,         BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE_RANGE(UNOP, NOT, PTRCAST)
+OPCODE(SYMADDR,         BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(SLICE,           BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+
+/* Select - three input values */
+OPCODE(SEL,             BADOP,    BADOP,    BADOP, 3, OPF_TARGET)
+
+/* Memory */
+OPCODE(LOAD,            BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(STORE,           BADOP,    BADOP,    BADOP, 1, OPF_NONE)
+
+/* Other */
+OPCODE(PHISOURCE,       BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(PHI,             BADOP,    BADOP,    BADOP, 0, OPF_TARGET)
+OPCODE(SETVAL,          BADOP,    BADOP,    BADOP, 0, OPF_TARGET)
+OPCODE(SETFVAL,         BADOP,    BADOP,    BADOP, 0, OPF_TARGET)
+OPCODE(CALL,            BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
+OPCODE(INLINED_CALL,    BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+OPCODE(NOP,             BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+OPCODE(DEATHNOTE,       BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+OPCODE(ASM,             BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+
+/* Sparse tagging (line numbers, context, whatever) */
+OPCODE(CONTEXT,         BADOP,    BADOP,    BADOP, 0, OPF_NONE)
+OPCODE(RANGE,           BADOP,    BADOP,    BADOP, 3, OPF_NONE)
+
+/* Needed to translate SSA back to normal form */
+OPCODE(COPY,            BADOP,    BADOP,    BADOP, 1, OPF_TARGET)
--- /dev/null	Mon Nov 18 13:19:02 2019
+++ new/usr/src/tools/smatch/src/opcode.h	Mon Nov 18 13:19:02 2019
@@ -0,0 +1,33 @@
+#ifndef OPCODE_H
+#define OPCODE_H
+
+#include "symbol.h"
+
+enum opcode {
+#define OPCODE(OP,NG,SW,TF,N,FL)  OP_##OP,
+#define OPCODE_RANGE(OP,S,E)	OP_##OP = OP_##S, OP_##OP##_END = OP_##E,
+#include "opcode.def"
+#undef  OPCODE
+#undef  OPCODE_RANGE
+	OP_LAST,			/* keep this one last! */
+};
+
+extern const struct opcode_table {
+	int	negate:8;
+	int	swap:8;
+	int	to_float:8;
+	unsigned int arity:2;
+	unsigned int flags:6;
+#define			OPF_NONE	0
+#define			OPF_TARGET	(1 << 0)
+} opcode_table[];
+
+
+static inline int opcode_float(int opcode, struct symbol *type)
+{
+	if (!type || !is_float_type(type))
+		return opcode;
+	return opcode_table[opcode].to_float;
+}
+
+#endif
--- /dev/null	Mon Nov 18 13:19:02 2019
+++ new/usr/src/tools/smatch/src/optimize.c	Mon Nov 18 13:19:02 2019
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: MIT
+//
+// optimize.c - main optimization loop
+//
+// Copyright (C) 2004 Linus Torvalds
+// Copyright (C) 2004 Christopher Li
+
+#include <assert.h>
+#include "optimize.h"
+#include "flowgraph.h"
+#include "linearize.h"
+#include "liveness.h"
+#include "flow.h"
+#include "cse.h"
+#include "ir.h"
+#include "ssa.h"
+
+int repeat_phase;
+
+static void clear_symbol_pseudos(struct entrypoint *ep)
+{
+	pseudo_t pseudo;
+
+	FOR_EACH_PTR(ep->accesses, pseudo) {
+		pseudo->sym->pseudo = NULL;
+	} END_FOR_EACH_PTR(pseudo);
+}
+
+
+static void clean_up_insns(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+
+	FOR_EACH_PTR(ep->bbs, bb) {
+		struct instruction *insn;
+		FOR_EACH_PTR(bb->insns, insn) {
+			repeat_phase |= simplify_instruction(insn);
+			if (!insn->bb)
+				continue;
+			assert(insn->bb == bb);
+			cse_collect(insn);
+		} END_FOR_EACH_PTR(insn);
+	} END_FOR_EACH_PTR(bb);
+}
+
+void optimize(struct entrypoint *ep)
+{
+	if (fdump_ir & PASS_LINEARIZE)
+		show_entry(ep);
+
+	/*
+	 * Do trivial flow simplification - branches to
+	 * branches, kill dead basicblocks etc
+	 */
+	kill_unreachable_bbs(ep);
+	ir_validate(ep);
+
+	domtree_build(ep);
+
+	/*
+	 * Turn symbols into pseudos
+	 */
+	if (fpasses & PASS_MEM2REG)
+		ssa_convert(ep);
+	ir_validate(ep);
+	if (fdump_ir & PASS_MEM2REG)
+		show_entry(ep);
+
+	if (!(fpasses & PASS_OPTIM))
+		return;
+repeat:
+	/*
+	 * Remove trivial instructions, and try to CSE
+	 * the rest.
+	 */
+	do {
+		simplify_memops(ep);
+		//ir_validate(ep);
+		do {
+			repeat_phase = 0;
+			clean_up_insns(ep);
+			if (repeat_phase & REPEAT_CFG_CLEANUP)
+				kill_unreachable_bbs(ep);
+
+			cse_eliminate(ep);
+
+			if (repeat_phase & REPEAT_SYMBOL_CLEANUP)
+				simplify_memops(ep);
+			//ir_validate(ep);
+		} while (repeat_phase);
+		pack_basic_blocks(ep);
+		//ir_validate(ep);
+		if (repeat_phase & REPEAT_CFG_CLEANUP)
+			kill_unreachable_bbs(ep);
+		//ir_validate(ep);
+	} while (repeat_phase);
+	//ir_validate(ep);
+
+	vrfy_flow(ep);
+
+	/* Cleanup */
+	clear_symbol_pseudos(ep);
+
+	/* And track pseudo register usage */
+	track_pseudo_liveness(ep);
+
+	/*
+	 * Some flow optimizations can only effectively
+	 * be done when we've done liveness analysis. But
+	 * if they trigger, we need to start all over
+	 * again
+	 */
+	if (simplify_flow(ep)) {
+		//ir_validate(ep);
+		clear_liveness(ep);
+		if (repeat_phase & REPEAT_CFG_CLEANUP)
+			kill_unreachable_bbs(ep);
+		goto repeat;
+	}
+	//ir_validate(ep);
+
+	/* Finally, add deathnotes to pseudos now that we have them */
+	if (dbg_dead)
+		track_pseudo_death(ep);
+}
--- /dev/null	Mon Nov 18 13:19:02 2019
+++ new/usr/src/tools/smatch/src/optimize.h	Mon Nov 18 13:19:02 2019
@@ -0,0 +1,9 @@
+#ifndef OPTIMIZE_H
+#define OPTIMIZE_H
+
+struct entrypoint;
+
+/* optimize.c */
+void optimize(struct entrypoint *ep);
+
+#endif
--- old/usr/src/tools/smatch/src/parse.c	Mon Nov 18 13:19:02 2019
+++ new/usr/src/tools/smatch/src/parse.c	Mon Nov 18 13:19:02 2019
@@ -58,6 +58,8 @@
 	typedef_specifier, inline_specifier, auto_specifier,
 	register_specifier, static_specifier, extern_specifier,
 	thread_specifier, const_qualifier, volatile_qualifier;
+static declarator_t restrict_qualifier;
+static declarator_t atomic_qualifier;
 
 static struct token *parse_if_statement(struct token *token, struct statement *stmt);
 static struct token *parse_return_statement(struct token *token, struct statement *stmt);
@@ -80,6 +82,7 @@
 
 static attr_t
 	attribute_packed, attribute_aligned, attribute_modifier,
+	attribute_ext_visible,
 	attribute_bitwise,
 	attribute_address_space, attribute_context,
 	attribute_designated_init,
@@ -89,7 +92,8 @@
 typedef struct symbol *to_mode_t(struct symbol *);
 
 static to_mode_t
-	to_QI_mode, to_HI_mode, to_SI_mode, to_DI_mode, to_TI_mode, to_word_mode;
+	to_QI_mode, to_HI_mode, to_SI_mode, to_DI_mode, to_TI_mode;
+static to_mode_t to_pointer_mode, to_word_mode;
 
 enum {
 	Set_T = 1,
@@ -115,6 +119,23 @@
 	SNone = 0, STypedef, SAuto, SRegister, SExtern, SStatic, SForced, SMax,
 };
 
+static void asm_modifier(struct token *token, unsigned long *mods, unsigned long mod)
+{
+	if (*mods & mod)
+		warning(token->pos, "duplicated asm modifier");
+	*mods |= mod;
+}
+
+static void asm_modifier_volatile(struct token *token, unsigned long *mods)
+{
+	asm_modifier(token, mods, MOD_VOLATILE);
+}
+
+static void asm_modifier_inline(struct token *token, unsigned long *mods)
+{
+	asm_modifier(token, mods, MOD_INLINE);
+}
+
 static struct symbol_op typedef_op = {
 	.type = KW_MODIFIER,
 	.declarator = typedef_specifier,
@@ -123,6 +144,7 @@
 static struct symbol_op inline_op = {
 	.type = KW_MODIFIER,
 	.declarator = inline_specifier,
+	.asm_modifier = asm_modifier_inline,
 };
 
 static declarator_t noreturn_specifier;
@@ -170,12 +192,19 @@
 static struct symbol_op volatile_op = {
 	.type = KW_QUALIFIER,
 	.declarator = volatile_qualifier,
+	.asm_modifier = asm_modifier_volatile,
 };
 
 static struct symbol_op restrict_op = {
 	.type = KW_QUALIFIER,
+	.declarator = restrict_qualifier,
 };
 
+static struct symbol_op atomic_op = {
+	.type = KW_QUALIFIER,
+	.declarator = atomic_qualifier,
+};
+
 static struct symbol_op typeof_op = {
 	.type = KW_SPECIFIER,
 	.declarator = typeof_specifier,
@@ -235,14 +264,6 @@
 	.class = CReal,
 };
 
-/* FIXME: this is not even slightly right. */
-static struct symbol_op complex_op = {
-	.type = KW_SPECIFIER,
-	.test = 0, //Set_T|Set_Signed|Set_Unsigned|Set_Short|Set_Vlong,
-	.set = 0, //Set_Double, //Set_T,Set_Double,
-	.class = CReal,
-};
-
 static struct symbol_op float_op = {
 	.type = KW_SPECIFIER | KW_SHORT,
 	.test = Set_T|Set_Signed|Set_Unsigned|Set_Short|Set_Long,
@@ -353,6 +374,10 @@
 	.attribute = attribute_modifier,
 };
 
+static struct symbol_op ext_visible_op = {
+	.attribute = attribute_ext_visible,
+};
+
 static struct symbol_op attr_bitwise_op = {
 	.attribute = attribute_bitwise,
 };
@@ -410,6 +435,11 @@
 	.to_mode = to_TI_mode
 };
 
+static struct symbol_op mode_pointer_op = {
+	.type = KW_MODE,
+	.to_mode = to_pointer_mode
+};
+
 static struct symbol_op mode_word_op = {
 	.type = KW_MODE,
 	.to_mode = to_word_mode
@@ -430,6 +460,10 @@
 	{ "volatile",	NS_TYPEDEF, .op = &volatile_op },
 	{ "__volatile",		NS_TYPEDEF, .op = &volatile_op },
 	{ "__volatile__", 	NS_TYPEDEF, .op = &volatile_op },
+	{ "restrict",	NS_TYPEDEF, .op = &restrict_op},
+	{ "__restrict",	NS_TYPEDEF, .op = &restrict_op},
+	{ "__restrict__",	NS_TYPEDEF, .op = &restrict_op},
+	{ "_Atomic",	NS_TYPEDEF, .op = &atomic_op},
 
 	/* Typedef.. */
 	{ "typedef",	NS_TYPEDEF, .op = &typedef_op },
@@ -448,7 +482,6 @@
 	{ "unsigned",	NS_TYPEDEF, .op = &unsigned_op },
 	{ "__int128",	NS_TYPEDEF, .op = &int128_op },
 	{ "_Bool",	NS_TYPEDEF, .type = &bool_ctype, .op = &spec_op },
-	{ "_Complex",   NS_TYPEDEF, .op = &complex_op },
 
 	/* Predeclared types */
 	{ "__builtin_va_list", NS_TYPEDEF, .type = &ptr_ctype, .op = &spec_op },
@@ -455,6 +488,11 @@
 	{ "__builtin_ms_va_list", NS_TYPEDEF, .type = &ptr_ctype, .op = &spec_op },
 	{ "__int128_t",	NS_TYPEDEF, .type = &lllong_ctype, .op = &spec_op },
 	{ "__uint128_t",NS_TYPEDEF, .type = &ulllong_ctype, .op = &spec_op },
+	{ "_Float32",	NS_TYPEDEF, .type = &float32_ctype, .op = &spec_op },
+	{ "_Float32x",	NS_TYPEDEF, .type = &float32x_ctype, .op = &spec_op },
+	{ "_Float64",	NS_TYPEDEF, .type = &float64_ctype, .op = &spec_op },
+	{ "_Float64x",	NS_TYPEDEF, .type = &float64x_ctype, .op = &spec_op },
+	{ "_Float128",	NS_TYPEDEF, .type = &float128_ctype, .op = &spec_op },
 
 	/* Extended types */
 	{ "typeof", 	NS_TYPEDEF, .op = &typeof_op },
@@ -476,11 +514,6 @@
 
 	{ "_Alignas",	NS_TYPEDEF, .op = &alignas_op },
 
-	/* Ignored for now.. */
-	{ "restrict",	NS_TYPEDEF, .op = &restrict_op},
-	{ "__restrict",	NS_TYPEDEF, .op = &restrict_op},
-	{ "__restrict__",	NS_TYPEDEF, .op = &restrict_op},
-
 	/* Static assertion */
 	{ "_Static_assert", NS_KEYWORD, .op = &static_assert_op },
 
@@ -522,9 +555,10 @@
 	{ "bitwise",	NS_KEYWORD,	MOD_BITWISE,	.op = &attr_bitwise_op },
 	{ "__bitwise__",NS_KEYWORD,	MOD_BITWISE,	.op = &attr_bitwise_op },
 	{ "address_space",NS_KEYWORD,	.op = &address_space_op },
-	{ "mode",	NS_KEYWORD,	.op = &mode_op },
 	{ "context",	NS_KEYWORD,	.op = &context_op },
 	{ "designated_init",	NS_KEYWORD,	.op = &designated_init_op },
+	{ "__designated_init__",	NS_KEYWORD,	.op = &designated_init_op },
+	{ "transparent_union",	NS_KEYWORD,	.op = &transparent_union_op },
 	{ "__transparent_union__",	NS_KEYWORD,	.op = &transparent_union_op },
 	{ "noreturn",	NS_KEYWORD,	MOD_NORETURN,	.op = &attr_mod_op },
 	{ "__noreturn__",	NS_KEYWORD,	MOD_NORETURN,	.op = &attr_mod_op },
@@ -533,20 +567,27 @@
 	{"const",	NS_KEYWORD,	MOD_PURE,	.op = &attr_mod_op },
 	{"__const",	NS_KEYWORD,	MOD_PURE,	.op = &attr_mod_op },
 	{"__const__",	NS_KEYWORD,	MOD_PURE,	.op = &attr_mod_op },
+	{"externally_visible",	NS_KEYWORD,	.op = &ext_visible_op },
+	{"__externally_visible__",	NS_KEYWORD,	.op = &ext_visible_op },
 
+	{ "mode",	NS_KEYWORD,	.op = &mode_op },
 	{ "__mode__",	NS_KEYWORD,	.op = &mode_op },
-	{ "QI",		NS_KEYWORD,	MOD_CHAR,	.op = &mode_QI_op },
-	{ "__QI__",	NS_KEYWORD,	MOD_CHAR,	.op = &mode_QI_op },
-	{ "HI",		NS_KEYWORD,	MOD_SHORT,	.op = &mode_HI_op },
-	{ "__HI__",	NS_KEYWORD,	MOD_SHORT,	.op = &mode_HI_op },
-	{ "SI",		NS_KEYWORD,			.op = &mode_SI_op },
-	{ "__SI__",	NS_KEYWORD,			.op = &mode_SI_op },
-	{ "DI",		NS_KEYWORD,	MOD_LONGLONG,	.op = &mode_DI_op },
-	{ "__DI__",	NS_KEYWORD,	MOD_LONGLONG,	.op = &mode_DI_op },
-	{ "TI",		NS_KEYWORD,	MOD_LONGLONGLONG,	.op = &mode_TI_op },
-	{ "__TI__",	NS_KEYWORD,	MOD_LONGLONGLONG,	.op = &mode_TI_op },
-	{ "word",	NS_KEYWORD,	MOD_LONG,	.op = &mode_word_op },
-	{ "__word__",	NS_KEYWORD,	MOD_LONG,	.op = &mode_word_op },
+	{ "QI",		NS_KEYWORD,	.op = &mode_QI_op },
+	{ "__QI__",	NS_KEYWORD,	.op = &mode_QI_op },
+	{ "HI",		NS_KEYWORD,	.op = &mode_HI_op },
+	{ "__HI__",	NS_KEYWORD,	.op = &mode_HI_op },
+	{ "SI",		NS_KEYWORD,	.op = &mode_SI_op },
+	{ "__SI__",	NS_KEYWORD,	.op = &mode_SI_op },
+	{ "DI",		NS_KEYWORD,	.op = &mode_DI_op },
+	{ "__DI__",	NS_KEYWORD,	.op = &mode_DI_op },
+	{ "TI",		NS_KEYWORD,	.op = &mode_TI_op },
+	{ "__TI__",	NS_KEYWORD,	.op = &mode_TI_op },
+	{ "byte",	NS_KEYWORD,	.op = &mode_QI_op },
+	{ "__byte__",	NS_KEYWORD,	.op = &mode_QI_op },
+	{ "pointer",	NS_KEYWORD,	.op = &mode_pointer_op },
+	{ "__pointer__",NS_KEYWORD,	.op = &mode_pointer_op },
+	{ "word",	NS_KEYWORD,	.op = &mode_word_op },
+	{ "__word__",	NS_KEYWORD,	.op = &mode_word_op },
 };
 
 
@@ -767,37 +808,38 @@
 	return struct_union_enum_specifier(SYM_UNION, token, ctx, parse_union_declaration);
 }
 
-
-typedef struct {
-	int x;
-	unsigned long long y;
-} Num;
-
-static void upper_boundary(Num *n, Num *v)
+///
+// safe right shift
+//
+// This allow to use a shift amount as big (or bigger)
+// than the width of the value to be shifted, in which case
+// the result is, of course, 0.
+static unsigned long long rshift(unsigned long long val, unsigned int n)
 {
-	if (n->x > v->x)
-		return;
-	if (n->x < v->x) {
-		*n = *v;
-		return;
-	}
-	if (n->y < v->y)
-		n->y = v->y;
+	if (n >= (sizeof(val) * 8))
+		return 0;
+	return val >> n;
 }
 
-static void lower_boundary(Num *n, Num *v)
+struct range {
+	long long		neg;
+	unsigned long long	pos;
+};
+
+static void update_range(struct range *range, unsigned long long uval, struct symbol *vtype)
 {
-	if (n->x < v->x)
-		return;
-	if (n->x > v->x) {
-		*n = *v;
-		return;
+	long long sval = uval;
+
+	if (is_signed_type(vtype) && (sval < 0)) {
+		if (sval < range->neg)
+			range->neg = sval;
+	} else {
+		if (uval > range->pos)
+			range->pos = uval;
 	}
-	if (n->y > v->y)
-		n->y = v->y;
 }
 
-static int type_is_ok(struct symbol *type, Num *upper, Num *lower)
+static int type_is_ok(struct symbol *type, struct range range)
 {
 	int shift = type->bit_size;
 	int is_unsigned = type->ctype.modifiers & MOD_UNSIGNED;
@@ -804,39 +846,70 @@
 
 	if (!is_unsigned)
 		shift--;
-	if (upper->x == 0 && upper->y >> shift)
+	if (rshift(range.pos, shift))
 		return 0;
-	if (lower->x == 0 || (!is_unsigned && (~lower->y >> shift) == 0))
+	if (range.neg == 0)
 		return 1;
-	return 0;
+	if (is_unsigned)
+		return 0;
+	if (rshift(~range.neg, shift))
+		return 0;
+	return 1;
 }
 
-static struct symbol *bigger_enum_type(struct symbol *s1, struct symbol *s2)
+static struct range type_range(struct symbol *type)
 {
-	if (s1->bit_size < s2->bit_size) {
-		s1 = s2;
-	} else if (s1->bit_size == s2->bit_size) {
-		if (s2->ctype.modifiers & MOD_UNSIGNED)
-			s1 = s2;
+	struct range range;
+	unsigned int size = type->bit_size;
+	unsigned long long max;
+	long long min;
+
+	if (is_signed_type(type)) {
+		min = sign_bit(size);
+		max = min - 1;
+	} else {
+		min = 0;
+		max = bits_mask(size);
 	}
-	if (s1->bit_size < bits_in_int)
-		return &int_ctype;
-	return s1;
+
+	range.pos = max;
+	range.neg = min;
+	return range;
 }
 
+static int val_in_range(struct range *range, long long sval, struct symbol *vtype)
+{
+	unsigned long long uval = sval;
+
+	if (is_signed_type(vtype) && (sval < 0))
+		return range->neg <= sval;
+	else
+		return uval <= range->pos;
+}
+
 static void cast_enum_list(struct symbol_list *list, struct symbol *base_type)
 {
+	struct range irange = type_range(&int_ctype);
 	struct symbol *sym;
 
 	FOR_EACH_PTR(list, sym) {
 		struct expression *expr = sym->initializer;
 		struct symbol *ctype;
+		long long val;
 		if (expr->type != EXPR_VALUE)
 			continue;
 		ctype = expr->ctype;
-		if (ctype->bit_size == base_type->bit_size)
+		val = get_expression_value(expr);
+		if (is_int_type(ctype) && val_in_range(&irange, val, ctype)) {
+			expr->ctype = &int_ctype;
 			continue;
+		}
+		if (ctype->bit_size == base_type->bit_size) {
+			expr->ctype = base_type;
+			continue;
+		}
 		cast_value(expr, base_type, expr, ctype);
+		expr->ctype = base_type;
 	} END_FOR_EACH_PTR(sym);
 }
 
@@ -844,7 +917,8 @@
 {
 	unsigned long long lastval = 0;
 	struct symbol *ctype = NULL, *base_type = NULL;
-	Num upper = {-1, 0}, lower = {1, 0};
+	struct range range = { };
+	int mix_bitwise = 0;
 
 	parent->examined = 1;
 	parent->ctype.base_type = &int_ctype;
@@ -900,26 +974,29 @@
 			 *    base type is at least "int_ctype".
 			 *  - otherwise the base_type is "bad_ctype".
 			 */
-			if (!base_type) {
+			if (!base_type || ctype == &bad_ctype) {
 				base_type = ctype;
 			} else if (ctype == base_type) {
 				/* nothing */
 			} else if (is_int_type(base_type) && is_int_type(ctype)) {
-				base_type = bigger_enum_type(base_type, ctype);
-			} else
+				base_type = &int_ctype;
+			} else if (is_restricted_type(base_type) != is_restricted_type(ctype)) {
+				if (!mix_bitwise++) {
+					warning(expr->pos, "mixed bitwiseness");
+				}
+			} else if (is_restricted_type(base_type) && base_type != ctype) {
+				sparse_error(expr->pos, "incompatible restricted type");
+				info(expr->pos, "   expected: %s", show_typename(base_type));
+				info(expr->pos, "        got: %s", show_typename(ctype));
 				base_type = &bad_ctype;
+			} else if (base_type != &bad_ctype) {
+				sparse_error(token->pos, "bad enum definition");
+				base_type = &bad_ctype;
+			}
 			parent->ctype.base_type = base_type;
 		}
 		if (is_int_type(base_type)) {
-			Num v = {.y = lastval};
-			if (ctype->ctype.modifiers & MOD_UNSIGNED)
-				v.x = 0;
-			else if ((long long)lastval >= 0)
-				v.x = 0;
-			else
-				v.x = -1;
-			upper_boundary(&upper, &v);
-			lower_boundary(&lower, &v);
+			update_range(&range, lastval, ctype);
 		}
 		token = next;
 
@@ -930,25 +1007,23 @@
 		token = token->next;
 	}
 	if (!base_type) {
-		sparse_error(token->pos, "bad enum definition");
+		sparse_error(token->pos, "empty enum definition");
 		base_type = &bad_ctype;
 	}
 	else if (!is_int_type(base_type))
-		base_type = base_type;
-	else if (type_is_ok(base_type, &upper, &lower))
-		base_type = base_type;
-	else if (type_is_ok(&int_ctype, &upper, &lower))
-		base_type = &int_ctype;
-	else if (type_is_ok(&uint_ctype, &upper, &lower))
+		;
+	else if (type_is_ok(&uint_ctype, range))
 		base_type = &uint_ctype;
-	else if (type_is_ok(&long_ctype, &upper, &lower))
-		base_type = &long_ctype;
-	else if (type_is_ok(&ulong_ctype, &upper, &lower))
+	else if (type_is_ok(&int_ctype, range))
+		base_type = &int_ctype;
+	else if (type_is_ok(&ulong_ctype, range))
 		base_type = &ulong_ctype;
-	else if (type_is_ok(&llong_ctype, &upper, &lower))
-		base_type = &llong_ctype;
-	else if (type_is_ok(&ullong_ctype, &upper, &lower))
+	else if (type_is_ok(&long_ctype, range))
+		base_type = &long_ctype;
+	else if (type_is_ok(&ullong_ctype, range))
 		base_type = &ullong_ctype;
+	else if (type_is_ok(&llong_ctype, range))
+		base_type = &llong_ctype;
 	else
 		base_type = &bad_ctype;
 	parent->ctype.base_type = base_type;
@@ -955,6 +1030,8 @@
 	parent->ctype.modifiers |= (base_type->ctype.modifiers & MOD_UNSIGNED);
 	parent->examined = 0;
 
+	if (mix_bitwise)
+		return token;
 	cast_enum_list(parent->symbol_list, base_type);
 
 	return token;
@@ -1043,6 +1120,12 @@
 	return token;
 }
 
+static struct token *attribute_ext_visible(struct token *token, struct symbol *attr, struct decl_state *ctx)
+{
+	ctx->is_ext_visible = 1;
+	return token;
+}
+
 static struct token *attribute_bitwise(struct token *token, struct symbol *attr, struct decl_state *ctx)
 {
 	if (Wbitwise)
@@ -1050,18 +1133,49 @@
 	return token;
 }
 
+static struct ident *numerical_address_space(int asn)
+{
+	char buff[32];
+
+	if (!asn)
+		return NULL;
+	sprintf(buff, "<asn:%d>", asn);
+	return built_in_ident(buff);
+}
+
 static struct token *attribute_address_space(struct token *token, struct symbol *attr, struct decl_state *ctx)
 {
 	struct expression *expr = NULL;
-	int as;
+	struct ident *as = NULL;
+	struct token *next;
+
 	token = expect(token, '(', "after address_space attribute");
-	token = conditional_expression(token, &expr);
-	if (expr) {
-		as = const_expression_value(expr);
-		if (Waddress_space && as)
-			ctx->ctype.as = as;
+	switch (token_type(token)) {
+	case TOKEN_NUMBER:
+		next = primary_expression(token, &expr);
+		if (expr->type != EXPR_VALUE)
+			goto invalid;
+		as = numerical_address_space(expr->value);
+		break;
+	case TOKEN_IDENT:
+		next = token->next;
+		as = token->ident;
+		break;
+	default:
+		next = token->next;
+	invalid:
+		as = NULL;
+		warning(token->pos, "invalid address space name");
 	}
-	token = expect(token, ')', "after address_space attribute");
+
+	if (Waddress_space && as) {
+		if (ctx->ctype.as)
+			sparse_error(token->pos,
+				     "multiple address space given: %s & %s",
+				     show_as(ctx->ctype.as), show_as(as));
+		ctx->ctype.as = as;
+	}
+	token = expect(next, ')', "after address_space attribute");
 	return token;
 }
 
@@ -1107,6 +1221,14 @@
 						     : &slllong_ctype;
 }
 
+static struct symbol *to_pointer_mode(struct symbol *ctype)
+{
+	if (ctype->ctype.base_type != &int_type)
+		return NULL;
+	return ctype->ctype.modifiers & MOD_UNSIGNED ? uintptr_ctype
+						     :  intptr_ctype;
+}
+
 static struct symbol *to_word_mode(struct symbol *ctype)
 {
 	if (ctype->ctype.base_type != &int_type)
@@ -1123,7 +1245,7 @@
 		if (mode && mode->op->type == KW_MODE)
 			ctx->mode = mode->op;
 		else
-			sparse_error(token->pos, "unknown mode attribute %s\n", show_ident(token->ident));
+			sparse_error(token->pos, "unknown mode attribute %s", show_ident(token->ident));
 		token = token->next;
 	} else
 		sparse_error(token->pos, "expect attribute mode symbol\n");
@@ -1135,43 +1257,24 @@
 {
 	struct context *context = alloc_context();
 	struct expression *args[3];
-	int argc = 0;
+	int idx = 0;
 
 	token = expect(token, '(', "after context attribute");
-	while (!match_op(token, ')')) {
-		struct expression *expr = NULL;
-		token = conditional_expression(token, &expr);
-		if (!expr)
-			break;
-		if (argc < 3)
-			args[argc++] = expr;
-		if (!match_op(token, ','))
-			break;
+	token = conditional_expression(token, &args[0]);
+	token = expect(token, ',', "after context 1st argument");
+	token = conditional_expression(token, &args[1]);
+	if (match_op(token, ',')) {
 		token = token->next;
-	}
-
-	switch(argc) {
-	case 0:
-		sparse_error(token->pos, "expected context input/output values");
-		break;
-	case 1:
-		context->in = get_expression_value(args[0]);
-		break;
-	case 2:
-		context->in = get_expression_value(args[0]);
-		context->out = get_expression_value(args[1]);
-		break;
-	case 3:
+		token = conditional_expression(token, &args[2]);
+		token = expect(token, ')', "after context 3rd argument");
 		context->context = args[0];
-		context->in = get_expression_value(args[1]);
-		context->out = get_expression_value(args[2]);
-		break;
+		idx++;
+	} else {
+		token = expect(token, ')', "after context 2nd argument");
 	}
-
-	if (argc)
-		add_ptr_list(&ctx->ctype.contexts, context);
-
-	token = expect(token, ')', "after context attribute");
+	context->in =  get_expression_value(args[idx++]);
+	context->out = get_expression_value(args[idx++]);
+	add_ptr_list(&ctx->ctype.contexts, context);
 	return token;
 }
 
@@ -1201,7 +1304,7 @@
 	struct expression *expr = NULL;
 
 	if (Wunknown_attribute)
-		warning(token->pos, "attribute '%s': unknown attribute", show_ident(token->ident));
+		warning(token->pos, "unknown attribute '%s'", show_ident(token->ident));
 	token = token->next;
 	if (match_op(token, '('))
 		token = parens_expression(token, &expr, "in attribute");
@@ -1260,7 +1363,8 @@
 		[SRegister] = MOD_REGISTER
 	};
 	return mod[ctx->storage_class] | (ctx->is_inline ? MOD_INLINE : 0)
-		| (ctx->is_tls ? MOD_TLS : 0);
+		| (ctx->is_tls ? MOD_TLS : 0)
+		| (ctx->is_ext_visible ? MOD_EXT_VISIBLE : 0);
 }
 
 static void set_storage_class(struct position *pos, struct decl_state *ctx, int class)
@@ -1391,6 +1495,18 @@
 	return next;
 }
 
+static struct token *restrict_qualifier(struct token *next, struct decl_state *ctx)
+{
+	apply_qualifier(&next->pos, &ctx->ctype, MOD_RESTRICT);
+	return next;
+}
+
+static struct token *atomic_qualifier(struct token *next, struct decl_state *ctx)
+{
+	apply_qualifier(&next->pos, &ctx->ctype, MOD_ATOMIC);
+	return next;
+}
+
 static void apply_ctype(struct position pos, struct ctype *thistype, struct ctype *ctype)
 {
 	unsigned long mod = thistype->modifiers;
@@ -1705,7 +1821,6 @@
 
 	if (next->special == ')') {
 		/* don't complain about those */
-		if (!n || match_op(next->next, ';'))
 		if (!n || match_op(next->next, ';') || match_op(next->next, ','))
 			return Empty;
 		if (Wstrict_prototypes)
@@ -1781,7 +1896,7 @@
 		ptr->ctype.contexts = ctx->ctype.contexts;
 		ctx->ctype.modifiers = 0;
 		ctx->ctype.base_type = ptr;
-		ctx->ctype.as = 0;
+		ctx->ctype.as = NULL;
 		ctx->ctype.contexts = NULL;
 		ctx->ctype.alignment = 0;
 
@@ -1964,24 +2079,20 @@
 static struct token *parse_asm_operands(struct token *token, struct statement *stmt,
 	struct expression_list **inout)
 {
-	struct expression *expr;
-
 	/* Allow empty operands */
 	if (match_op(token->next, ':') || match_op(token->next, ')'))
 		return token->next;
 	do {
-		struct ident *ident = NULL;
+		struct expression *op = alloc_expression(token->pos, EXPR_ASM_OPERAND);
 		if (match_op(token->next, '[') &&
 		    token_type(token->next->next) == TOKEN_IDENT &&
 		    match_op(token->next->next->next, ']')) {
-			ident = token->next->next->ident;
+			op->name = token->next->next->ident;
 			token = token->next->next->next;
 		}
-		add_expression(inout, (struct expression *)ident); /* UGGLEE!!! */
-		token = primary_expression(token->next, &expr);
-		add_expression(inout, expr);
-		token = parens_expression(token, &expr, "in asm parameter");
-		add_expression(inout, expr);
+		token = primary_expression(token->next, &op->constraint);
+		token = parens_expression(token, &op->expr, "in asm parameter");
+		add_expression(inout, op);
 	} while (match_op(token, ','));
 	return token;
 }
@@ -2017,17 +2128,18 @@
 
 static struct token *parse_asm_statement(struct token *token, struct statement *stmt)
 {
-	int is_goto = 0;
+	unsigned long mods = 0;
 
 	token = token->next;
 	stmt->type = STMT_ASM;
-	if (match_idents(token, &__volatile___ident, &__volatile_ident, &volatile_ident, NULL)) {
+	while (token_type(token) == TOKEN_IDENT) {
+		struct symbol *s = lookup_keyword(token->ident, NS_TYPEDEF);
+		if (s && s->op  && s->op->asm_modifier)
+			s->op->asm_modifier(token, &mods);
+		else if (token->ident == &goto_ident)
+			asm_modifier(token, &mods, MOD_ASM_GOTO);
 		token = token->next;
 	}
-	if (token_type(token) == TOKEN_IDENT && token->ident == &goto_ident) {
-		is_goto = 1;
-		token = token->next;
-	}
 	token = expect(token, '(', "after asm");
 	token = parse_expression(token, &stmt->asm_string);
 	if (match_op(token, ':'))
@@ -2036,7 +2148,7 @@
 		token = parse_asm_operands(token, stmt, &stmt->asm_inputs);
 	if (match_op(token, ':'))
 		token = parse_asm_clobbers(token, stmt, &stmt->asm_clobbers);
-	if (is_goto && match_op(token, ':'))
+	if (match_op(token, ':') && (mods & MOD_ASM_GOTO))
 		token = parse_asm_labels(token, stmt, &stmt->asm_labels);
 	token = expect(token, ')', "after asm");
 	return expect(token, ';', "at end of asm-statement");
@@ -2129,7 +2241,7 @@
 	start_function_scope(sym->pos);
 	ret = alloc_symbol(sym->pos, SYM_NODE);
 	ret->ctype = sym->ctype.base_type->ctype;
-	ret->ctype.modifiers &= ~(MOD_STORAGE | MOD_CONST | MOD_VOLATILE | MOD_TLS | MOD_INLINE | MOD_ADDRESSABLE | MOD_NOCAST | MOD_NODEREF | MOD_ACCESSED | MOD_TOPLEVEL);
+	ret->ctype.modifiers &= ~(MOD_STORAGE | MOD_QUALIFIER | MOD_TLS | MOD_ACCESS | MOD_NOCAST | MOD_NODEREF);
 	ret->ctype.modifiers |= (MOD_AUTO | MOD_REGISTER);
 	bind_symbol(ret, &return_ident, NS_ITERATOR);
 	stmt->ret = ret;
@@ -2372,15 +2484,19 @@
 static struct token *parse_context_statement(struct token *token, struct statement *stmt)
 {
 	stmt->type = STMT_CONTEXT;
-	token = parse_expression(token->next, &stmt->expression);
-	if (stmt->expression->type == EXPR_PREOP
-	    && stmt->expression->op == '('
-	    && stmt->expression->unop->type == EXPR_COMMA) {
-		struct expression *expr;
-		expr = stmt->expression->unop;
-		stmt->context = expr->left;
-		stmt->expression = expr->right;
+	token = token->next;
+	token = expect(token, '(', "after __context__ statement");
+	token = assignment_expression(token, &stmt->expression);
+	if (!stmt->expression)
+		unexpected(token, "expression expected after '('");
+	if (match_op(token, ',')) {
+		token = token->next;
+		stmt->context = stmt->expression;
+		token = assignment_expression(token, &stmt->expression);
+		if (!stmt->expression)
+			unexpected(token, "expression expected after ','");
 	}
+	token = expect(token, ')', "at end of __context__ statement");
 	return expect(token, ';', "at end of statement");
 }
 
@@ -2387,11 +2503,14 @@
 static struct token *parse_range_statement(struct token *token, struct statement *stmt)
 {
 	stmt->type = STMT_RANGE;
-	token = assignment_expression(token->next, &stmt->range_expression);
+	token = token->next;
+	token = expect(token, '(', "after __range__ statement");
+	token = assignment_expression(token, &stmt->range_expression);
 	token = expect(token, ',', "after range expression");
 	token = assignment_expression(token, &stmt->range_low);
 	token = expect(token, ',', "after low range");
 	token = assignment_expression(token, &stmt->range_high);
+	token = expect(token, ')', "after range statement");
 	return expect(token, ';', "after range statement");
 }
 
@@ -2407,12 +2526,15 @@
 
 		if (match_op(token->next, ':')) {
 			struct symbol *s = label_symbol(token);
+			token = skip_attributes(token->next->next);
+			if (s->stmt) {
+				sparse_error(stmt->pos, "label '%s' redefined", show_ident(s->ident));
+				// skip the label to avoid multiple definitions
+				return statement(token, tree);
+			}
 			stmt->type = STMT_LABEL;
 			stmt->label_identifier = s;
-			if (s->stmt)
-				sparse_error(stmt->pos, "label '%s' redefined", show_ident(token->ident));
 			s->stmt = stmt;
-			token = skip_attributes(token->next->next);
 			return statement(token, &stmt->label_statement);
 		}
 	}
@@ -2697,11 +2819,10 @@
 	function_computed_target_list = NULL;
 	function_computed_goto_list = NULL;
 
-	if (decl->ctype.modifiers & MOD_EXTERN &&
-		!(decl->ctype.modifiers & MOD_INLINE) &&
-		Wexternal_function_has_definition)
-		warning(decl->pos, "function '%s' with external linkage has definition", show_ident(decl->ident));
-
+	if ((decl->ctype.modifiers & (MOD_EXTERN|MOD_INLINE)) == MOD_EXTERN) {
+		if (Wexternal_function_has_definition)
+			warning(decl->pos, "function '%s' with external linkage has definition", show_ident(decl->ident));
+	}
 	if (!(decl->ctype.modifiers & MOD_STATIC))
 		decl->ctype.modifiers |= MOD_EXTERN;
 
@@ -2777,7 +2898,9 @@
 			sparse_error(arg->pos, "missing type declaration for parameter '%s'",
 				show_ident(arg->ident));
 		}
-		continue;
+		type = alloc_symbol(arg->pos, SYM_NODE);
+		type->ident = arg->ident;
+		type->ctype.base_type = &int_ctype;
 match:
 		type->used = 1;
 		/* "char" and "short" promote to "int" */
@@ -2950,6 +3073,10 @@
 		if (decl->same_symbol) {
 			decl->definition = decl->same_symbol->definition;
 			decl->op = decl->same_symbol->op;
+			if (is_typedef) {
+				// TODO: handle -std=c89 --pedantic
+				check_duplicates(decl);
+			}
 		}
 
 		if (!match_op(token, ','))
--- old/usr/src/tools/smatch/src/parse.h	Mon Nov 18 13:19:03 2019
+++ new/usr/src/tools/smatch/src/parse.h	Mon Nov 18 13:19:03 2019
@@ -135,7 +135,6 @@
 
 extern struct symbol *ctype_integer(int size, int want_unsigned);
 
-extern void copy_statement(struct statement *src, struct statement *dst);
 extern int inline_function(struct expression *expr, struct symbol *sym);
 extern void uninline(struct symbol *sym);
 extern void init_parser(int);
--- old/usr/src/tools/smatch/src/pre-process.c	Mon Nov 18 13:19:03 2019
+++ new/usr/src/tools/smatch/src/pre-process.c	Mon Nov 18 13:19:03 2019
@@ -49,6 +49,7 @@
 static struct ident_list *macros;	// only needed for -dD
 static int false_nesting = 0;
 static int counter_macro = 0;		// __COUNTER__ expansion
+static int include_level = 0;
 
 #define INCLUDEPATHS 300
 const char *includepath[INCLUDEPATHS+1] = {
@@ -147,49 +148,96 @@
 	return 0;
 }
 
-static void replace_with_defined(struct token *token)
+static void replace_with_bool(struct token *token, bool val)
 {
 	static const char *string[] = { "0", "1" };
-	int defined = token_defined(token);
 
 	token_type(token) = TOKEN_NUMBER;
-	token->number = string[defined];
+	token->number = string[val];
 }
 
+static void replace_with_defined(struct token *token)
+{
+	replace_with_bool(token, token_defined(token));
+}
+
+static void replace_with_has_builtin(struct token *token)
+{
+	struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
+	replace_with_bool(token, sym && sym->builtin);
+}
+
+static void replace_with_has_attribute(struct token *token)
+{
+	struct symbol *sym = lookup_symbol(token->ident, NS_KEYWORD);
+	replace_with_bool(token, sym && sym->op && sym->op->attribute);
+}
+
+static void expand_line(struct token *token)
+{
+	replace_with_integer(token, token->pos.line);
+}
+
+static void expand_file(struct token *token)
+{
+	replace_with_string(token, stream_name(token->pos.stream));
+}
+
+static void expand_basefile(struct token *token)
+{
+	replace_with_string(token, base_filename);
+}
+
+static time_t t = 0;
+static void expand_date(struct token *token)
+{
+	static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
+
+	if (!t)
+		time(&t);
+	strftime(buffer, 12, "%b %e %Y", localtime(&t));
+	replace_with_string(token, buffer);
+}
+
+static void expand_time(struct token *token)
+{
+	static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */
+
+	if (!t)
+		time(&t);
+	strftime(buffer, 9, "%T", localtime(&t));
+	replace_with_string(token, buffer);
+}
+
+static void expand_counter(struct token *token)
+{
+	replace_with_integer(token, counter_macro++);
+}
+
+static void expand_include_level(struct token *token)
+{
+	replace_with_integer(token, include_level - 1);
+}
+
 static int expand_one_symbol(struct token **list)
 {
 	struct token *token = *list;
 	struct symbol *sym;
-	static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
-	static time_t t = 0;
 
 	if (token->pos.noexpand)
 		return 1;
 
 	sym = lookup_macro(token->ident);
-	if (sym) {
-		store_macro_pos(token);
+	if (!sym)
+		return 1;
+	store_macro_pos(token);
+	if (sym->expander) {
+		sym->expander(token);
+		return 1;
+	} else {
 		sym->used_in = file_scope;
 		return expand(list, sym);
 	}
-	if (token->ident == &__LINE___ident) {
-		replace_with_integer(token, token->pos.line);
-	} else if (token->ident == &__FILE___ident) {
-		replace_with_string(token, stream_name(token->pos.stream));
-	} else if (token->ident == &__DATE___ident) {
-		if (!t)
-			time(&t);
-		strftime(buffer, 12, "%b %e %Y", localtime(&t));
-		replace_with_string(token, buffer);
-	} else if (token->ident == &__TIME___ident) {
-		if (!t)
-			time(&t);
-		strftime(buffer, 9, "%T", localtime(&t));
-		replace_with_string(token, buffer);
-	} else if (token->ident == &__COUNTER___ident) {
-		replace_with_integer(token, counter_macro++);
-	}
-	return 1;
 }
 
 static inline struct token *scan_next(struct token **where)
@@ -514,13 +562,10 @@
 		left->pos.noexpand = 0;
 		return 1;
 
-	case TOKEN_NUMBER: {
-		char *number = __alloc_bytes(strlen(buffer) + 1);
-		memcpy(number, buffer, strlen(buffer) + 1);
+	case TOKEN_NUMBER:
 		token_type(left) = TOKEN_NUMBER;	/* could be . + num */
-		left->number = number;
+		left->number = xstrdup(buffer);
 		return 1;
-	}
 
 	case TOKEN_SPECIAL:
 		if (buffer[2] && buffer[3])
@@ -851,6 +896,10 @@
 	includepath[0] = path;
 }
 
+#ifndef PATH_MAX
+#define PATH_MAX 4096	// for Hurd where it's not defined
+#endif
+
 static int try_include(const char *path, const char *filename, int flen, struct token **where, const char **next_path)
 {
 	int fd;
@@ -867,8 +916,7 @@
 		return 1;
 	fd = open(fullname, O_RDONLY);
 	if (fd >= 0) {
-		char * streamname = __alloc_bytes(plen + flen);
-		memcpy(streamname, fullname, plen + flen);
+		char *streamname = xmemdup(fullname, plen + flen);
 		*where = tokenize(streamname, fd, *where, next_path);
 		close(fd);
 		return 1;
@@ -912,7 +960,7 @@
 		return NULL;
 
 	if (!getcwd(cwd, sizeof(cwd)))
-		return NULL;
+		goto close;
 
 	while ((entry = readdir(dp))) {
 		lstat(entry->d_name, &statbuf);
@@ -919,6 +967,7 @@
 
 		if (strcmp(entry->d_name, look_for) == 0) {
 			snprintf(buf, sizeof(buf), "%s/%s", cwd, entry->d_name);
+			closedir(dp);
 			return buf;
 		}
 
@@ -932,10 +981,13 @@
 			chdir(entry->d_name);
 			ret = find_include("", look_for);
 			chdir("..");
-			if (ret)
+			if (ret) {
+				closedir(dp);
 				return ret;
+			}
 		}
 	}
+close:
 	closedir(dp);
 
 	return NULL;
@@ -982,8 +1034,13 @@
 	char dir_part[PATH_MAX];
 	const char *file_part;
 	const char *include_name;
+	static int cnt;
 	int len;
 
+	/* Avoid guessing includes recursively. */
+	if (cnt++ > 1000)
+		return;
+
 	if (!filename || filename[0] == '\0')
 		return;
 
@@ -1420,40 +1477,16 @@
 	return NULL;
 }
 
-static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
+static int do_define(struct position pos, struct token *token, struct ident *name,
+		     struct token *arglist, struct token *expansion, int attr)
 {
-	struct token *arglist, *expansion;
-	struct token *left = token->next;
 	struct symbol *sym;
-	struct ident *name;
-	int ret;
+	int ret = 1;
 
-	if (token_type(left) != TOKEN_IDENT) {
-		sparse_error(token->pos, "expected identifier to 'define'");
-		return 1;
-	}
-
-	name = left->ident;
-
-	arglist = NULL;
-	expansion = left->next;
-	if (!expansion->pos.whitespace) {
-		if (match_op(expansion, '(')) {
-			arglist = expansion;
-			expansion = parse_arguments(expansion);
-			if (!expansion)
-				return 1;
-		} else if (!eof_token(expansion)) {
-			warning(expansion->pos,
-				"no whitespace before object-like macro body");
-		}
-	}
-
 	expansion = parse_expansion(expansion, arglist, name);
 	if (!expansion)
 		return 1;
 
-	ret = 1;
 	sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
 	if (sym) {
 		int clean;
@@ -1468,7 +1501,7 @@
 			ret = 0;
 			if ((clean && attr == SYM_ATTR_NORMAL)
 					|| sym->used_in == file_scope) {
-				warning(left->pos, "preprocessor token %.*s redefined",
+				warning(pos, "preprocessor token %.*s redefined",
 						name->len, name->name);
 				info(sym->pos, "this was the original definition");
 			}
@@ -1477,7 +1510,7 @@
 	}
 
 	if (!sym || sym->scope != file_scope) {
-		sym = alloc_symbol(left->pos, SYM_NODE);
+		sym = alloc_symbol(pos, SYM_NODE);
 		bind_symbol(sym, name, NS_MACRO);
 		add_ident(&macros, name);
 		ret = 0;
@@ -1486,7 +1519,8 @@
 	if (!ret) {
 		sym->expansion = expansion;
 		sym->arglist = arglist;
-		__free_token(token);	/* Free the "define" token, but not the rest of the line */
+		if (token) /* Free the "define" token, but not the rest of the line */
+			__free_token(token);
 	}
 
 	sym->namespace = NS_MACRO;
@@ -1496,6 +1530,74 @@
 	return ret;
 }
 
+///
+// predefine a macro with a printf-formatted value
+// @name: the name of the macro
+// @weak: 0/1 for a normal or a weak define
+// @fmt: the printf format followed by it's arguments.
+//
+// The type of the value is automatically infered:
+// TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise.
+// If @fmt is null or empty, the macro is defined with an empty definition.
+void predefine(const char *name, int weak, const char *fmt, ...)
+{
+	struct ident *ident = built_in_ident(name);
+	struct token *value = &eof_token_entry;
+	int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL;
+
+	if (fmt && fmt[0]) {
+		static char buf[256];
+		va_list ap;
+
+		va_start(ap, fmt);
+		vsnprintf(buf, sizeof(buf), fmt, ap);
+		va_end(ap);
+
+		value = __alloc_token(0);
+		if (isdigit(buf[0])) {
+			token_type(value) = TOKEN_NUMBER;
+			value->number = xstrdup(buf);
+		} else {
+			token_type(value) = TOKEN_IDENT;
+			value->ident = built_in_ident(buf);
+		}
+		value->pos.whitespace = 1;
+		value->next = &eof_token_entry;
+	}
+
+	do_define(value->pos, NULL, ident, NULL, value, attr);
+}
+
+static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
+{
+	struct token *arglist, *expansion;
+	struct token *left = token->next;
+	struct ident *name;
+
+	if (token_type(left) != TOKEN_IDENT) {
+		sparse_error(token->pos, "expected identifier to 'define'");
+		return 1;
+	}
+
+	name = left->ident;
+
+	arglist = NULL;
+	expansion = left->next;
+	if (!expansion->pos.whitespace) {
+		if (match_op(expansion, '(')) {
+			arglist = expansion;
+			expansion = parse_arguments(expansion);
+			if (!expansion)
+				return 1;
+		} else if (!eof_token(expansion)) {
+			warning(expansion->pos,
+				"no whitespace before object-like macro body");
+		}
+	}
+
+	return do_define(left->pos, token, name, arglist, expansion, attr);
+}
+
 static int handle_define(struct stream *stream, struct token **line, struct token *token)
 {
 	return do_handle_define(stream, line, token, SYM_ATTR_NORMAL);
@@ -1552,13 +1654,13 @@
 	return do_handle_undef(stream, line, token, SYM_ATTR_STRONG);
 }
 
-static int preprocessor_if(struct stream *stream, struct token *token, int true)
+static int preprocessor_if(struct stream *stream, struct token *token, int cond)
 {
 	token_type(token) = false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF;
 	free_preprocessor_line(token->next);
 	token->next = stream->top_if;
 	stream->top_if = token;
-	if (false_nesting || true != 1)
+	if (false_nesting || cond != 1)
 		false_nesting++;
 	return 0;
 }
@@ -1626,6 +1728,14 @@
 				state = 1;
 				beginning = list;
 				break;
+			} else if (p->ident == &__has_builtin_ident) {
+				state = 4;
+				beginning = list;
+				break;
+			} else if (p->ident == &__has_attribute_ident) {
+				state = 6;
+				beginning = list;
+				break;
 			}
 			if (!expand_one_symbol(list))
 				continue;
@@ -1656,6 +1766,38 @@
 				sparse_error(p->pos, "missing ')' after \"defined\"");
 			*list = p->next;
 			continue;
+
+		// __has_builtin(x) or __has_attribute(x)
+		case 4: case 6:
+			if (match_op(p, '(')) {
+				state++;
+			} else {
+				sparse_error(p->pos, "missing '(' after \"__has_%s\"",
+					state == 4 ? "builtin" : "attribute");
+				state = 0;
+			}
+			*beginning = p;
+			break;
+		case 5: case 7:
+			if (token_type(p) != TOKEN_IDENT) {
+				sparse_error(p->pos, "identifier expected");
+				state = 0;
+				break;
+			}
+			if (!match_op(p->next, ')'))
+				sparse_error(p->pos, "missing ')' after \"__has_%s\"",
+					state == 5 ? "builtin" : "attribute");
+			if (state == 5)
+				replace_with_has_builtin(p);
+			else
+				replace_with_has_attribute(p);
+			state = 8;
+			*beginning = p;
+			break;
+		case 8:
+			state = 0;
+			*list = p->next;
+			continue;
 		}
 		list = &p->next;
 	}
@@ -1969,9 +2111,6 @@
 	return 1;
 }
 
-/*
- * Ignore "#ident".
- */
 static int handle_ident(struct stream *stream, struct token **line, struct token *token)
 {
 	return 1;
@@ -2021,6 +2160,18 @@
 		{ "if",		handle_if },
 		{ "elif",	handle_elif },
 	};
+	static struct {
+		const char *name;
+		void (*expander)(struct token *);
+	} dynamic[] = {
+		{ "__LINE__",		expand_line },
+		{ "__FILE__",		expand_file },
+		{ "__BASE_FILE__",	expand_basefile },
+		{ "__DATE__",		expand_date },
+		{ "__TIME__",		expand_time },
+		{ "__COUNTER__",	expand_counter },
+		{ "__INCLUDE_LEVEL__",	expand_include_level },
+	};
 
 	for (i = 0; i < ARRAY_SIZE(normal); i++) {
 		struct symbol *sym;
@@ -2034,6 +2185,11 @@
 		sym->handler = special[i].handler;
 		sym->normal = 0;
 	}
+	for (i = 0; i < ARRAY_SIZE(dynamic); i++) {
+		struct symbol *sym;
+		sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO);
+		sym->expander = dynamic[i].expander;
+	}
 
 	counter_macro = 0;
 }
@@ -2115,9 +2271,11 @@
 			if (!stream->dirty)
 				stream->constant = CONSTANT_FILE_YES;
 			*list = next->next;
+			include_level--;
 			continue;
 		case TOKEN_STREAMBEGIN:
 			*list = next->next;
+			include_level++;
 			continue;
 
 		default:
@@ -2179,6 +2337,12 @@
 	return token;
 }
 
+static int is_VA_ARGS_token(struct token *token)
+{
+	return (token_type(token) == TOKEN_IDENT) &&
+		(token->ident == &__VA_ARGS___ident);
+}
+
 static void dump_macro(struct symbol *sym)
 {
 	int nargs = sym->arglist ? sym->arglist->count.normal : 0;
@@ -2194,27 +2358,34 @@
 		for (; !eof_token(token); token = token->next) {
 			if (token_type(token) == TOKEN_ARG_COUNT)
 				continue;
-			printf("%s%s", sep, show_token(token));
+			if (is_VA_ARGS_token(token))
+				printf("%s...", sep);
+			else
+				printf("%s%s", sep, show_token(token));
 			args[narg++] = token;
-			sep = ", ";
+			sep = ",";
 		}
 		putchar(')');
 	}
-	putchar(' ');
 
 	token = sym->expansion;
-	while (!eof_token(token)) {
+	while (token_type(token) != TOKEN_UNTAINT) {
 		struct token *next = token->next;
+		if (token->pos.whitespace)
+			putchar(' ');
 		switch (token_type(token)) {
-		case TOKEN_UNTAINT:
+		case TOKEN_CONCAT:
+			printf("##");
 			break;
+		case TOKEN_STR_ARGUMENT:
+			printf("#");
+			/* fall-through */
+		case TOKEN_QUOTED_ARGUMENT:
 		case TOKEN_MACRO_ARGUMENT:
 			token = args[token->argnum];
 			/* fall-through */
 		default:
 			printf("%s", show_token(token));
-			if (next->pos.whitespace)
-				putchar(' ');
 		}
 		token = next;
 	}
--- old/usr/src/tools/smatch/src/ptrlist.c	Mon Nov 18 13:19:04 2019
+++ new/usr/src/tools/smatch/src/ptrlist.c	Mon Nov 18 13:19:04 2019
@@ -1,10 +1,13 @@
 /*
  * ptrlist.c
  *
- * Pointer list manipulation
- *
  * (C) Copyright Linus Torvalds 2003-2005
  */
+
+///
+// Pointer list manipulation
+// -------------------------
+
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
@@ -17,6 +20,10 @@
 __ALLOCATOR(struct ptr_list, "ptr list", ptrlist);
 __ALLOCATOR(struct ptr_list, "rl ptr list", rl_ptrlist);
 
+///
+// get the size of a ptrlist
+// @head: the head of the list
+// @return: the size of the list given by @head.
 int ptr_list_size(struct ptr_list *head)
 {
 	int nr = 0;
@@ -30,14 +37,120 @@
 	return nr;
 }
 
-/*
- * Linearize the entries of a list up to a total of 'max',
- * and return the nr of entries linearized.
- *
- * The array to linearize into (second argument) should really
- * be "void *x[]", but we want to let people fill in any kind
- * of pointer array, so let's just call it "void **".
- */
+///
+// test if a list is empty
+// @head: the head of the list
+// @return: ``true`` if the list is empty, ``false`` otherwise.
+bool ptr_list_empty(const struct ptr_list *head)
+{
+	const struct ptr_list *list = head;
+
+	if (!head)
+		return true;
+
+	do {
+		if (list->nr - list->rm)
+			return false;
+	} while ((list = list->next) != head);
+
+	return true;
+}
+
+///
+// test is a list contains more than one element
+// @head: the head of the list
+// @return: ``true`` if the list has more than 1 element, ``false`` otherwise.
+bool ptr_list_multiple(const struct ptr_list *head)
+{
+	const struct ptr_list *list = head;
+	int nr = 0;
+
+	if (!head)
+		return false;
+
+	do {
+		nr += list->nr - list->rm;
+		if (nr > 1)
+			return true;
+	} while ((list = list->next) != head);
+
+	return false;
+}
+
+///
+// get the first element of a ptrlist
+// @head: the head of the list
+// @return: the first element of the list or ``NULL`` if the list is empty
+void *first_ptr_list(struct ptr_list *head)
+{
+	struct ptr_list *list = head;
+
+	if (!head)
+		return NULL;
+
+	while (list->nr == 0) {
+		list = list->next;
+		if (list == head)
+			return NULL;
+	}
+	return PTR_ENTRY_NOTAG(list, 0);
+}
+
+///
+// get the last element of a ptrlist
+// @head: the head of the list
+// @return: the last element of the list or ``NULL`` if the list is empty
+void *last_ptr_list(struct ptr_list *head)
+{
+	struct ptr_list *list;
+
+	if (!head)
+		return NULL;
+	list = head->prev;
+	while (list->nr == 0) {
+		if (list == head)
+			return NULL;
+		list = list->prev;
+	}
+	return PTR_ENTRY_NOTAG(list, list->nr-1);
+}
+
+///
+// get the nth element of a ptrlist
+// @head: the head of the list
+// @return: the nth element of the list or ``NULL`` if the list is too short.
+void *ptr_list_nth_entry(struct ptr_list *list, unsigned int idx)
+{
+	struct ptr_list *head = list;
+
+	if (!head)
+		return NULL;
+
+	do {
+		unsigned int nr = list->nr;
+
+		if (idx < nr)
+			return list->list[idx];
+		else
+			idx -= nr;
+	} while ((list = list->next) != head);
+	return NULL;
+}
+
+///
+// linearize the entries of a list
+//
+// @head: the list to be linearized
+// @arr: a ``void*`` array to fill with @head's entries
+// @max: the maximum number of entries to store into @arr
+// @return: the number of entries linearized.
+//
+// Linearize the entries of a list up to a total of @max,
+// and return the nr of entries linearized.
+//
+// The array to linearize into (@arr) should really
+// be ``void *x[]``, but we want to let people fill in any kind
+// of pointer array, so let's just call it ``void **``.
 int linearize_ptr_list(struct ptr_list *head, void **arr, int max)
 {
 	int nr = 0;
@@ -59,12 +172,15 @@
 	return nr;
 }
 
-/*
- * When we've walked the list and deleted entries,
- * we may need to re-pack it so that we don't have
- * any empty blocks left (empty blocks upset the
- * walking code
- */
+///
+// pack a ptrlist
+//
+// @listp: a pointer to the list to be packed.
+//
+// When we've walked the list and deleted entries,
+// we may need to re-pack it so that we don't have
+// any empty blocks left (empty blocks upset the
+// walking code).
 void pack_ptr_list(struct ptr_list **listp)
 {
 	struct ptr_list *head = *listp;
@@ -98,6 +214,13 @@
 	}
 }		
 
+///
+// split a ptrlist block
+// @head: the ptrlist block to be splitted
+//
+// A new block is inserted just after @head and the entries
+// at the half end of @head are moved to this new block.
+// The goal being to create space inside @head for a new entry.
 void split_ptr_list_head(struct ptr_list *head)
 {
 	int old = head->nr, nr = old / 2;
@@ -116,7 +239,15 @@
 }
 
 int rl_ptrlist_hack;
-void **__add_ptr_list(struct ptr_list **listp, void *ptr, unsigned long tag)
+///
+// add an entry to a ptrlist
+// @listp: a pointer to the list
+// @ptr: the entry to add to the list
+// @return: the address where the new entry is stored.
+//
+// :note: code must not use this function and should use
+//	:func:`add_ptr_list` instead.
+void **__add_ptr_list(struct ptr_list **listp, void *ptr)
 {
 	struct ptr_list *list = *listp;
 	struct ptr_list *last = NULL; /* gcc complains needlessly */
@@ -123,11 +254,6 @@
 	void **ret;
 	int nr;
 
-	/* The low two bits are reserved for tags */
-	assert((3 & (unsigned long)ptr) == 0);
-	assert((~3 & tag) == 0);
-	ptr = (void *)(tag | (unsigned long)ptr);
-
 	if (!list || (nr = (last = list->prev)->nr) >= LIST_NODE_NR) {
 		struct ptr_list *newlist;
 
@@ -155,6 +281,52 @@
 	return ret;
 }
 
+///
+// add a tagged entry to a ptrlist
+// @listp: a pointer to the list
+// @ptr: the entry to add to the list
+// @tag: the tag to add to @ptr
+// @return: the address where the new entry is stored.
+//
+// :note: code must not use this function and should use
+//	:func:`add_ptr_list_tag` instead.
+void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
+{
+	/* The low two bits are reserved for tags */
+	assert((3 & (unsigned long)ptr) == 0);
+	assert((~3 & tag) == 0);
+
+	ptr = (void *)(tag | (unsigned long)ptr);
+
+	return __add_ptr_list(listp, ptr);
+}
+
+///
+// test if some entry is already present in a ptrlist
+// @list: the head of the list
+// @entry: the entry to test
+// @return: ``true`` if the entry is already present, ``false`` otherwise.
+bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
+{
+	const struct ptr_list *list = head;
+
+	if (!head)
+		return false;
+	do {
+		int nr = list->nr;
+		int i;
+		for (i = 0; i < nr; i++)
+			if (list->list[i] == entry)
+				return true;
+	} while ((list = list->next) != head);
+	return false;
+}
+
+///
+// delete an entry from a ptrlist
+// @list: a pointer to the list
+// @entry: the item to be deleted
+// @count: the minimum number of times @entry should be deleted or 0.
 int delete_ptr_list_entry(struct ptr_list **list, void *entry, int count)
 {
 	void *ptr;
@@ -172,7 +344,14 @@
 	return count;
 }
 
-int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr, void *new_ptr, int count)
+///
+// replace an entry in a ptrlist
+// @list: a pointer to the list
+// @old_ptr: the entry to be replaced
+// @new_ptr: the new entry
+// @count: the minimum number of times @entry should be deleted or 0.
+int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr,
+	void *new_ptr, int count)
 {
 	void *ptr;
 
@@ -188,7 +367,12 @@
 	return count;
 }
 
-/* This removes the last entry, but doesn't pack the ptr list */
+///
+// remove the last entry of a ptrlist
+// @head: a pointer to the list
+// @return: the last elemant of the list or NULL if the list is empty.
+//
+// :note: this doesn't repack the list
 void * undo_ptr_list_last(struct ptr_list **head)
 {
 	struct ptr_list *last, *first = *head;
@@ -209,6 +393,10 @@
 	return NULL;
 }
 
+///
+// remove the last entry and repack the list
+// @head: a pointer to the list
+// @return: the last elemant of the list or NULL if the list is empty.
 void * delete_ptr_list_last(struct ptr_list **head)
 {
 	void *ptr = NULL;
@@ -229,6 +417,11 @@
 	return ptr;
 }
 
+///
+// concat two ptrlists
+// @a: the source list
+// @b: a pointer to the destination list.
+// The element of @a are added at the end of @b.
 void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
 {
 	void *entry;
@@ -237,6 +430,63 @@
 	} END_FOR_EACH_PTR(entry);
 }
 
+///
+// copy the elements of a list at the end of another list.
+// @listp: a pointer to the destination list.
+// @src: the head of the source list.
+void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
+{
+	struct ptr_list *head, *tail;
+	struct ptr_list *cur = src;
+	int idx;
+
+	if (!src)
+		return;
+	head = *listp;
+	if (!head) {
+		*listp = src;
+		return;
+	}
+
+	tail = head->prev;
+	idx = tail->nr;
+	do {
+		struct ptr_list *next;
+		int nr = cur->nr;
+		int i;
+		for (i = 0; i < nr;) {
+			void *ptr = cur->list[i++];
+			if (!ptr)
+				continue;
+			if (idx >= LIST_NODE_NR) {
+				struct ptr_list *prev = tail;
+				tail = __alloc_ptrlist(0);
+				prev->next = tail;
+				tail->prev = prev;
+				prev->nr = idx;
+				idx = 0;
+			}
+			tail->list[idx++] = ptr;
+		}
+
+		next = cur->next;
+		__free_ptrlist(cur);
+		cur = next;
+	} while (cur != src);
+
+	tail->nr = idx;
+	head->prev = tail;
+	tail->next = head;
+}
+
+///
+// free a ptrlist
+// @listp: a pointer to the list
+// Each blocks of the list are freed (but the entries
+// themselves are not freed).
+//
+// :note: code must not use this function and should use
+//	the macro :func:`free_ptr_list` instead.
 void __free_ptr_list(struct ptr_list **listp)
 {
 	struct ptr_list *tmp, *list = *listp;
--- old/usr/src/tools/smatch/src/ptrlist.h	Mon Nov 18 13:19:04 2019
+++ new/usr/src/tools/smatch/src/ptrlist.h	Mon Nov 18 13:19:04 2019
@@ -2,6 +2,7 @@
 #define PTR_LIST_H
 
 #include <stdlib.h>
+#include <stdbool.h>
 
 /*
  * Generic pointer list manipulation code. 
@@ -10,41 +11,41 @@
  */
 
 /* Silly type-safety check ;) */
-#define DECLARE_PTR_LIST(listname,type)	struct listname { type *list[1]; }
 #define CHECK_TYPE(head,ptr)		(void)(&(ptr) == &(head)->list[0])
 #define TYPEOF(head)			__typeof__(&(head)->list[0])
 #define VRFY_PTR_LIST(head)		(void)(sizeof((head)->list[0]))
 
-/*
- * The "unnecessary" statement expression is there to shut up a totally 
- * bogus gcc warning about unused expressions, brought on by the fact
- * that we cast the result to the proper type.
- */
-#define MKTYPE(head,expr)		({ (TYPEOF(head))(expr); })
+#define LIST_NODE_NR (13)
 
-#define LIST_NODE_NR (29)
+#define DECLARE_PTR_LIST(listname, type)	\
+	struct listname {			\
+		int nr:8;			\
+		int rm:8;			\
+		struct listname *prev;		\
+		struct listname *next;		\
+		type *list[LIST_NODE_NR];	\
+	}
 
-struct ptr_list {
-	int nr:8;
-	int rm:8;
-	struct ptr_list *prev;
-	struct ptr_list *next;
-	void *list[LIST_NODE_NR];
-};
+DECLARE_PTR_LIST(ptr_list, void);
 
-#define ptr_list_empty(x) ((x) == NULL)
 
 void * undo_ptr_list_last(struct ptr_list **head);
 void * delete_ptr_list_last(struct ptr_list **head);
 int delete_ptr_list_entry(struct ptr_list **, void *, int);
 int replace_ptr_list_entry(struct ptr_list **, void *old, void *new, int);
+bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry);
 extern void sort_list(struct ptr_list **, int (*)(const void *, const void *));
 
-extern void **__add_ptr_list(struct ptr_list **, void *, unsigned long);
 extern void concat_ptr_list(struct ptr_list *a, struct ptr_list **b);
-extern void __free_ptr_list(struct ptr_list **);
+extern void copy_ptr_list(struct ptr_list **h, struct ptr_list *t);
 extern int ptr_list_size(struct ptr_list *);
+extern bool ptr_list_empty(const struct ptr_list *head);
+extern bool ptr_list_multiple(const struct ptr_list *head);
 extern int linearize_ptr_list(struct ptr_list *, void **, int);
+extern void *first_ptr_list(struct ptr_list *);
+extern void *last_ptr_list(struct ptr_list *);
+extern void *ptr_list_nth_entry(struct ptr_list *, unsigned int idx);
+extern void pack_ptr_list(struct ptr_list **);
 
 /*
  * Hey, who said that you can't do overloading in C?
@@ -52,257 +53,231 @@
  * You just have to be creative, and use some gcc
  * extensions..
  */
-#define add_ptr_list_tag(list,entry,tag) \
-	MKTYPE(*(list), (CHECK_TYPE(*(list),(entry)),__add_ptr_list((struct ptr_list **)(list), (entry), (tag))))
-#define add_ptr_list_notag(list,entry)										\
-	MKTYPE(*(list), (CHECK_TYPE(*(list),(entry)),__add_ptr_list((struct ptr_list **)(list),			\
-								    (void *)((unsigned long)(entry) & ~3UL), 	\
-								    (unsigned long)(entry) & 3)))
-#define add_ptr_list(list,entry) \
-	add_ptr_list_tag(list,entry,0)
-#define free_ptr_list(list) \
-	do { VRFY_PTR_LIST(*(list)); __free_ptr_list((struct ptr_list **)(list)); } while (0)
+extern void **__add_ptr_list(struct ptr_list **, void *);
+extern void **__add_ptr_list_tag(struct ptr_list **, void *, unsigned long);
 
-#define PTR_ENTRY_NOTAG(h,i)	((h)->list[i])
-#define PTR_ENTRY(h,i)	(void *)(~3UL & (unsigned long)PTR_ENTRY_NOTAG(h,i))
+#define add_ptr_list(list, ptr) ({					\
+		struct ptr_list** head = (struct ptr_list**)(list);	\
+		CHECK_TYPE(*(list),ptr);				\
+		(__typeof__(&(ptr))) __add_ptr_list(head, ptr);		\
+	})
+#define add_ptr_list_tag(list, ptr, tag) ({				\
+		struct ptr_list** head = (struct ptr_list**)(list);	\
+		CHECK_TYPE(*(list),ptr);				\
+		(__typeof__(&(ptr))) __add_ptr_list_tag(head, ptr, tag);\
+	})
 
-static inline void *first_ptr_list(struct ptr_list *list)
-{
-	struct ptr_list *head = list;
+extern void __free_ptr_list(struct ptr_list **);
+#define free_ptr_list(list)	do {					\
+		VRFY_PTR_LIST(*(list));					\
+		__free_ptr_list((struct ptr_list **)(list));		\
+	} while (0)
 
-	if (!list)
-		return NULL;
 
-	while (list->nr == 0) {
-		list = list->next;
-		if (list == head)
-			return NULL;
-	}
-	return PTR_ENTRY(list, 0);
-}
+////////////////////////////////////////////////////////////////////////
+// API
+#define PREPARE_PTR_LIST(head, ptr) \
+	DO_PREPARE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
-static inline void *last_ptr_list(struct ptr_list *list)
-{
-	struct ptr_list *head = list;
+#define NEXT_PTR_LIST(ptr) \
+	DO_NEXT(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
-	if (!list)
-		return NULL;
-	list = list->prev;
-	while (list->nr == 0) {
-		if (list == head)
-			return NULL;
-		list = list->prev;
-	}
-	return PTR_ENTRY(list, list->nr-1);
-}
+#define RESET_PTR_LIST(ptr) \
+	DO_RESET(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
-#define PTR_DEREF(__head, idx, PTR_ENTRY) ({						\
-	struct ptr_list *__list = __head;						\
-	while (__list && __list->nr == 0) {						\
-		__list = __list->next;							\
-		if (__list == __head)							\
-			__list = NULL;							\
-	}										\
-	__list ? PTR_ENTRY(__list, idx) : NULL;						\
-})
+#define FINISH_PTR_LIST(ptr) \
+	DO_FINISH(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-#define DO_PREPARE(head, ptr, __head, __list, __nr, PTR_ENTRY)				\
-	do {										\
-		struct ptr_list *__head = (struct ptr_list *) (head);			\
-		struct ptr_list *__list = __head;					\
-		int __nr = 0;								\
-		CHECK_TYPE(head,ptr);							\
-		ptr = PTR_DEREF(__head, 0, PTR_ENTRY);					\
+#define RECURSE_PTR_REVERSE(ptr, new)					\
+	DO_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr,		\
+		   new, __head##new, __list##new, __nr##new, PTR_ENTRY_UNTAG)
 
-#define DO_NEXT(ptr, __head, __list, __nr, PTR_ENTRY)					\
-		if (ptr) {								\
-			if (++__nr < __list->nr) {					\
-				ptr = PTR_ENTRY(__list,__nr);				\
-			} else {							\
-				__list = __list->next;					\
-				ptr = NULL;						\
-				while (__list->nr == 0 && __list != __head)		\
-					__list = __list->next;				\
-				if (__list != __head) {					\
-					__nr = 0;					\
-					ptr = PTR_ENTRY(__list,0);			\
-				}							\
-			}								\
-		}
 
-#define DO_RESET(ptr, __head, __list, __nr, PTR_ENTRY)					\
-	do {										\
-		__nr = 0;								\
-		__list = __head;							\
-		if (__head) ptr = PTR_DEREF(__head, 0, PTR_ENTRY);			\
-	} while (0)
+#define FOR_EACH_PTR(head, ptr) \
+	DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
 
-#define DO_FINISH(ptr, __head, __list, __nr)						\
-		(void)(__nr); /* Sanity-check nesting */				\
-	} while (0)
+#define FOR_EACH_PTR_TAG(head, ptr) \
+	DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
-#define PREPARE_PTR_LIST(head, ptr) \
-	DO_PREPARE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+#define END_FOR_EACH_PTR(ptr) \
+	DO_END_FOR_EACH(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-#define NEXT_PTR_LIST(ptr) \
-	DO_NEXT(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+#define FOR_EACH_PTR_REVERSE(head, ptr) \
+	DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
 
-#define RESET_PTR_LIST(ptr) \
-	DO_RESET(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+#define FOR_EACH_PTR_REVERSE_TAG(head, ptr) \
+	DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
-#define FINISH_PTR_LIST(ptr) \
-	DO_FINISH(ptr, __head##ptr, __list##ptr, __nr##ptr)
+#define END_FOR_EACH_PTR_REVERSE(ptr) \
+	DO_END_FOR_EACH_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-#define DO_FOR_EACH(head, ptr, __head, __list, __nr, PTR_ENTRY) do {			\
-	struct ptr_list *__head = (struct ptr_list *) (head);				\
-	struct ptr_list *__list = __head;						\
-	CHECK_TYPE(head,ptr);								\
-	if (__head) {									\
-		do { int __nr;								\
-			for (__nr = 0; __nr < __list->nr; __nr++) {			\
-				do {							\
-					ptr = PTR_ENTRY(__list,__nr);			\
-					if (__list->rm && !ptr)				\
-						continue;				\
-					do {
+#define THIS_ADDRESS(ptr) \
+	DO_THIS_ADDRESS(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-#define DO_END_FOR_EACH(ptr, __head, __list, __nr)					\
-					} while (0);					\
-				} while (0);						\
-			}								\
-		} while ((__list = __list->next) != __head);				\
-	}										\
-} while (0)
+#define INSERT_CURRENT(new, ptr) \
+	DO_INSERT_CURRENT(new, __head##ptr, __list##ptr, __nr##ptr)
 
-#define DO_FOR_EACH_REVERSE(head, ptr, __head, __list, __nr, PTR_ENTRY) do {		\
-	struct ptr_list *__head = (struct ptr_list *) (head);				\
-	struct ptr_list *__list = __head;						\
-	CHECK_TYPE(head,ptr);								\
-	if (__head) {									\
-		do { int __nr;								\
-			__list = __list->prev;						\
-			__nr = __list->nr;						\
-			while (--__nr >= 0) {						\
-				do {							\
-					ptr = PTR_ENTRY(__list,__nr);			\
-					if (__list->rm && !ptr)				\
-						continue;				\
-					do {
+#define DELETE_CURRENT_PTR(ptr) \
+	DO_DELETE_CURRENT(__head##ptr, __list##ptr, __nr##ptr)
 
+#define REPLACE_CURRENT_PTR(ptr, new_ptr)				\
+	do { *THIS_ADDRESS(ptr) = (new_ptr); } while (0)
 
-#define DO_END_FOR_EACH_REVERSE(ptr, __head, __list, __nr)				\
-					} while (0);					\
-				} while (0);						\
-			}								\
-		} while (__list != __head);						\
-	}										\
-} while (0)
+// This replace the current element by a null-pointer.
+// It's used when an element of the list must be removed
+// but the address of the other elements must not be changed.
+#define MARK_CURRENT_DELETED(ptr) \
+	DO_MARK_CURRENT_DELETED(ptr, __list##ptr)
 
-#define DO_REVERSE(ptr, __head, __list, __nr, new, __newhead,				\
-		   __newlist, __newnr, PTR_ENTRY) do { 					\
-	struct ptr_list *__newhead = __head;						\
-	struct ptr_list *__newlist = __list;						\
-	int __newnr = __nr;								\
-	new = ptr;									\
-	goto __inside##new;								\
-	if (1) {									\
-		do {									\
-			__newlist = __newlist->prev;					\
-			__newnr = __newlist->nr;					\
-	__inside##new:									\
-			while (--__newnr >= 0) {					\
-				do {							\
-					new = PTR_ENTRY(__newlist,__newnr);		\
-					do {
+#define PACK_PTR_LIST(x) \
+	pack_ptr_list((struct ptr_list **)(x))
 
-#define RECURSE_PTR_REVERSE(ptr, new)							\
-	DO_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr,				\
-		   new, __head##new, __list##new, __nr##new, PTR_ENTRY)
+#define CURRENT_TAG(ptr)	(3 & (unsigned long)*THIS_ADDRESS(ptr))
+#define TAG_CURRENT(ptr,val)	update_tag(THIS_ADDRESS(ptr),val)
 
-#define DO_THIS_ADDRESS(ptr, __head, __list, __nr)					\
-	((__typeof__(&(ptr))) (__list->list + __nr))
+// backward compatibility for smatch
+#define FOR_EACH_PTR_NOTAG(list, ptr)	FOR_EACH_PTR(list, ptr)
+#define END_FOR_EACH_PTR_NOTAG(ptr)	END_FOR_EACH_PTR(ptr)
 
-#define FOR_EACH_PTR(head, ptr) \
-	DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+////////////////////////////////////////////////////////////////////////
+// Implementation
+#define PTR_UNTAG(p)		((void*)(~3UL & (unsigned long)(p)))
+#define PTR_ENTRY_NOTAG(h,i)	((h)->list[i])
+#define PTR_ENTRY_UNTAG(h,i)	PTR_UNTAG((h)->list[i])
 
-#define END_FOR_EACH_PTR(ptr) \
-	DO_END_FOR_EACH(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-#define FOR_EACH_PTR_NOTAG(head, ptr) \
-	DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
+#define PTR_NEXT(ptr, __head, __list, __nr, PTR_ENTRY)			\
+	do {								\
+		if (__nr < __list->nr) {				\
+			ptr = PTR_ENTRY(__list,__nr);			\
+			__nr++;						\
+			break;						\
+		}							\
+		ptr = NULL;						\
+		__nr = 0;						\
+	} while ((__list = __list->next) != __head)			\
 
-#define END_FOR_EACH_PTR_NOTAG(ptr) END_FOR_EACH_PTR(ptr)
+#define DO_PREPARE(head, ptr, __head, __list, __nr, PTR_ENTRY)		\
+	do {								\
+		__typeof__(head) __head = (head);			\
+		__typeof__(head) __list = __head;			\
+		int __nr = 0;						\
+		ptr = NULL;						\
+		if (__head) {						\
+			PTR_NEXT(ptr, __head, __list, __nr, PTR_ENTRY);	\
+		}							\
 
-#define FOR_EACH_PTR_REVERSE(head, ptr) \
-	DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+#define DO_NEXT(ptr, __head, __list, __nr, PTR_ENTRY)			\
+		if (ptr) {						\
+			PTR_NEXT(ptr, __head, __list, __nr, PTR_ENTRY);	\
+		}
 
-#define END_FOR_EACH_PTR_REVERSE(ptr) \
-	DO_END_FOR_EACH_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr)
+#define DO_RESET(ptr, __head, __list, __nr, PTR_ENTRY)			\
+	do {								\
+		__nr = 0;						\
+		__list = __head;					\
+		if (__head)						\
+			PTR_NEXT(ptr, __head, __list, __nr, PTR_ENTRY);	\
+	} while (0)
 
-#define FOR_EACH_PTR_REVERSE_NOTAG(head, ptr) \
-	DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
+#define DO_FINISH(ptr, __head, __list, __nr)				\
+		VRFY_PTR_LIST(__head); /* Sanity-check nesting */	\
+	} while (0)
 
-#define END_FOR_EACH_PTR_REVERSE_NOTAG(ptr) END_FOR_EACH_PTR_REVERSE(ptr)
+#define DO_FOR_EACH(head, ptr, __head, __list, __nr, PTR_ENTRY) do {	\
+	__typeof__(head) __head = (head);				\
+	__typeof__(head) __list = __head;				\
+	int __nr;							\
+	if (!__head)							\
+		break;							\
+	do {								\
+		for (__nr = 0; __nr < __list->nr; __nr++) {		\
+			ptr = PTR_ENTRY(__list,__nr);			\
+			if (__list->rm && !ptr)				\
+				continue;				\
 
-#define THIS_ADDRESS(ptr) \
-	DO_THIS_ADDRESS(ptr, __head##ptr, __list##ptr, __nr##ptr)
+#define DO_END_FOR_EACH(ptr, __head, __list, __nr)			\
+		}							\
+	} while ((__list = __list->next) != __head);			\
+} while (0)
 
-extern void split_ptr_list_head(struct ptr_list *);
+#define DO_FOR_EACH_REVERSE(head, ptr, __head, __list, __nr, PTR_ENTRY) do { \
+	__typeof__(head) __head = (head);				\
+	__typeof__(head) __list = __head;				\
+	int __nr;							\
+	if (!head)							\
+		break;							\
+	do {								\
+		__list = __list->prev;					\
+		__nr = __list->nr;					\
+		while (--__nr >= 0) {					\
+			ptr = PTR_ENTRY(__list,__nr);			\
+			if (__list->rm && !ptr)				\
+				continue;				\
 
-#define DO_SPLIT(ptr, __head, __list, __nr) do {					\
-	split_ptr_list_head(__list);							\
-	if (__nr >= __list->nr) {							\
-		__nr -= __list->nr;							\
-		__list = __list->next;							\
-	};										\
-} while (0)
 
-#define DO_INSERT_CURRENT(new, ptr, __head, __list, __nr) do {				\
-	void **__this, **__last;							\
-	if (__list->nr == LIST_NODE_NR)							\
-		DO_SPLIT(ptr, __head, __list, __nr);					\
-	__this = __list->list + __nr;							\
-	__last = __list->list + __list->nr - 1;						\
-	while (__last >= __this) {							\
-		__last[1] = __last[0];							\
-		__last--;								\
-	}										\
-	*__this = (new);								\
-	__list->nr++;									\
+#define DO_END_FOR_EACH_REVERSE(ptr, __head, __list, __nr)		\
+		}							\
+	} while (__list != __head);					\
 } while (0)
 
-#define INSERT_CURRENT(new, ptr) \
-	DO_INSERT_CURRENT(new, ptr, __head##ptr, __list##ptr, __nr##ptr)
+#define DO_REVERSE(ptr, __head, __list, __nr, new, __newhead,		\
+		   __newlist, __newnr, PTR_ENTRY) do {			\
+	__typeof__(__head) __newhead = __head;				\
+	__typeof__(__head) __newlist = __list;				\
+	int __newnr = __nr;						\
+	new = ptr;							\
+	goto __inside##new;						\
+	do {								\
+		__newlist = __newlist->prev;				\
+		__newnr = __newlist->nr;				\
+	__inside##new:							\
+		while (--__newnr >= 0) {				\
+			new = PTR_ENTRY(__newlist,__newnr);		\
 
-#define DO_DELETE_CURRENT(ptr, __head, __list, __nr) do {				\
-	void **__this = __list->list + __nr;						\
-	void **__last = __list->list + __list->nr - 1;					\
-	while (__this < __last) {							\
-		__this[0] = __this[1];							\
-		__this++;								\
-	}										\
-	*__this = (void *)0xf0f0f0f0;							\
-	__list->nr--; __nr--;								\
-} while (0)
+#define DO_THIS_ADDRESS(ptr, __head, __list, __nr)			\
+	(&__list->list[__nr])
 
-#define DELETE_CURRENT_PTR(ptr) \
-	DO_DELETE_CURRENT(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-#define REPLACE_CURRENT_PTR(ptr, new_ptr)						\
-	do { *THIS_ADDRESS(ptr) = (new_ptr); } while (0)
+extern void split_ptr_list_head(struct ptr_list *);
 
-#define DO_MARK_CURRENT_DELETED(ptr, __list) do {	\
-		REPLACE_CURRENT_PTR(ptr, NULL);		\
-		__list->rm++;				\
-	} while (0)
+#define DO_INSERT_CURRENT(new, __head, __list, __nr) do {		\
+	TYPEOF(__head) __this, __last;					\
+	if (__list->nr == LIST_NODE_NR) {				\
+		split_ptr_list_head((struct ptr_list*)__list);		\
+		if (__nr >= __list->nr) {				\
+			__nr -= __list->nr;				\
+			__list = __list->next;				\
+		}							\
+	}								\
+	__this = __list->list + __nr;					\
+	__last = __list->list + __list->nr - 1;				\
+	while (__last >= __this) {					\
+		__last[1] = __last[0];					\
+		__last--;						\
+	}								\
+	*__this = (new);						\
+	__list->nr++;							\
+} while (0)
 
-#define MARK_CURRENT_DELETED(ptr) \
-	DO_MARK_CURRENT_DELETED(ptr, __list##ptr)
+#define DO_DELETE_CURRENT(__head, __list, __nr) do {			\
+	TYPEOF(__head) __this = __list->list + __nr;			\
+	TYPEOF(__head) __last = __list->list + __list->nr - 1;		\
+	while (__this < __last) {					\
+		__this[0] = __this[1];					\
+		__this++;						\
+	}								\
+	*__this = (void *)0xf0f0f0f0;					\
+	__list->nr--; __nr--;						\
+} while (0)
 
-extern void pack_ptr_list(struct ptr_list **);
 
-#define PACK_PTR_LIST(x) pack_ptr_list((struct ptr_list **)(x))
+#define DO_MARK_CURRENT_DELETED(ptr, __list) do {			\
+		REPLACE_CURRENT_PTR(ptr, NULL);				\
+		__list->rm++;						\
+	} while (0)
 
+
 static inline void update_tag(void *p, unsigned long tag)
 {
 	unsigned long *ptr = p;
@@ -314,7 +289,4 @@
 	return (void *)(tag | (unsigned long)ptr);
 }
 
-#define CURRENT_TAG(ptr) (3 & (unsigned long)*THIS_ADDRESS(ptr))
-#define TAG_CURRENT(ptr,val)	update_tag(THIS_ADDRESS(ptr),val)
-
 #endif /* PTR_LIST_H */
--- /dev/null	Mon Nov 18 13:19:05 2019
+++ new/usr/src/tools/smatch/src/ptrmap.c	Mon Nov 18 13:19:05 2019
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Stupid implementation of pointer -> pointer map.
+ *
+ * Copyright (c) 2017 Luc Van Oostenryck.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ptrmap.h"
+#include "allocate.h"
+#include <stddef.h>
+
+#define	MAP_NR	7
+
+struct ptrpair {
+	void *key;
+	void *val;
+};
+struct ptrmap {
+	struct ptrmap *next;
+	int nr;
+	struct ptrpair pairs[MAP_NR];
+};
+
+DECLARE_ALLOCATOR(ptrmap);
+ALLOCATOR(ptrmap, "ptrmap");
+
+void __ptrmap_add(struct ptrmap **mapp, void *key, void *val)
+{
+	struct ptrmap *head = *mapp;
+	struct ptrmap *newmap;
+	struct ptrmap *map;
+	struct ptrpair *pair;
+	int nr;
+
+	if ((map = head)) {
+		struct ptrmap *next = map->next;
+		if (next)		// head is full
+			map = next;
+		if ((nr = map->nr) < MAP_NR)
+			goto oldmap;
+	}
+
+	// need a new block
+	newmap = __alloc_ptrmap(0);
+	if (!head) {
+		*mapp = newmap;
+	} else {
+		newmap->next = head->next;
+		head->next = newmap;
+	}
+	map = newmap;
+	nr = 0;
+
+oldmap:
+	pair = &map->pairs[nr];
+	pair->key = key;
+	pair->val = val;
+	map->nr = ++nr;
+}
+
+void *__ptrmap_lookup(struct ptrmap *map, void *key)
+{
+	for (; map; map = map->next) {
+		int i, n = map->nr;
+		for (i = 0; i < n; i++) {
+			struct ptrpair *pair = &map->pairs[i];
+			if (pair->key == key)
+				return pair->val;
+		}
+	}
+	return NULL;
+}
+
+void __ptrmap_update(struct ptrmap **mapp, void *key, void *val)
+{
+	struct ptrmap *map = *mapp;
+
+	for (; map; map = map->next) {
+		int i, n = map->nr;
+		for (i = 0; i < n; i++) {
+			struct ptrpair *pair = &map->pairs[i];
+			if (pair->key == key) {
+				if (pair->val != val)
+					pair->val = val;
+				return;
+			}
+		}
+	}
+
+	__ptrmap_add(mapp, key, val);
+}
--- /dev/null	Mon Nov 18 13:19:05 2019
+++ new/usr/src/tools/smatch/src/ptrmap.h	Mon Nov 18 13:19:05 2019
@@ -0,0 +1,28 @@
+#ifndef PTRMAP_H
+#define PTRMAP_H
+
+struct ptrmap;
+
+#define DECLARE_PTRMAP(name, ktype, vtype)				\
+	struct name ## _pair { ktype key; vtype val; };			\
+	struct name { struct name ## _pair block[1]; };			\
+	static inline							\
+	void name##_add(struct name **map, ktype k, vtype v) {		\
+		__ptrmap_add((struct ptrmap**)map, k, v);		\
+	}								\
+	static inline							\
+	void name##_update(struct name **map, ktype k, vtype v) {	\
+		__ptrmap_update((struct ptrmap**)map, k, v);		\
+	}								\
+	static inline							\
+	vtype name##_lookup(struct name *map, ktype k) {		\
+		vtype val = __ptrmap_lookup((struct ptrmap*)map, k);	\
+		return val;						\
+	}								\
+
+/* ptrmap.c */
+void __ptrmap_add(struct ptrmap **mapp, void *key, void *val);
+void __ptrmap_update(struct ptrmap **mapp, void *key, void *val);
+void *__ptrmap_lookup(struct ptrmap *map, void *key);
+
+#endif
--- old/usr/src/tools/smatch/src/scope.h	Mon Nov 18 13:19:05 2019
+++ new/usr/src/tools/smatch/src/scope.h	Mon Nov 18 13:19:05 2019
@@ -29,7 +29,7 @@
 struct position;
 
 struct scope {
-	struct token *token;		/* Scope start information */
+	struct token *token;
 	struct symbol_list *symbols;	/* List of symbols in this scope */
 	struct scope *next;
 };
--- old/usr/src/tools/smatch/src/show-parse.c	Mon Nov 18 13:19:05 2019
+++ new/usr/src/tools/smatch/src/show-parse.c	Mon Nov 18 13:19:05 2019
@@ -72,10 +72,11 @@
 
 	if (!sym)
 		return;
-	fprintf(stderr, "%.*s%s%3d:%lu %s %s (as: %d) %p (%s:%d:%d) %s\n",
+	fprintf(stderr, "%.*s%s%3d:%lu %s %s (as: %s) %p (%s:%d:%d) %s\n",
 		indent, indent_string, typestr[sym->type],
 		sym->bit_size, sym->ctype.alignment,
-		modifier_string(sym->ctype.modifiers), show_ident(sym->ident), sym->ctype.as,
+		modifier_string(sym->ctype.modifiers), show_ident(sym->ident),
+		show_as(sym->ctype.as),
 		sym, stream_name(sym->pos.stream), sym->pos.line, sym->pos.pos,
 		builtin_typename(sym) ?: "");
 	i = 0;
@@ -125,6 +126,8 @@
 		{MOD_EXTERN,		"extern"},
 		{MOD_CONST,		"const"},
 		{MOD_VOLATILE,		"volatile"},
+		{MOD_RESTRICT,		"restrict"},
+		{MOD_ATOMIC,		"[atomic]"},
 		{MOD_SIGNED,		"[signed]"},
 		{MOD_UNSIGNED,		"[unsigned]"},
 		{MOD_CHAR,		"[char]"},
@@ -132,13 +135,11 @@
 		{MOD_LONG,		"[long]"},
 		{MOD_LONGLONG,		"[long long]"},
 		{MOD_LONGLONGLONG,	"[long long long]"},
-		{MOD_TYPEDEF,		"[typedef]"},
 		{MOD_TLS,		"[tls]"},
 		{MOD_INLINE,		"inline"},
 		{MOD_ADDRESSABLE,	"[addressable]"},
 		{MOD_NOCAST,		"[nocast]"},
 		{MOD_NODEREF,		"[noderef]"},
-		{MOD_ACCESSED,		"[accessed]"},
 		{MOD_TOPLEVEL,		"[toplevel]"},
 		{MOD_ASSIGNED,		"[assigned]"},
 		{MOD_TYPE,		"[type]"},
@@ -182,6 +183,13 @@
 	} END_FOR_EACH_PTR(sym);
 }
 
+const char *show_as(struct ident *as)
+{
+	if (!as)
+		return "";
+	return show_ident(as);
+}
+
 struct type_name {
 	char *start;
 	char *end;
@@ -218,38 +226,38 @@
 static struct ctype_name {
 	struct symbol *sym;
 	const char *name;
+	const char *suffix;
 } typenames[] = {
-	{ & char_ctype,  "char" },
-	{ &schar_ctype,  "signed char" },
-	{ &uchar_ctype,  "unsigned char" },
-	{ & short_ctype, "short" },
-	{ &sshort_ctype, "signed short" },
-	{ &ushort_ctype, "unsigned short" },
-	{ & int_ctype,   "int" },
-	{ &sint_ctype,   "signed int" },
-	{ &uint_ctype,   "unsigned int" },
-	{ &slong_ctype,  "signed long" },
-	{ & long_ctype,  "long" },
-	{ &ulong_ctype,  "unsigned long" },
-	{ & llong_ctype, "long long" },
-	{ &sllong_ctype, "signed long long" },
-	{ &ullong_ctype, "unsigned long long" },
-	{ & lllong_ctype, "long long long" },
-	{ &slllong_ctype, "signed long long long" },
-	{ &ulllong_ctype, "unsigned long long long" },
+	{ & char_ctype,  "char", "" },
+	{ &schar_ctype,  "signed char", "" },
+	{ &uchar_ctype,  "unsigned char", "" },
+	{ & short_ctype, "short", "" },
+	{ &sshort_ctype, "signed short", "" },
+	{ &ushort_ctype, "unsigned short", "" },
+	{ & int_ctype,   "int", "" },
+	{ &sint_ctype,   "signed int", "" },
+	{ &uint_ctype,   "unsigned int", "U" },
+	{ & long_ctype,  "long", "L" },
+	{ &slong_ctype,  "signed long", "L" },
+	{ &ulong_ctype,  "unsigned long", "UL" },
+	{ & llong_ctype, "long long", "LL" },
+	{ &sllong_ctype, "signed long long", "LL" },
+	{ &ullong_ctype, "unsigned long long", "ULL" },
+	{ & lllong_ctype, "long long long", "LLL" },
+	{ &slllong_ctype, "signed long long long", "LLL" },
+	{ &ulllong_ctype, "unsigned long long long", "ULLL" },
 
-	{ &void_ctype,   "void" },
-	{ &bool_ctype,   "bool" },
-	{ &string_ctype, "string" },
+	{ &void_ctype,   "void", "" },
+	{ &bool_ctype,   "bool", "" },
 
-	{ &float_ctype,  "float" },
-	{ &double_ctype, "double" },
-	{ &ldouble_ctype,"long double" },
-	{ &incomplete_ctype, "incomplete type" },
-	{ &int_type, "abstract int" },
-	{ &fp_type, "abstract fp" },
-	{ &label_ctype, "label type" },
-	{ &bad_ctype, "bad type" },
+	{ &float_ctype,  "float", "F" },
+	{ &double_ctype, "double", "" },
+	{ &ldouble_ctype,"long double", "L" },
+	{ &incomplete_ctype, "incomplete type", "" },
+	{ &int_type, "abstract int", "" },
+	{ &fp_type, "abstract fp", "" },
+	{ &label_ctype, "label type", "" },
+	{ &bad_ctype, "bad type", "" },
 };
 
 const char *builtin_typename(struct symbol *sym)
@@ -262,6 +270,16 @@
 	return NULL;
 }
 
+const char *builtin_type_suffix(struct symbol *sym)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(typenames); i++)
+		if (typenames[i].sym == sym)
+			return typenames[i].suffix;
+	return NULL;
+}
+
 const char *builtin_ctypename(struct ctype *ctype)
 {
 	int i;
@@ -276,7 +294,7 @@
 {
 	const char *typename;
 	unsigned long mod = 0;
-	int as = 0;
+	struct ident *as = NULL;
 	int was_ptr = 0;
 	int restr = 0;
 	int fouled = 0;
@@ -288,14 +306,16 @@
 		size_t len;
 
 		if (as)
-			prepend(name, "<asn:%d>", as);
+			prepend(name, "%s ", show_as(as));
 
+		if (sym->type == SYM_BASETYPE || sym->type == SYM_ENUM)
+			mod &= ~MOD_SPECIFIER;
 		s = modifier_string(mod);
 		len = strlen(s);
 		name->start -= len;    
 		memcpy(name->start, s, len);  
 		mod = 0;
-		as = 0;
+		as = NULL;
 	}
 
 	if (!sym)
@@ -345,14 +365,15 @@
 		break;
 
 	case SYM_NODE:
-		append(name, "%s", show_ident(sym->ident));
+		if (sym->ident)
+			append(name, "%s", show_ident(sym->ident));
 		mod |= sym->ctype.modifiers;
-		as |= sym->ctype.as;
+		combine_address_space(sym->pos, &as, sym->ctype.as);
 		break;
 
 	case SYM_BITFIELD:
 		mod |= sym->ctype.modifiers;
-		as |= sym->ctype.as;
+		combine_address_space(sym->pos, &as, sym->ctype.as);
 		append(name, ":%d", sym->bit_size);
 		break;
 
@@ -362,7 +383,7 @@
 
 	case SYM_ARRAY:
 		mod |= sym->ctype.modifiers;
-		as |= sym->ctype.as;
+		combine_address_space(sym->pos, &as, sym->ctype.as);
 		if (was_ptr) {
 			prepend(name, "( ");
 			append(name, " )");
@@ -400,6 +421,10 @@
 		prepend(name, "restricted ");
 	if (fouled)
 		prepend(name, "fouled ");
+
+	// strip trailing space
+	if (name->end > name->start && name->end[-1] == ' ')
+		name->end--;
 }
 
 void show_type(struct symbol *sym)
@@ -927,7 +952,7 @@
 		return new;
 	}
 	if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
-		printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, sym->value);
+		printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, 0LL);
 		return new;
 	}
 	printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new, show_ident(sym->ident), sym);
@@ -949,15 +974,6 @@
 	return 0;
 }
 
-static int type_is_signed(struct symbol *sym)
-{
-	if (sym->type == SYM_NODE)
-		sym = sym->ctype.base_type;
-	if (sym->type == SYM_PTR)
-		return 0;
-	return !(sym->ctype.modifiers & MOD_UNSIGNED);
-}
-
 static int show_cast_expr(struct expression *expr)
 {
 	struct symbol *old_type, *new_type;
@@ -973,7 +989,7 @@
 	if (oldbits >= newbits)
 		return op;
 	new = new_pseudo();
-	is_signed = type_is_signed(old_type);
+	is_signed = is_signed_type(old_type);
 	if (is_signed) {
 		printf("\tsext%d.%d\tv%d,v%d\n", oldbits, newbits, new, op);
 	} else {
@@ -996,7 +1012,7 @@
 	int new = new_pseudo();
 	long double value = expr->fvalue;
 
-	printf("\tmovf.%d\t\tv%d,$%Lf\n", expr->ctype->bit_size, new, value);
+	printf("\tmovf.%d\t\tv%d,$%Le\n", expr->ctype->bit_size, new, value);
 	return new;
 }
 
@@ -1018,11 +1034,11 @@
 static int show_conditional_expr(struct expression *expr)
 {
 	int cond = show_expression(expr->conditional);
-	int true = show_expression(expr->cond_true);
-	int false = show_expression(expr->cond_false);
+	int valt = show_expression(expr->cond_true);
+	int valf = show_expression(expr->cond_false);
 	int new = new_pseudo();
 
-	printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n", cond, expr->ctype->bit_size, new, true, false);
+	printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n", cond, expr->ctype->bit_size, new, valt, valf);
 	return new;
 }
 
@@ -1169,6 +1185,9 @@
 	case EXPR_TYPE:
 		warning(expr->pos, "unable to show type expression");
 		return 0;
+	case EXPR_ASM_OPERAND:
+		warning(expr->pos, "unable to show asm operand expression");
+		return 0;
 	}
 	return 0;
 }
--- old/usr/src/tools/smatch/src/simplify.c	Mon Nov 18 13:19:06 2019
+++ new/usr/src/tools/smatch/src/simplify.c	Mon Nov 18 13:19:06 2019
@@ -4,6 +4,41 @@
  * Copyright (C) 2004 Linus Torvalds
  */
 
+///
+// Instruction simplification
+// --------------------------
+//
+// Notation
+// ^^^^^^^^
+// The following conventions are used to describe the simplications:
+// * Uppercase letters are reserved for constants:
+//   * `M` for a constant mask,
+//   * `S` for a constant shift,
+//   * `N` for a constant number of bits (usually other than a shift),
+//   * `C` or 'K' for others constants.
+// * Lowercase letters `a`, `b`, `x`, `y`, ... are used for non-constants
+//   or when it doesn't matter if the pseudo is a constant or not.
+// * Primes are used if needed to distinguish symbols (`M`, `M'`, ...).
+// * Expressions or sub-expressions involving only constants are
+//   understood to be evaluated.
+// * `$mask(N)` is used for `((1 << N) -1)`
+// * `$trunc(x, N)` is used for `(x & $mask(N))`
+// * Expressions like `(-1 << S)`, `(-1 >> S)` and others formulae are
+//   understood to be truncated to the size of the current instruction
+//   (needed, since in general this size is not the same as the one used
+//   by sparse for the evaluation of arithmetic operations).
+// * `TRUNC(x, N)` is used for a truncation *to* a size of `N` bits
+// * `ZEXT(x, N)` is used for a zero-extension *from* a size of `N` bits
+// * `OP(x, C)` is used to represent some generic operation using a constant,
+//   including when the constant is implicit (e.g. `TRUNC(x, N)`).
+// * `MASK(x, M)` is used to respresent a 'masking' instruction:
+//   - `AND(x, M)`
+//   - `LSR(x, S)`, with `M` = (-1 << S)
+//   - `SHL(x, S)`, with `M` = (-1 >> S)
+//   - `TRUNC(x, N)`, with `M` = $mask(N)
+//   - `ZEXT(x, N)`, with `M` = $mask(N)
+// * `SHIFT(x, S)` is used for `LSR(x, S)` or `SHL(x, S)`.
+
 #include <assert.h>
 
 #include "parse.h"
@@ -12,7 +47,12 @@
 #include "flow.h"
 #include "symbol.h"
 
-/* Find the trivial parent for a phi-source */
+///
+// Utilities
+// ^^^^^^^^^
+
+///
+// find the trivial parent for a phi-source
 static struct basic_block *phi_parent(struct basic_block *source, pseudo_t pseudo)
 {
 	/* Can't go upwards if the pseudo is defined in the bb it came from.. */
@@ -26,16 +66,15 @@
 	return first_basic_block(source->parents);
 }
 
-/*
- * Copy the phi-node's phisrcs into to given array.
- * Returns 0 if the the list contained the expected
- * number of element, a positive number if there was
- * more than expected and a negative one if less.
- *
- * Note: we can't reuse a function like linearize_ptr_list()
- * because any VOIDs in the phi-list must be ignored here
- * as in this context they mean 'entry has been removed'.
- */
+///
+// copy the phi-node's phisrcs into to given array
+// @return: 0 if the the list contained the expected
+//	number of element, a positive number if there was
+//	more than expected and a negative one if less.
+//
+// :note: we can't reuse a function like linearize_ptr_list()
+//	because any VOIDs in the phi-list must be ignored here
+//	as in this context they mean 'entry has been removed'.
 static int get_phisources(struct instruction *sources[], int nbr, struct instruction *insn)
 {
 	pseudo_t phi;
@@ -68,9 +107,9 @@
 		return 0;
 	if (linearize_ptr_list((struct ptr_list *)bb->parents, (void **)parents, 3) != 2)
 		return 0;
-	p1 = array[0]->src1;
+	p1 = array[0]->phi_src;
 	bb1 = array[0]->bb;
-	p2 = array[1]->src1;
+	p2 = array[1]->phi_src;
 	bb2 = array[1]->bb;
 
 	/* Only try the simple "direct parents" case */
@@ -133,31 +172,64 @@
 	return REPEAT_CSE;
 }
 
-static int clean_up_phi(struct instruction *insn)
+///
+// detect trivial phi-nodes
+// @insn: the phi-node
+// @pseudo: the candidate resulting pseudo (NULL when starting)
+// @return: the unique result if the phi-node is trivial, NULL otherwise
+//
+// A phi-node is trivial if it has a single possible result:
+//	* all operands are the same
+//	* the operands are themselves defined by a chain or cycle of phi-nodes
+//		and the set of all operands involved contains a single value
+//		not defined by these phi-nodes
+//
+// Since the result is unique, these phi-nodes can be removed.
+static pseudo_t trivial_phi(pseudo_t pseudo, struct instruction *insn, struct pseudo_list **list)
 {
+	pseudo_t target = insn->target;
 	pseudo_t phi;
-	struct instruction *last;
-	int same;
 
-	last = NULL;
-	same = 1;
+	add_pseudo(list, target);
+
 	FOR_EACH_PTR(insn->phi_list, phi) {
 		struct instruction *def;
+		pseudo_t src;
+
 		if (phi == VOID)
 			continue;
 		def = phi->def;
-		if (def->src1 == VOID || !def->bb)
+		if (!def->bb)
 			continue;
-		if (last) {
-			if (last->src1 != def->src1)
-				same = 0;
+		src = def->phi_src; // bypass OP_PHISRC & get the real source
+		if (src == VOID)
 			continue;
+		if (!pseudo) {
+			pseudo = src;
+			continue;
 		}
-		last = def;
+		if (src == pseudo)
+			continue;
+		if (src == target)
+			continue;
+		if (DEF_OPCODE(def, src) == OP_PHI) {
+			if (pseudo_in_list(*list, src))
+				continue;
+			if ((pseudo = trivial_phi(pseudo, def, list)))
+				continue;
+		}
+		return NULL;
 	} END_FOR_EACH_PTR(phi);
 
-	if (same) {
-		pseudo_t pseudo = last ? last->src1 : VOID;
+	return pseudo ? pseudo : VOID;
+}
+
+static int clean_up_phi(struct instruction *insn)
+{
+	struct pseudo_list *list = NULL;
+	pseudo_t pseudo;
+
+	if ((pseudo = trivial_phi(NULL, insn, &list))) {
 		convert_instruction_target(insn, pseudo);
 		kill_instruction(insn);
 		return REPEAT_CSE;
@@ -179,29 +251,44 @@
 	} END_FOR_EACH_PTR(pu);
 	assert(count <= 0);
 out:
-	if (ptr_list_size((struct ptr_list *) *list) == 0)
+	if (pseudo_user_list_empty(*list))
 		*list = NULL;
 	return count;
 }
 
-static inline void remove_usage(pseudo_t p, pseudo_t *usep)
+static inline void rem_usage(pseudo_t p, pseudo_t *usep, int kill)
 {
 	if (has_use_list(p)) {
+		if (p->type == PSEUDO_SYM)
+			repeat_phase |= REPEAT_SYMBOL_CLEANUP;
 		delete_pseudo_user_list_entry(&p->users, usep, 1);
-		if (!p->users)
+		if (kill && !p->users)
 			kill_instruction(p->def);
 	}
 }
 
+static inline void remove_usage(pseudo_t p, pseudo_t *usep)
+{
+	rem_usage(p, usep, 1);
+}
+
 void kill_use(pseudo_t *usep)
 {
 	if (usep) {
 		pseudo_t p = *usep;
 		*usep = VOID;
-		remove_usage(p, usep);
+		rem_usage(p, usep, 1);
 	}
 }
 
+// Like kill_use() but do not (recursively) kill dead instructions
+void remove_use(pseudo_t *usep)
+{
+	pseudo_t p = *usep;
+	*usep = VOID;
+	rem_usage(p, usep, 0);
+}
+
 static void kill_use_list(struct pseudo_list *list)
 {
 	pseudo_t p;
@@ -212,19 +299,20 @@
 	} END_FOR_EACH_PTR(p);
 }
 
-/*
- * kill an instruction:
- * - remove it from its bb
- * - remove the usage of all its operands
- * If forse is zero, the normal case, the function only for
- * instructions free of (possible) side-effects. Otherwise
- * the function does that unconditionally (must only be used
- * for unreachable instructions.
- */
-void kill_insn(struct instruction *insn, int force)
+///
+// kill an instruction
+// @insn: the instruction to be killed
+// @force: if unset, the normal case, the instruction is not killed
+//	if not free of possible side-effect; if set the instruction
+//	is unconditionally killed.
+//
+// The killed instruction is removed from its BB and the usage
+// of all its operands are removed. The instruction is also
+// marked as killed by setting its ->bb to NULL.
+int kill_insn(struct instruction *insn, int force)
 {
 	if (!insn || !insn->bb)
-		return;
+		return 0;
 
 	switch (insn->opcode) {
 	case OP_SEL:
@@ -236,12 +324,8 @@
 		kill_use(&insn->src2);
 		/* fall through */
 
-	case OP_CAST:
-	case OP_SCAST:
-	case OP_FPCAST:
-	case OP_PTRCAST:
+	case OP_UNOP ... OP_UNOP_END:
 	case OP_SETVAL:
-	case OP_NOT: case OP_NEG:
 	case OP_SLICE:
 		kill_use(&insn->src1);
 		break;
@@ -254,10 +338,12 @@
 		break;
 
 	case OP_SYMADDR:
+		kill_use(&insn->src);
 		repeat_phase |= REPEAT_SYMBOL_CLEANUP;
 		break;
 
 	case OP_CBR:
+	case OP_SWITCH:
 	case OP_COMPUTEDGOTO:
 		kill_use(&insn->cond);
 		break;
@@ -266,9 +352,9 @@
 		if (!force) {
 			/* a "pure" function can be killed too */
 			if (!(insn->func->type == PSEUDO_SYM))
-				return;
+				return 0;
 			if (!(insn->func->sym->ctype.modifiers & MOD_PURE))
-				return;
+				return 0;
 		}
 		kill_use_list(insn->arguments);
 		if (insn->func->type == PSEUDO_REG)
@@ -276,14 +362,14 @@
 		break;
 
 	case OP_LOAD:
-		if (!force && insn->type->ctype.modifiers & MOD_VOLATILE)
-			return;
+		if (!force && insn->is_volatile)
+			return 0;
 		kill_use(&insn->src);
 		break;
 
 	case OP_STORE:
 		if (!force)
-			return;
+			return 0;
 		kill_use(&insn->src);
 		kill_use(&insn->target);
 		break;
@@ -290,28 +376,24 @@
 
 	case OP_ENTRY:
 		/* ignore */
-		return;
+		return 0;
 
 	case OP_BR:
+	case OP_SETFVAL:
 	default:
 		break;
 	}
 
 	insn->bb = NULL;
-	repeat_phase |= REPEAT_CSE;
-	return;
+	return repeat_phase |= REPEAT_CSE;
 }
 
-/*
- * Kill trivially dead instructions
- */
+///
+// kill trivially dead instructions
 static int dead_insn(struct instruction *insn, pseudo_t *src1, pseudo_t *src2, pseudo_t *src3)
 {
-	struct pseudo_user *pu;
-	FOR_EACH_PTR(insn->target->users, pu) {
-		if (*pu->userp != VOID)
-			return 0;
-	} END_FOR_EACH_PTR(pu);
+	if (has_users(insn->target))
+		return 0;
 
 	insn->bb = NULL;
 	kill_use(src1);
@@ -320,11 +402,47 @@
 	return REPEAT_CSE;
 }
 
+static inline bool has_target(struct instruction *insn)
+{
+	return opcode_table[insn->opcode].flags & OPF_TARGET;
+}
+
+void remove_dead_insns(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+
+	FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
+		struct instruction *insn;
+		FOR_EACH_PTR_REVERSE(bb->insns, insn) {
+			if (!insn->bb)
+				continue;
+			if (!has_target(insn))
+				continue;
+			if (!has_users(insn->target))
+				kill_instruction(insn);
+		} END_FOR_EACH_PTR_REVERSE(insn);
+	} END_FOR_EACH_PTR_REVERSE(bb);
+}
+
 static inline int constant(pseudo_t pseudo)
 {
 	return pseudo->type == PSEUDO_VAL;
 }
 
+///
+// replace the operand of an instruction
+// @insn: the instruction
+// @pp: the address of the instruction's operand
+// @new: the new value for the operand
+// @return: REPEAT_CSE.
+static inline int replace_pseudo(struct instruction *insn, pseudo_t *pp, pseudo_t new)
+{
+	pseudo_t old = *pp;
+	use_pseudo(insn, new, pp);
+	remove_usage(old, pp);
+	return REPEAT_CSE;
+}
+
 static int replace_with_pseudo(struct instruction *insn, pseudo_t pseudo)
 {
 	convert_instruction_target(insn, pseudo);
@@ -335,13 +453,8 @@
 		kill_use(&insn->src3);
 	case OP_BINARY ... OP_BINCMP_END:
 		kill_use(&insn->src2);
-	case OP_NOT:
-	case OP_NEG:
+	case OP_UNOP ... OP_UNOP_END:
 	case OP_SYMADDR:
-	case OP_CAST:
-	case OP_SCAST:
-	case OP_FPCAST:
-	case OP_PTRCAST:
 		kill_use(&insn->src1);
 		break;
 
@@ -352,8 +465,15 @@
 	return REPEAT_CSE;
 }
 
-unsigned int value_size(long long value)
+static inline int def_opcode(pseudo_t p)
 {
+	if (p->type != PSEUDO_REG)
+		return OP_BADOP;
+	return p->def->opcode;
+}
+
+static unsigned int value_size(long long value)
+{
 	value >>= 8;
 	if (!value)
 		return 8;
@@ -366,12 +486,11 @@
 	return 64;
 }
 
-/*
- * Try to determine the maximum size of bits in a pseudo.
- *
- * Right now this only follow casts and constant values, but we
- * could look at things like logical 'and' instructions etc.
- */
+///
+// try to determine the maximum size of bits in a pseudo
+//
+// Right now this only follow casts and constant values, but we
+// could look at things like AND instructions, etc.
 static unsigned int operand_size(struct instruction *insn, pseudo_t pseudo)
 {
 	unsigned int size = insn->size;
@@ -378,7 +497,7 @@
 
 	if (pseudo->type == PSEUDO_REG) {
 		struct instruction *src = pseudo->def;
-		if (src && src->opcode == OP_CAST && src->orig_type) {
+		if (src && src->opcode == OP_ZEXT && src->orig_type) {
 			unsigned int orig_size = src->orig_type->bit_size;
 			if (orig_size < size)
 				size = orig_size;
@@ -392,17 +511,417 @@
 	return size;
 }
 
-static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long value)
+static pseudo_t eval_insn(struct instruction *insn)
 {
-	unsigned int size = operand_size(insn, pseudo);
+	/* FIXME! Verify signs and sizes!! */
+	unsigned int size = insn->size;
+	long long left = insn->src1->value;
+	long long right = insn->src2->value;
+	unsigned long long ul, ur;
+	long long res, mask, bits;
 
-	if (value >= size) {
-		warning(insn->pos, "right shift by bigger than source value");
-		return replace_with_pseudo(insn, value_pseudo(insn->type, 0));
+	mask = 1ULL << (size-1);
+	bits = mask | (mask-1);
+
+	if (left & mask)
+		left |= ~bits;
+	if (right & mask)
+		right |= ~bits;
+	ul = left & bits;
+	ur = right & bits;
+
+	switch (insn->opcode) {
+	case OP_ADD:
+		res = left + right;
+		break;
+	case OP_SUB:
+		res = left - right;
+		break;
+	case OP_MUL:
+		res = ul * ur;
+		break;
+	case OP_DIVU:
+		if (!ur)
+			goto undef;
+		res = ul / ur;
+		break;
+	case OP_DIVS:
+		if (!right)
+			goto undef;
+		if (left == mask && right == -1)
+			goto undef;
+		res = left / right;
+		break;
+	case OP_MODU:
+		if (!ur)
+			goto undef;
+		res = ul % ur;
+		break;
+	case OP_MODS:
+		if (!right)
+			goto undef;
+		if (left == mask && right == -1)
+			goto undef;
+		res = left % right;
+		break;
+	case OP_SHL:
+		if (ur >= size)
+			goto undef;
+		res = left << right;
+		break;
+	case OP_LSR:
+		if (ur >= size)
+			goto undef;
+		res = ul >> ur;
+		break;
+	case OP_ASR:
+		if (ur >= size)
+			goto undef;
+		res = left >> right;
+		break;
+       /* Logical */
+	case OP_AND:
+		res = left & right;
+		break;
+	case OP_OR:
+		res = left | right;
+		break;
+	case OP_XOR:
+		res = left ^ right;
+		break;
+
+	/* Binary comparison */
+	case OP_SET_EQ:
+		res = left == right;
+		break;
+	case OP_SET_NE:
+		res = left != right;
+		break;
+	case OP_SET_LE:
+		res = left <= right;
+		break;
+	case OP_SET_GE:
+		res = left >= right;
+		break;
+	case OP_SET_LT:
+		res = left < right;
+		break;
+	case OP_SET_GT:
+		res = left > right;
+		break;
+	case OP_SET_B:
+		res = ul < ur;
+		break;
+	case OP_SET_A:
+		res = ul > ur;
+		break;
+	case OP_SET_BE:
+		res = ul <= ur;
+		break;
+	case OP_SET_AE:
+		res = ul >= ur;
+		break;
+	default:
+		return NULL;
 	}
+	res &= bits;
+
+	return value_pseudo(res);
+
+undef:
+	return NULL;
+}
+
+///
+// Simplifications
+// ^^^^^^^^^^^^^^^
+
+///
+// try to simplify MASK(OR(AND(x, M'), b), M)
+// @insn: the masking instruction
+// @mask: the associated mask (M)
+// @ora: one of the OR's operands, guaranteed to be PSEUDO_REG
+// @orb: the other OR's operand
+// @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
+static int simplify_mask_or_and(struct instruction *insn, unsigned long long mask,
+	pseudo_t ora, pseudo_t orb)
+{
+	unsigned long long omask, nmask;
+	struct instruction *and = ora->def;
+	pseudo_t src2 = and->src2;
+
+	if (and->opcode != OP_AND)
+		return 0;
+	if (!constant(src2))
+		return 0;
+	omask = src2->value;
+	nmask = omask & mask;
+	if (nmask == 0) {
+		// if (M' & M) == 0: ((a & M') | b) -> b
+		return replace_pseudo(insn, &insn->src1, orb);
+	}
+	if (multi_users(insn->src1))
+		return 0;	// can't modify anything inside the OR
+	if (nmask == mask) {
+		struct instruction *or = insn->src1->def;
+		pseudo_t *arg = (ora == or->src1) ? &or->src1 : &or->src2;
+		// if (M' & M) == M: ((a & M') | b) -> (a | b)
+		return replace_pseudo(or, arg, and->src1);
+	}
+	if (nmask != omask && !multi_users(ora)) {
+		// if (M' & M) != M': AND(a, M') -> AND(a, (M' & M))
+		and->src2 = value_pseudo(nmask);
+		return REPEAT_CSE;
+	}
+	return 0;
+}
+
+///
+// try to simplify MASK(OR(a, b), M)
+// @insn: the masking instruction
+// @mask: the associated mask (M)
+// @or: the OR instruction
+// @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
+static int simplify_mask_or(struct instruction *insn, unsigned long long mask, struct instruction *or)
+{
+	pseudo_t src1 = or->src1;
+	pseudo_t src2 = or->src2;
+	int rc;
+
+	if (src1->type == PSEUDO_REG) {
+		if ((rc = simplify_mask_or_and(insn, mask, src1, src2)))
+			return rc;
+	}
+	if (src2->type == PSEUDO_REG) {
+		if ((rc = simplify_mask_or_and(insn, mask, src2, src1)))
+			return rc;
+	} else if (src2->type == PSEUDO_VAL) {
+		unsigned long long oval = src2->value;
+		unsigned long long nval = oval & mask;
+		// Try to simplify:
+		//	MASK(OR(x, C), M)
+		if (nval == 0) {
+			// if (C & M) == 0: OR(x, C) -> x
+			return replace_pseudo(insn, &insn->src1, src1);
+		}
+		if (nval == mask) {
+			// if (C & M) == M: OR(x, C) -> M
+			return replace_pseudo(insn, &insn->src1, value_pseudo(mask));
+		}
+		if (nval != oval && !multi_users(or->target)) {
+			// if (C & M) != C: OR(x, C) -> OR(x, (C & M))
+			return replace_pseudo(or, &or->src2, value_pseudo(nval));
+		}
+	}
+	return 0;
+}
+
+///
+// try to simplify MASK(SHIFT(OR(a, b), S), M)
+// @sh: the shift instruction
+// @or: the OR instruction
+// @mask: the mask associated to MASK (M):
+// @return: 0 if no changes have been made, one or more REPEAT_* flags otherwise.
+static int simplify_mask_shift_or(struct instruction *sh, struct instruction *or, unsigned long long mask)
+{
+	unsigned long long smask = bits_mask(sh->size);
+	int shift = sh->src2->value;
+
+	if (sh->opcode == OP_LSR)
+		mask <<= shift;
+	else
+		mask >>= shift;
+	return simplify_mask_or(sh, smask & mask, or);
+}
+
+static int simplify_mask_shift(struct instruction *sh, unsigned long long mask)
+{
+	struct instruction *inner;
+
+	if (!constant(sh->src2) || sh->tainted)
+		return 0;
+	switch (DEF_OPCODE(inner, sh->src1)) {
+	case OP_OR:
+		if (!multi_users(sh->target))
+			return simplify_mask_shift_or(sh, inner, mask);
+		break;
+	}
+	return 0;
+}
+
+static long long check_shift_count(struct instruction *insn, unsigned long long uval)
+{
+	unsigned int size = insn->size;
+	long long sval = uval;
+
+	if (uval < size)
+		return uval;
+
+	sval = sign_extend_safe(sval, size);
+	sval = sign_extend_safe(sval, bits_in_int);
+	if (sval < 0)
+		insn->src2 = value_pseudo(sval);
+	if (insn->tainted)
+		return sval;
+
+	if (sval < 0 && Wshift_count_negative)
+		warning(insn->pos, "shift count is negative (%lld)", sval);
+	if (sval > 0 && Wshift_count_overflow) {
+		struct symbol *ctype = insn->type;
+		const char *tname;
+		if (ctype->type == SYM_NODE)
+			ctype = ctype->ctype.base_type;
+		tname = show_typename(ctype);
+		warning(insn->pos, "shift too big (%llu) for type %s", sval, tname);
+	}
+	insn->tainted = 1;
+	return sval;
+}
+
+static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value)
+{
+	struct instruction *def;
+	unsigned long long mask, omask, nmask;
+	unsigned long long nval;
+	unsigned int size;
+	pseudo_t src2;
+
 	if (!value)
 		return replace_with_pseudo(insn, pseudo);
+	value = check_shift_count(insn, value);
+	if (value < 0)
+		return 0;
+
+	size = insn->size;
+	switch (insn->opcode) {
+	case OP_ASR:
+		if (value >= size)
+			return 0;
+		if (pseudo->type != PSEUDO_REG)
+			break;
+		def = pseudo->def;
+		switch (def->opcode) {
+		case OP_LSR:
+		case OP_ASR:
+			if (def == insn)	// cyclic DAG!
+				break;
+			src2 = def->src2;
+			if (src2->type != PSEUDO_VAL)
+				break;
+			nval = src2->value;
+			if (nval > insn->size || nval == 0)
+				break;
+			value += nval;
+			if (def->opcode == OP_LSR)
+				insn->opcode = OP_LSR;
+			else if (value >= size)
+				value = size - 1;
+			goto new_value;
+
+		case OP_ZEXT:
+			// transform:
+			//	zext.N	%t <- (O) %a
+			//	asr.N	%r <- %t, C
+			// into
+			//	zext.N	%t <- (O) %a
+			//	lsr.N	%r <- %t, C
+			insn->opcode = OP_LSR;
+			return REPEAT_CSE;
+		}
+		break;
+	case OP_LSR:
+		size = operand_size(insn, pseudo);
+		if (value >= size)
+			goto zero;
+		switch(DEF_OPCODE(def, pseudo)) {
+		case OP_AND:
+			// replace (A & M) >> S
+			// by      (A >> S) & (M >> S)
+			if (!constant(def->src2))
+				break;
+			mask = bits_mask(insn->size - value) << value;
+			omask = def->src2->value;
+			nmask = omask & mask;
+			if (nmask == 0)
+				return replace_with_pseudo(insn, value_pseudo(0));
+			if (nmask == mask)
+				return replace_pseudo(insn, &insn->src1, def->src1);
+			if (nbr_users(pseudo) > 1)
+				break;
+			def->opcode = OP_LSR;
+			def->src2 = insn->src2;
+			insn->opcode = OP_AND;
+			insn->src2 = value_pseudo(omask >> value);
+			return REPEAT_CSE;
+		case OP_LSR:
+			goto case_shift_shift;
+		case OP_OR:
+			mask = bits_mask(size);
+			return simplify_mask_shift_or(insn, def, mask);
+		case OP_SHL:
+			// replace ((x << S) >> S)
+			// by      (x & (-1 >> S))
+			if (def->src2 != insn->src2)
+				break;
+			mask = bits_mask(insn->size - value);
+			goto replace_mask;
+		}
+		break;
+	case OP_SHL:
+		if (value >= size)
+			goto zero;
+		switch(DEF_OPCODE(def, pseudo)) {
+		case OP_AND:
+			// simplify (A & M) << S
+			if (!constant(def->src2))
+				break;
+			mask = bits_mask(insn->size) >> value;
+			omask = def->src2->value;
+			nmask = omask & mask;
+			if (nmask == 0)
+				return replace_with_pseudo(insn, value_pseudo(0));
+			if (nmask == mask)
+				return replace_pseudo(insn, &insn->src1, def->src1);
+			// do not simplify into ((A << S) & (M << S))
+			break;
+		case OP_LSR:
+			// replace ((x >> S) << S)
+			// by      (x & (-1 << S))
+			if (def->src2 != insn->src2)
+				break;
+			mask = bits_mask(insn->size - value) << value;
+			goto replace_mask;
+		case OP_OR:
+			mask = bits_mask(size);
+			return simplify_mask_shift_or(insn, def, mask);
+		case OP_SHL:
+		case_shift_shift:		// also for LSR - LSR
+			if (def == insn)	// cyclic DAG!
+				break;
+			src2 = def->src2;
+			if (src2->type != PSEUDO_VAL)
+				break;
+			nval = src2->value;
+			if (nval > insn->size)
+				break;
+			value += nval;
+			goto new_value;
+		}
+		break;
+	}
 	return 0;
+
+new_value:
+	if (value < size) {
+		insn->src2 = value_pseudo(value);
+		return replace_pseudo(insn, &insn->src1, pseudo->def->src1);
+	}
+zero:
+	return replace_with_pseudo(insn, value_pseudo(0));
+replace_mask:
+	insn->opcode = OP_AND;
+	insn->src2 = value_pseudo(mask);
+	return replace_pseudo(insn, &insn->src1, def->src1);
 }
 
 static int simplify_mul_div(struct instruction *insn, long long value)
@@ -414,8 +933,7 @@
 		return replace_with_pseudo(insn, insn->src1);
 
 	switch (insn->opcode) {
-	case OP_MULS:
-	case OP_MULU:
+	case OP_MUL:
 		if (value == 0)
 			return replace_with_pseudo(insn, insn->src2);
 	/* Fall through */
@@ -433,35 +951,11 @@
 	return 0;
 }
 
-static int compare_opcode(int opcode, int inverse)
-{
-	if (!inverse)
-		return opcode;
-
-	switch (opcode) {
-	case OP_SET_EQ:	return OP_SET_NE;
-	case OP_SET_NE:	return OP_SET_EQ;
-
-	case OP_SET_LT:	return OP_SET_GE;
-	case OP_SET_LE:	return OP_SET_GT;
-	case OP_SET_GT:	return OP_SET_LE;
-	case OP_SET_GE:	return OP_SET_LT;
-
-	case OP_SET_A:	return OP_SET_BE;
-	case OP_SET_AE:	return OP_SET_B;
-	case OP_SET_B:	return OP_SET_AE;
-	case OP_SET_BE:	return OP_SET_A;
-
-	default:
-		return opcode;
-	}
-}
-
 static int simplify_seteq_setne(struct instruction *insn, long long value)
 {
 	pseudo_t old = insn->src1;
-	struct instruction *def = old->def;
-	pseudo_t src1, src2;
+	struct instruction *def;
+	unsigned osize;
 	int inverse;
 	int opcode;
 
@@ -468,13 +962,34 @@
 	if (value != 0 && value != 1)
 		return 0;
 
+	if (old->type != PSEUDO_REG)
+		return 0;
+	def = old->def;
 	if (!def)
 		return 0;
 
 	inverse = (insn->opcode == OP_SET_NE) == value;
+	if (!inverse && def->size == 1 && insn->size == 1) {
+		// Replace:
+		//	setne   %r <- %s, $0
+		// or:
+		//	seteq   %r <- %s, $1
+		// by %s when boolean
+		return replace_with_pseudo(insn, old);
+	}
 	opcode = def->opcode;
 	switch (opcode) {
-	case OP_BINCMP ... OP_BINCMP_END:
+	case OP_AND:
+		if (inverse)
+			break;
+		if (def->size != insn->size)
+			break;
+		if (def->src2->type != PSEUDO_VAL)
+			break;
+		if (def->src2->value != 1)
+			break;
+		return replace_with_pseudo(insn, old);
+	case OP_FPCMP ... OP_BINCMP_END:
 		// Convert:
 		//	setcc.n	%t <- %a, %b
 		//	setne.m %r <- %t, $0
@@ -482,64 +997,131 @@
 		//	setcc.n	%t <- %a, %b
 		//	setcc.m %r <- %a, $b
 		// and similar for setne/eq ... 0/1
-		src1 = def->src1;
-		src2 = def->src2;
-		insn->opcode = compare_opcode(opcode, inverse);
-		use_pseudo(insn, src1, &insn->src1);
-		use_pseudo(insn, src2, &insn->src2);
+		insn->opcode = inverse ? opcode_table[opcode].negate : opcode;
+		use_pseudo(insn, def->src1, &insn->src1);
+		use_pseudo(insn, def->src2, &insn->src2);
 		remove_usage(old, &insn->src1);
 		return REPEAT_CSE;
 
-	default:
-		return 0;
+	case OP_SEXT:
+		if (value && (def->orig_type->bit_size == 1))
+			break;
+		/* Fall through */
+	case OP_ZEXT:
+		// Convert:
+		//	*ext.m	%s <- (1) %a
+		//	setne.1 %r <- %s, $0
+		// into:
+		//	setne.1 %s <- %a, $0
+		// and same for setne/eq ... 0/1
+		return replace_pseudo(insn, &insn->src1, def->src);
+	case OP_TRUNC:
+		if (multi_users(old))
+			break;
+		// convert
+		//	trunc.n	%s <- (o) %a
+		//	setne.m %r <- %s, $0
+		// into:
+		//	and.o	%s <- %a, $((1 << o) - 1)
+		//	setne.m %r <- %s, $0
+		// and same for setne/eq ... 0/1
+		osize = def->size;
+		def->opcode = OP_AND;
+		def->type = def->orig_type;
+		def->size = def->type->bit_size;
+		def->src2 = value_pseudo(bits_mask(osize));
+		return REPEAT_CSE;
 	}
+	return 0;
 }
 
+static int simplify_constant_mask(struct instruction *insn, unsigned long long mask)
+{
+	pseudo_t old = insn->src1;
+	unsigned long long omask;
+	unsigned long long nmask;
+	struct instruction *def;
+	int osize;
+
+	switch (DEF_OPCODE(def, old)) {
+	case OP_FPCMP ... OP_BINCMP_END:
+		osize = 1;
+		goto oldsize;
+	case OP_OR:
+		return simplify_mask_or(insn, mask, def);
+	case OP_LSR:
+	case OP_SHL:
+		return simplify_mask_shift(def, mask);
+	case OP_ZEXT:
+		osize = def->orig_type->bit_size;
+		/* fall through */
+	oldsize:
+		omask = (1ULL << osize) - 1;
+		nmask = mask & omask;
+		if (nmask == omask)
+			// the AND mask is redundant
+			return replace_with_pseudo(insn, old);
+		if (nmask != mask) {
+			// can use a smaller mask
+			insn->src2 = value_pseudo(nmask);
+			return REPEAT_CSE;
+		}
+		break;
+	}
+	return 0;
+}
+
 static int simplify_constant_rightside(struct instruction *insn)
 {
 	long long value = insn->src2->value;
+	long long sbit = 1ULL << (insn->size - 1);
+	long long bits = sbit | (sbit - 1);
 
 	switch (insn->opcode) {
-	case OP_OR_BOOL:
-		if (value == 1)
+	case OP_OR:
+		if ((value & bits) == bits)
 			return replace_with_pseudo(insn, insn->src2);
 		goto case_neutral_zero;
 
+	case OP_XOR:
+		if ((value & bits) == bits) {
+			insn->opcode = OP_NOT;
+			return REPEAT_CSE;
+		}
+		goto case_neutral_zero;
+
 	case OP_SUB:
 		if (value) {
 			insn->opcode = OP_ADD;
-			insn->src2 = value_pseudo(insn->type, -value);
+			insn->src2 = value_pseudo(-value);
 			return REPEAT_CSE;
 		}
 	/* Fall through */
 	case OP_ADD:
-	case OP_OR: case OP_XOR:
-	case OP_SHL:
-	case OP_LSR:
 	case_neutral_zero:
 		if (!value)
 			return replace_with_pseudo(insn, insn->src1);
 		return 0;
 	case OP_ASR:
-		return simplify_asr(insn, insn->src1, value);
+	case OP_SHL:
+	case OP_LSR:
+		return simplify_shift(insn, insn->src1, value);
 
 	case OP_MODU: case OP_MODS:
 		if (value == 1)
-			return replace_with_pseudo(insn, value_pseudo(insn->type, 0));
+			return replace_with_pseudo(insn, value_pseudo(0));
 		return 0;
 
 	case OP_DIVU: case OP_DIVS:
-	case OP_MULU: case OP_MULS:
+	case OP_MUL:
 		return simplify_mul_div(insn, value);
 
-	case OP_AND_BOOL:
-		if (value == 1)
-			return replace_with_pseudo(insn, insn->src1);
-	/* Fall through */
 	case OP_AND:
 		if (!value)
 			return replace_with_pseudo(insn, insn->src2);
-		return 0;
+		if ((value & bits) == bits)
+			return replace_with_pseudo(insn, insn->src1);
+		return simplify_constant_mask(insn, value);
 
 	case OP_SET_NE:
 	case OP_SET_EQ:
@@ -561,7 +1143,7 @@
 	case OP_SHL:
 	case OP_LSR: case OP_ASR:
 	case OP_AND:
-	case OP_MULU: case OP_MULS:
+	case OP_MUL:
 		if (!value)
 			return replace_with_pseudo(insn, insn->src1);
 		return 0;
@@ -571,122 +1153,12 @@
 
 static int simplify_constant_binop(struct instruction *insn)
 {
-	/* FIXME! Verify signs and sizes!! */
-	long long left = insn->src1->value;
-	long long right = insn->src2->value;
-	unsigned long long ul, ur;
-	long long res, mask, bits;
+	pseudo_t res = eval_insn(insn);
 
-	mask = 1ULL << (insn->size-1);
-	bits = mask | (mask-1);
-
-	if (left & mask)
-		left |= ~bits;
-	if (right & mask)
-		right |= ~bits;
-	ul = left & bits;
-	ur = right & bits;
-
-	switch (insn->opcode) {
-	case OP_ADD:
-		res = left + right;
-		break;
-	case OP_SUB:
-		res = left - right;
-		break;
-	case OP_MULU:
-		res = ul * ur;
-		break;
-	case OP_MULS:
-		res = left * right;
-		break;
-	case OP_DIVU:
-		if (!ur)
-			return 0;
-		res = ul / ur;
-		break;
-	case OP_DIVS:
-		if (!right)
-			return 0;
-		if (left == mask && right == -1)
-			return 0;
-		res = left / right;
-		break;
-	case OP_MODU:
-		if (!ur)
-			return 0;
-		res = ul % ur;
-		break;
-	case OP_MODS:
-		if (!right)
-			return 0;
-		if (left == mask && right == -1)
-			return 0;
-		res = left % right;
-		break;
-	case OP_SHL:
-		res = left << right;
-		break;
-	case OP_LSR:
-		res = ul >> ur;
-		break;
-	case OP_ASR:
-		res = left >> right;
-		break;
-       /* Logical */
-	case OP_AND:
-		res = left & right;
-		break;
-	case OP_OR:
-		res = left | right;
-		break;
-	case OP_XOR:
-		res = left ^ right;
-		break;
-	case OP_AND_BOOL:
-		res = left && right;
-		break;
-	case OP_OR_BOOL:
-		res = left || right;
-		break;
-			       
-	/* Binary comparison */
-	case OP_SET_EQ:
-		res = left == right;
-		break;
-	case OP_SET_NE:
-		res = left != right;
-		break;
-	case OP_SET_LE:
-		res = left <= right;
-		break;
-	case OP_SET_GE:
-		res = left >= right;
-		break;
-	case OP_SET_LT:
-		res = left < right;
-		break;
-	case OP_SET_GT:
-		res = left > right;
-		break;
-	case OP_SET_B:
-		res = ul < ur;
-		break;
-	case OP_SET_A:
-		res = ul > ur;
-		break;
-	case OP_SET_BE:
-		res = ul <= ur;
-		break;
-	case OP_SET_AE:
-		res = ul >= ur;
-		break;
-	default:
+	if (!res)
 		return 0;
-	}
-	res &= bits;
 
-	replace_with_pseudo(insn, value_pseudo(insn->type, res));
+	replace_with_pseudo(insn, res);
 	return REPEAT_CSE;
 }
 
@@ -700,7 +1172,7 @@
 			warning(insn->pos, "self-comparison always evaluates to false");
 	case OP_SUB:
 	case OP_XOR:
-		return replace_with_pseudo(insn, value_pseudo(insn->type, 0));
+		return replace_with_pseudo(insn, value_pseudo(0));
 
 	case OP_SET_EQ:
 	case OP_SET_LE: case OP_SET_GE:
@@ -707,19 +1179,12 @@
 	case OP_SET_BE: case OP_SET_AE:
 		if (Wtautological_compare)
 			warning(insn->pos, "self-comparison always evaluates to true");
-		return replace_with_pseudo(insn, value_pseudo(insn->type, 1));
+		return replace_with_pseudo(insn, value_pseudo(1));
 
 	case OP_AND:
 	case OP_OR:
 		return replace_with_pseudo(insn, arg);
 
-	case OP_AND_BOOL:
-	case OP_OR_BOOL:
-		remove_usage(arg, &insn->src2);
-		insn->src2 = value_pseudo(insn->type, 0);
-		insn->opcode = OP_SET_NE;
-		return REPEAT_CSE;
-
 	default:
 		break;
 	}
@@ -765,15 +1230,25 @@
 	return 1;
 }
 
-static int simplify_commutative_binop(struct instruction *insn)
+static int canonicalize_commutative(struct instruction *insn)
 {
-	if (!canonical_order(insn->src1, insn->src2)) {
-		switch_pseudo(insn, &insn->src1, insn, &insn->src2);
-		return REPEAT_CSE;
-	}
-	return 0;
+	if (canonical_order(insn->src1, insn->src2))
+		return 0;
+
+	switch_pseudo(insn, &insn->src1, insn, &insn->src2);
+	return repeat_phase |= REPEAT_CSE;
 }
 
+static int canonicalize_compare(struct instruction *insn)
+{
+	if (canonical_order(insn->src1, insn->src2))
+		return 0;
+
+	switch_pseudo(insn, &insn->src1, insn, &insn->src2);
+	insn->opcode = opcode_table[insn->opcode].swap;
+	return repeat_phase |= REPEAT_CSE;
+}
+
 static inline int simple_pseudo(pseudo_t pseudo)
 {
 	return pseudo->type == PSEUDO_VAL || pseudo->type == PSEUDO_SYM;
@@ -795,7 +1270,7 @@
 		return 0;
 	if (!simple_pseudo(def->src2))
 		return 0;
-	if (ptr_list_size((struct ptr_list *)def->target->users) != 1)
+	if (multi_users(def->target))
 		return 0;
 	switch_pseudo(def, &def->src1, insn, &insn->src2);
 	return REPEAT_CSE;
@@ -813,6 +1288,15 @@
 	case OP_NEG:
 		res = -val;
 		break;
+	case OP_SEXT:
+		mask = 1ULL << (insn->orig_type->bit_size-1);
+		if (val & mask)
+			val |= ~(mask | (mask-1));
+		/* fall through */
+	case OP_ZEXT:
+	case OP_TRUNC:
+		res = val;
+		break;
 	default:
 		return 0;
 	}
@@ -819,7 +1303,7 @@
 	mask = 1ULL << (insn->size-1);
 	res &= mask | (mask-1);
 	
-	replace_with_pseudo(insn, value_pseudo(insn->type, res));
+	replace_with_pseudo(insn, value_pseudo(res));
 	return REPEAT_CSE;
 }
 
@@ -877,7 +1361,7 @@
 
 offset:
 	/* Invalid code */
-	if (new == orig) {
+	if (new == orig || new == addr) {
 		if (new == VOID)
 			return 0;
 		/*
@@ -889,19 +1373,20 @@
 		 */
 		if (repeat_phase & REPEAT_CFG_CLEANUP)
 			return 0;
-		new = VOID;
 		warning(insn->pos, "crazy programmer");
+		replace_pseudo(insn, &insn->src, VOID);
+		return 0;
 	}
 	insn->offset += off->value;
-	use_pseudo(insn, new, &insn->src);
-	remove_usage(addr, &insn->src);
+	replace_pseudo(insn, &insn->src, new);
 	return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
 }
 
-/*
- * We walk the whole chain of adds/subs backwards. That's not
- * only more efficient, but it allows us to find loops.
- */
+///
+// simplify memops instructions
+//
+// :note: We walk the whole chain of adds/subs backwards.
+//	That's not only more efficient, but it allows us to find loops.
 static int simplify_memop(struct instruction *insn)
 {
 	int one, ret = 0;
@@ -914,73 +1399,148 @@
 	return ret;
 }
 
-static long long get_cast_value(long long val, int old_size, int new_size, int sign)
-{
-	long long mask;
-
-	if (sign && new_size > old_size) {
-		mask = 1 << (old_size-1);
-		if (val & mask)
-			val |= ~(mask | (mask-1));
-	}
-	mask = 1 << (new_size-1);
-	return val & (mask | (mask-1));
-}
-
 static int simplify_cast(struct instruction *insn)
 {
-	struct symbol *orig_type;
-	int orig_size, size;
+	unsigned long long mask;
+	struct instruction *def;
 	pseudo_t src;
+	pseudo_t val;
+	int osize;
+	int size;
 
 	if (dead_insn(insn, &insn->src, NULL, NULL))
 		return REPEAT_CSE;
 
-	orig_type = insn->orig_type;
-	if (!orig_type)
-		return 0;
+	src = insn->src;
 
-	/* Keep casts with pointer on either side (not only case of OP_PTRCAST) */
-	if (is_ptr_type(orig_type) || is_ptr_type(insn->type))
-		return 0;
+	/* A cast of a constant? */
+	if (constant(src))
+		return simplify_constant_unop(insn);
 
-	orig_size = orig_type->bit_size;
+	// can merge with the previous instruction?
 	size = insn->size;
-	src = insn->src;
+	def = src->def;
+	switch (def_opcode(src)) {
+	case OP_AND:
+		val = def->src2;
+		if (val->type != PSEUDO_VAL)
+			break;
+		/* A cast of a AND might be a no-op.. */
+		switch (insn->opcode) {
+		case OP_TRUNC:
+			if (multi_users(src))
+				break;
+			def->opcode = OP_TRUNC;
+			def->orig_type = def->type;
+			def->type = insn->type;
+			def->size = size;
 
-	/* A cast of a constant? */
-	if (constant(src)) {
-		int sign = orig_type->ctype.modifiers & MOD_SIGNED;
-		long long val = get_cast_value(src->value, orig_size, size, sign);
-		src = value_pseudo(orig_type, val);
-		goto simplify;
-	}
+			insn->opcode = OP_AND;
+			mask = val->value;
+			mask &= (1ULL << size) - 1;
+			insn->src2 = value_pseudo(mask);
+			return REPEAT_CSE;
 
-	/* A cast of a "and" might be a no-op.. */
-	if (src->type == PSEUDO_REG) {
-		struct instruction *def = src->def;
-		if (def->opcode == OP_AND && def->size >= size) {
-			pseudo_t val = def->src2;
-			if (val->type == PSEUDO_VAL) {
-				unsigned long long value = val->value;
-				if (!(value >> (size-1)))
-					goto simplify;
-			}
+		case OP_SEXT:
+			if (val->value & (1 << (def->size - 1)))
+				break;
+			// OK, sign bit is 0
+		case OP_ZEXT:
+			if (multi_users(src))
+				break;
+			// transform:
+			//	and.n	%b <- %a, M
+			//	*ext.m	%c <- (n) %b
+			// into:
+			//	zext.m	%b <- %a
+			//	and.m	%c <- %b, M
+			// For ZEXT, the mask will always be small
+			// enough. For SEXT, it can only be done if
+			// the mask force the sign bit to 0.
+			def->opcode = OP_ZEXT;
+			def->orig_type = insn->orig_type;
+			def->type = insn->type;
+			def->size = insn->size;
+			insn->opcode = OP_AND;
+			insn->src2 = val;
+			return REPEAT_CSE;
 		}
+		break;
+	case OP_FPCMP ... OP_BINCMP_END:
+		switch (insn->opcode) {
+		case OP_SEXT:
+			if (insn->size == 1)
+				break;
+			/* fall through */
+		case OP_ZEXT:
+		case OP_TRUNC:
+			// simplify:
+			//	setcc.n	%t <- %a, %b
+			//	zext.m	%r <- (n) %t
+			// into:
+			//	setcc.m	%r <- %a, %b
+			// and same for s/zext/trunc/
+			insn->opcode = def->opcode;
+			use_pseudo(insn, def->src2, &insn->src2);
+			return replace_pseudo(insn, &insn->src1, def->src1);
+		}
+		break;
+	case OP_OR:
+		switch (insn->opcode) {
+		case OP_TRUNC:
+			mask = bits_mask(insn->size);
+			return simplify_mask_or(insn, mask, def);
+		}
+		break;
+	case OP_LSR:
+	case OP_SHL:
+		if (insn->opcode != OP_TRUNC)
+			break;
+		mask = bits_mask(insn->size);
+		return simplify_mask_shift(def, mask);
+	case OP_TRUNC:
+		switch (insn->opcode) {
+		case OP_TRUNC:
+			insn->orig_type = def->orig_type;
+			return replace_pseudo(insn, &insn->src1, def->src);
+		case OP_ZEXT:
+			if (size != def->orig_type->bit_size)
+				break;
+			insn->opcode = OP_AND;
+			insn->src2 = value_pseudo((1ULL << def->size) - 1);
+			return replace_pseudo(insn, &insn->src1, def->src);
+		}
+		break;
+	case OP_ZEXT:
+		switch (insn->opcode) {
+		case OP_SEXT:
+			insn->opcode = OP_ZEXT;
+			/* fall through */
+		case OP_ZEXT:
+			insn->orig_type = def->orig_type;
+			return replace_pseudo(insn, &insn->src, def->src);
+		}
+		/* fall through */
+	case OP_SEXT:
+		switch (insn->opcode) {
+		case OP_TRUNC:
+			osize = def->orig_type->bit_size;
+			if (size == osize)
+				return replace_with_pseudo(insn, def->src);
+			if (size > osize)
+				insn->opcode = def->opcode;
+			insn->orig_type = def->orig_type;
+			return replace_pseudo(insn, &insn->src, def->src);
+		}
+		switch (insn->opcode) {
+		case OP_SEXT:
+			insn->orig_type = def->orig_type;
+			return replace_pseudo(insn, &insn->src, def->src);
+		}
+		break;
 	}
 
-	if (size == orig_size) {
-		int op = (orig_type->ctype.modifiers & MOD_SIGNED) ? OP_SCAST : OP_CAST;
-		if (insn->opcode == op)
-			goto simplify;
-		if (insn->opcode == OP_FPCAST && is_float_type(orig_type))
-			goto simplify;
-	}
-
 	return 0;
-
-simplify:
-	return replace_with_pseudo(insn, src);
 }
 
 static int simplify_select(struct instruction *insn)
@@ -1019,6 +1579,12 @@
 			return REPEAT_CSE;
 		}
 	}
+	if (cond == src2 && is_zero(src1)) {
+		kill_use(&insn->src1);
+		kill_use(&insn->src3);
+		replace_with_pseudo(insn, value_pseudo(0));
+		return REPEAT_CSE;
+	}
 	return 0;
 }
 
@@ -1051,18 +1617,15 @@
 	return 0;
 }
 
-/*
- * Simplify "set_ne/eq $0 + br"
- */
-static int simplify_cond_branch(struct instruction *br, pseudo_t cond, struct instruction *def, pseudo_t *pp)
+///
+// simplify SET_NE/EQ $0 + BR
+static int simplify_cond_branch(struct instruction *br, struct instruction *def, pseudo_t newcond)
 {
-	use_pseudo(br, *pp, &br->cond);
-	remove_usage(cond, &br->cond);
+	replace_pseudo(br, &br->cond, newcond);
 	if (def->opcode == OP_SET_EQ) {
-		struct basic_block *true = br->bb_true;
-		struct basic_block *false = br->bb_false;
-		br->bb_false = true;
-		br->bb_true = false;
+		struct basic_block *tmp = br->bb_true;
+		br->bb_true = br->bb_false;
+		br->bb_false = tmp;
 	}
 	return REPEAT_CSE;
 }
@@ -1096,9 +1659,9 @@
 
 		if (def->opcode == OP_SET_NE || def->opcode == OP_SET_EQ) {
 			if (constant(def->src1) && !def->src1->value)
-				return simplify_cond_branch(insn, cond, def, &def->src2);
+				return simplify_cond_branch(insn, def, def->src2);
 			if (constant(def->src2) && !def->src2->value)
-				return simplify_cond_branch(insn, cond, def, &def->src1);
+				return simplify_cond_branch(insn, def, def->src1);
 		}
 		if (def->opcode == OP_SEL) {
 			if (constant(def->src2) && constant(def->src3)) {
@@ -1113,24 +1676,15 @@
 					return REPEAT_CSE;
 				}
 				if (val2) {
-					struct basic_block *true = insn->bb_true;
-					struct basic_block *false = insn->bb_false;
-					insn->bb_false = true;
-					insn->bb_true = false;
+					struct basic_block *tmp = insn->bb_true;
+					insn->bb_true = insn->bb_false;
+					insn->bb_false = tmp;
 				}
-				use_pseudo(insn, def->src1, &insn->cond);
-				remove_usage(cond, &insn->cond);
-				return REPEAT_CSE;
+				return replace_pseudo(insn, &insn->cond, def->src1);
 			}
 		}
-		if (def->opcode == OP_CAST || def->opcode == OP_SCAST) {
-			int orig_size = def->orig_type ? def->orig_type->bit_size : 0;
-			if (def->size > orig_size) {
-				use_pseudo(insn, def->src, &insn->cond);
-				remove_usage(cond, &insn->cond);
-				return REPEAT_CSE;
-			}
-		}
+		if (def->opcode == OP_SEXT || def->opcode == OP_ZEXT)
+			return replace_pseudo(insn, &insn->cond, def->src);
 	}
 	return 0;
 }
@@ -1165,45 +1719,64 @@
 	if (!insn->bb)
 		return 0;
 	switch (insn->opcode) {
-	case OP_ADD: case OP_MULS:
+	case OP_ADD: case OP_MUL:
 	case OP_AND: case OP_OR: case OP_XOR:
-	case OP_AND_BOOL: case OP_OR_BOOL:
+		canonicalize_commutative(insn);
 		if (simplify_binop(insn))
 			return REPEAT_CSE;
-		if (simplify_commutative_binop(insn))
-			return REPEAT_CSE;
 		return simplify_associative_binop(insn);
 
-	case OP_MULU:
 	case OP_SET_EQ: case OP_SET_NE:
-		if (simplify_binop(insn))
-			return REPEAT_CSE;
-		return simplify_commutative_binop(insn);
+		canonicalize_commutative(insn);
+		return simplify_binop(insn);
 
+	case OP_SET_LE: case OP_SET_GE:
+	case OP_SET_LT: case OP_SET_GT:
+	case OP_SET_B:  case OP_SET_A:
+	case OP_SET_BE: case OP_SET_AE:
+		canonicalize_compare(insn);
+		/* fall through */
 	case OP_SUB:
 	case OP_DIVU: case OP_DIVS:
 	case OP_MODU: case OP_MODS:
 	case OP_SHL:
 	case OP_LSR: case OP_ASR:
-	case OP_SET_LE: case OP_SET_GE:
-	case OP_SET_LT: case OP_SET_GT:
-	case OP_SET_B:  case OP_SET_A:
-	case OP_SET_BE: case OP_SET_AE:
 		return simplify_binop(insn);
 
-	case OP_NOT: case OP_NEG:
+	case OP_NOT: case OP_NEG: case OP_FNEG:
 		return simplify_unop(insn);
-	case OP_LOAD: case OP_STORE:
+	case OP_LOAD:
+		if (!has_users(insn->target))
+			return kill_instruction(insn);
+		/* fall-through */
+	case OP_STORE:
 		return simplify_memop(insn);
 	case OP_SYMADDR:
-		if (dead_insn(insn, NULL, NULL, NULL))
+		if (dead_insn(insn, &insn->src, NULL, NULL))
 			return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP;
-		return replace_with_pseudo(insn, insn->symbol);
-	case OP_CAST:
-	case OP_SCAST:
-	case OP_FPCAST:
-	case OP_PTRCAST:
+		return replace_with_pseudo(insn, insn->src);
+	case OP_SEXT: case OP_ZEXT:
+	case OP_TRUNC:
 		return simplify_cast(insn);
+	case OP_FCVTU: case OP_FCVTS:
+	case OP_UCVTF: case OP_SCVTF:
+	case OP_FCVTF:
+	case OP_PTRCAST:
+		if (dead_insn(insn, &insn->src, NULL, NULL))
+			return REPEAT_CSE;
+		break;
+	case OP_UTPTR:
+	case OP_PTRTU:
+		return replace_with_pseudo(insn, insn->src);
+	case OP_SLICE:
+		if (dead_insn(insn, &insn->src, NULL, NULL))
+			return REPEAT_CSE;
+		break;
+	case OP_SETVAL:
+	case OP_SETFVAL:
+		if (dead_insn(insn, NULL, NULL, NULL))
+			return REPEAT_CSE;
+		break;
 	case OP_PHI:
 		if (dead_insn(insn, NULL, NULL, NULL)) {
 			kill_use_list(insn->phi_list);
@@ -1222,6 +1795,13 @@
 		return simplify_switch(insn);
 	case OP_RANGE:
 		return simplify_range(insn);
+	case OP_FADD:
+	case OP_FSUB:
+	case OP_FMUL:
+	case OP_FDIV:
+		if (dead_insn(insn, &insn->src1, &insn->src2, NULL))
+			return REPEAT_CSE;
+		break;
 	}
 	return 0;
 }
--- old/usr/src/tools/smatch/src/smatch.h	Mon Nov 18 13:19:06 2019
+++ new/usr/src/tools/smatch/src/smatch.h	Mon Nov 18 13:19:06 2019
@@ -107,6 +107,7 @@
 
 enum hook_type {
 	EXPR_HOOK,
+	EXPR_HOOK_AFTER,
 	STMT_HOOK,
 	STMT_HOOK_AFTER,
 	SYM_HOOK,
@@ -156,7 +157,7 @@
 typedef struct smatch_state *(unmatched_func_t)(struct sm_state *state);
 void add_merge_hook(int client_id, merge_func_t *func);
 void add_unmatched_state_hook(int client_id, unmatched_func_t *func);
-void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *sm));
+void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *cur, struct sm_state *other));
 typedef void (scope_hook)(void *data);
 void add_scope_hook(scope_hook *hook, void *data);
 typedef void (func_hook)(const char *fn, struct expression *expr, void *data);
@@ -205,6 +206,7 @@
 extern struct symbol *cur_func_sym;
 extern int option_debug;
 extern int local_debug;
+bool debug_implied(void);
 extern int option_info;
 extern int option_spammy;
 extern int option_timeout;
@@ -367,6 +369,7 @@
 /* smatch_helper.c */
 DECLARE_PTR_LIST(int_stack, int);
 char *alloc_string(const char *str);
+char *alloc_string_newline(const char *str);
 void free_string(char *str);
 void append(char *dest, const char *data, int buff_len);
 void remove_parens(char *str);
@@ -401,9 +404,10 @@
 int get_absolute_max(struct expression *expr, sval_t *sval);
 int parse_call_math(struct expression *expr, char *math, sval_t *val);
 int parse_call_math_rl(struct expression *call, const char *math, struct range_list **rl);
+const char *get_allocation_math(struct expression *expr);
 char *get_value_in_terms_of_parameter_math(struct expression *expr);
 char *get_value_in_terms_of_parameter_math_var_sym(const char *var, struct symbol *sym);
-int is_zero(struct expression *expr);
+int expr_is_zero(struct expression *expr);
 int known_condition_true(struct expression *expr);
 int known_condition_false(struct expression *expr);
 int implied_condition_true(struct expression *expr);
@@ -410,6 +414,8 @@
 int implied_condition_false(struct expression *expr);
 int can_integer_overflow(struct symbol *type, struct expression *expr);
 void clear_math_cache(void);
+void set_fast_math_only(void);
+void clear_fast_math_only(void);
 
 int is_array(struct expression *expr);
 struct expression *get_array_base(struct expression *expr);
@@ -421,7 +427,7 @@
 struct expression *strip_expr_set_parent(struct expression *expr);
 void scoped_state(int my_id, const char *name, struct symbol *sym);
 int is_error_return(struct expression *expr);
-int getting_address(void);
+int getting_address(struct expression *expr);
 int get_struct_and_member(struct expression *expr, const char **type, const char **member);
 char *get_member_name(struct expression *expr);
 char *get_fnptr_name(struct expression *expr);
@@ -462,7 +468,7 @@
 int is_char_pointer(struct expression *expr);
 int is_string(struct expression *expr);
 int is_static(struct expression *expr);
-int is_local_variable(struct expression *expr);
+bool is_local_variable(struct expression *expr);
 int types_equiv(struct symbol *one, struct symbol *two);
 int fn_static(void);
 const char *global_static();
@@ -524,6 +530,7 @@
 void __split_label_stmt(struct statement *stmt);
 void __split_stmt(struct statement *stmt);
 extern int __in_function_def;
+extern int __in_unmatched_hook;
 extern int option_assume_loops;
 extern int option_two_passes;
 extern int option_no_db;
@@ -673,11 +680,6 @@
 int get_absolute_min_helper(struct expression *expr, sval_t *sval);
 int get_absolute_max_helper(struct expression *expr, sval_t *sval);
 
-/* smatch_local_values.c */
-int get_local_rl(struct expression *expr, struct range_list **rl);
-int get_local_max_helper(struct expression *expr, sval_t *sval);
-int get_local_min_helper(struct expression *expr, sval_t *sval);
-
 /* smatch_type_value.c */
 int get_db_type_rl(struct expression *expr, struct range_list **rl);
 /* smatch_data_val.c */
@@ -686,7 +688,7 @@
 int get_array_rl(struct expression *expr, struct range_list **rl);
 
 /* smatch_states.c */
-void __swap_cur_stree(struct stree *stree);
+struct stree *__swap_cur_stree(struct stree *stree);
 void __push_fake_cur_stree();
 struct stree *__pop_fake_cur_stree();
 void __free_fake_cur_stree();
@@ -695,6 +697,8 @@
 void __merge_stree_into_cur(struct stree *stree);
 
 int unreachable(void);
+void __set_cur_stree_readonly(void);
+void __set_cur_stree_writable(void);
 void __set_sm(struct sm_state *sm);
 void __set_sm_cur_stree(struct sm_state *sm);
 void __set_sm_fake_stree(struct sm_state *sm);
@@ -768,7 +772,6 @@
 
 /* smatch_hooks.c */
 void __pass_to_client(void *data, enum hook_type type);
-void __pass_to_client_no_data(enum hook_type type);
 void __pass_case_to_client(struct expression *switch_expr,
 			   struct range_list *rl);
 int __has_merge_function(int client_id);
@@ -776,7 +779,7 @@
 					     struct smatch_state *s1,
 					     struct smatch_state *s2);
 struct smatch_state *__client_unmatched_state_function(struct sm_state *sm);
-void call_pre_merge_hook(struct sm_state *sm);
+void call_pre_merge_hook(struct sm_state *cur, struct sm_state *other);
 void __push_scope_hooks(void);
 void __call_scope_hooks(void);
 
@@ -874,6 +877,7 @@
 void select_return_implies_hook(int type, void (*callback)(struct expression *call, struct expression *arg, char *key, char *value));
 struct range_list *db_return_vals(struct expression *expr);
 struct range_list *db_return_vals_from_str(const char *fn_name);
+struct range_list *db_return_vals_no_args(struct expression *expr);
 char *return_state_to_var_sym(struct expression *expr, int param, const char *key, struct symbol **sym);
 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl);
 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym);
@@ -1058,6 +1062,8 @@
 char *map_call_to_param_name_sym(struct expression *expr, struct symbol **sym);
 
 /* smatch_comparison.c */
+#define UNKNOWN_COMPARISON 0
+#define IMPOSSIBLE_COMPARISON -1
 struct compare_data {
 	/* The ->left and ->right expression pointers might be NULL (I'm lazy) */
 	struct expression *left;
@@ -1075,7 +1081,7 @@
 		int comparison,
 		struct expression *right,
 		const char *right_var, struct var_sym_list *right_vsl);
-int filter_comparison(int orig, int op);
+int comparison_intersection(int orig, int op);
 int merge_comparisons(int one, int two);
 int combine_comparisons(int left_compare, int right_compare);
 int state_to_comparison(struct smatch_state *state);
@@ -1173,6 +1179,7 @@
 /* smatch_param_set.c */
 int param_was_set(struct expression *expr);
 int param_was_set_var_sym(const char *name, struct symbol *sym);
+void print_limited_param_set(int return_id, char *return_ranges, struct expression *expr);
 /* smatch_param_filter.c */
 int param_has_filter_data(struct sm_state *sm);
 
@@ -1181,9 +1188,6 @@
 struct smatch_state *merge_link_states(struct smatch_state *s1, struct smatch_state *s2);
 void store_link(int link_id, const char *name, struct symbol *sym, const char *link_name, struct symbol *link_sym);
 
-/* smatch_auto_copy.c */
-void set_auto_copy(int owner);
-
 /* check_buf_comparison */
 const char *limit_type_str(unsigned int limit_type);
 struct expression *get_size_variable(struct expression *buf, int *limit_type);
@@ -1235,7 +1239,7 @@
 int get_toplevel_mtag(struct symbol *sym, mtag_t *tag);
 int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new);
 int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset);
-void update_mtag_data(struct expression *expr);
+void update_mtag_data(struct expression *expr, struct smatch_state *state);
 int get_mtag_sval(struct expression *expr, sval_t *sval);
 
 /* Trinity fuzzer stuff */
@@ -1242,6 +1246,7 @@
 const char *get_syscall_arg_type(struct symbol *sym);
 
 /* smatch_bit_info.c */
+struct bit_info *rl_to_binfo(struct range_list *rl);
 struct bit_info *get_bit_info(struct expression *expr);
 struct bit_info *get_bit_info_var_sym(const char *name, struct symbol *sym);
 /* smatch_mem_tracker.c */
@@ -1254,6 +1259,7 @@
 long get_stmt_cnt(void);
 
 /* smatch_nul_terminator.c */
+bool is_nul_terminated_var_sym(const char *name, struct symbol *sym);
 bool is_nul_terminated(struct expression *expr);
 /* check_kernel.c  */
 bool is_ignored_kernel_data(const char *name);
--- old/usr/src/tools/smatch/src/smatch_array_values.c	Mon Nov 18 13:19:07 2019
+++ new/usr/src/tools/smatch/src/smatch_array_values.c	Mon Nov 18 13:19:07 2019
@@ -188,6 +188,25 @@
 	update_cache(name, is_file_local(array), rl);
 }
 
+static void mark_strings_unknown(const char *fn, struct expression *expr, void *_arg)
+{
+	struct expression *dest;
+	struct symbol *type;
+	int arg = PTR_INT(_arg);
+	char *name;
+
+	dest = get_argument_from_call_expr(expr->args, arg);
+	if (!dest)
+		return;
+	name = get_array_name(dest);
+	if (!name)
+		return;
+	type = get_type(dest);
+	if (type_is_ptr(type))
+		type = get_real_base_type(type);
+	update_cache(name, is_file_local(dest), alloc_whole_rl(type));
+}
+
 void register_array_values(int id)
 {
 	my_id = id;
@@ -194,4 +213,12 @@
 
 	add_hook(&match_assign, ASSIGNMENT_HOOK);
 	add_hook(&match_assign, GLOBAL_ASSIGNMENT_HOOK);
+
+	add_function_hook("sprintf", &mark_strings_unknown, INT_PTR(0));
+	add_function_hook("snprintf", &mark_strings_unknown, INT_PTR(0));
+
+	add_function_hook("strcpy", &mark_strings_unknown, INT_PTR(0));
+	add_function_hook("strncpy", &mark_strings_unknown, INT_PTR(0));
+	add_function_hook("strlcpy", &mark_strings_unknown, INT_PTR(0));
+	add_function_hook("strscpy", &mark_strings_unknown, INT_PTR(0));
 }
--- old/usr/src/tools/smatch/src/smatch_assigned_expr.c	Mon Nov 18 13:19:07 2019
+++ new/usr/src/tools/smatch/src/smatch_assigned_expr.c	Mon Nov 18 13:19:07 2019
@@ -51,7 +51,7 @@
 {
 	struct smatch_state *state;
 
-	state = get_state(my_id, name, sym);
+	state = __get_state(my_id, name, sym);
 	if (!state)
 		return NULL;
 	return (struct expression *)state->data;
--- old/usr/src/tools/smatch/src/smatch_auto_copy.c	Mon Nov 18 13:19:07 2019
+++ /dev/null	Mon Nov 18 13:19:08 2019
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2014 Oracle.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
- */
-
-#include "smatch.h"
-#include "smatch_slist.h"
-
-static int my_id;
-
-static int *auto_copy;
-
-void set_auto_copy(int owner)
-{
-	if (owner <= 1 || owner > num_checks) {
-		sm_ierror("bogus set_auto_copy()");
-		return;
-	}
-	auto_copy[owner] = 1;
-}
-
-static void match_assign(struct expression *expr)
-{
-	char *left_name = NULL;
-	char *right_name = NULL;
-	struct symbol *left_sym, *right_sym;
-	struct state_list *slist = NULL;
-	struct sm_state *sm;
-
-	left_name = expr_to_var_sym(expr->left, &left_sym);
-	if (!left_name || !left_sym)
-		goto free;
-	right_name = expr_to_var_sym(expr->right, &right_sym);
-	if (!right_name || !right_sym)
-		goto free;
-
-	FOR_EACH_SM(__get_cur_stree(), sm) {
-		if (sm->owner <= 1 || sm->owner > num_checks)
-			continue;
-		if (!auto_copy[sm->owner])
-			continue;
-		if (right_sym != sm->sym)
-			continue;
-		if (strcmp(right_name, sm->name) != 0)
-			continue;
-		add_ptr_list(&slist, sm);
-	} END_FOR_EACH_SM(sm);
-
-
-	FOR_EACH_PTR(slist, sm) {
-		set_state(sm->owner, left_name, left_sym, sm->state);
-	} END_FOR_EACH_PTR(sm);
-
-free:
-	free_slist(&slist);
-	free_string(left_name);
-	free_string(right_name);
-}
-
-void register_auto_copy(int id)
-{
-	my_id = id;
-	auto_copy = malloc((num_checks + 1) * sizeof(*auto_copy));
-	memset(auto_copy, 0, (num_checks + 1) * sizeof(*auto_copy));
-
-	add_hook(&match_assign, ASSIGNMENT_HOOK);
-}
--- old/usr/src/tools/smatch/src/smatch_bits.c	Mon Nov 18 13:19:08 2019
+++ new/usr/src/tools/smatch/src/smatch_bits.c	Mon Nov 18 13:19:08 2019
@@ -54,7 +54,7 @@
 	return state;
 }
 
-static struct bit_info *rl_to_binfo(struct range_list *rl)
+struct bit_info *rl_to_binfo(struct range_list *rl)
 {
 	struct bit_info *ret = __alloc_bit_info(0);
 	sval_t sval;
--- old/usr/src/tools/smatch/src/smatch_buf_size.c	Mon Nov 18 13:19:08 2019
+++ new/usr/src/tools/smatch/src/smatch_buf_size.c	Mon Nov 18 13:19:08 2019
@@ -23,7 +23,7 @@
 #include "smatch_extra.h"
 #include "smatch_function_hashtable.h"
 
-#define UNKNOWN_SIZE (-1)
+#define UNKNOWN_SIZE -1
 
 static int my_size_id;
 
@@ -274,8 +274,7 @@
 		return;
 	call = strip_expr(expr->right);
 
-	if (!parse_call_math_rl(call, math, &rl))
-		return;
+	call_results_to_rl(call, &int_ctype, math, &rl);
 	rl = cast_rl(&int_ctype, rl);
 	set_state_expr(my_size_id, expr->left, alloc_estate_rl(rl));
 }
@@ -471,6 +470,7 @@
 struct range_list *get_array_size_bytes_rl(struct expression *expr)
 {
 	struct range_list *ret = NULL;
+	sval_t sval;
 	int size;
 
 	expr = remove_addr_fluff(expr);
@@ -528,6 +528,8 @@
 		return alloc_int_rl(size);
 
 	ret = size_from_db(expr);
+	if (rl_to_sval(ret, &sval) && sval.value == -1)
+		return NULL;
 	if (ret)
 		return ret;
 
@@ -632,6 +634,8 @@
 	struct symbol *type;
 
 	rl = clone_rl(rl); // FIXME!!!
+	if (!rl)
+		rl = size_to_rl(UNKNOWN_SIZE);
 	set_state_expr(my_size_id, expr, alloc_estate_rl(rl));
 
 	type = get_type(expr);
@@ -719,7 +723,7 @@
 	if (get_implied_rl(mult, &rl))
 		store_alloc(expr->left, rl);
 	else
-		store_alloc(expr->left, size_to_rl(-1));
+		store_alloc(expr->left, size_to_rl(UNKNOWN_SIZE));
 }
 
 static void match_page(const char *fn, struct expression *expr, void *_unused)
@@ -744,7 +748,7 @@
 		size.value++;
 		store_alloc(expr->left, size_to_rl(size.value));
 	} else {
-		store_alloc(expr->left, size_to_rl(-1));
+		store_alloc(expr->left, size_to_rl(UNKNOWN_SIZE));
 	}
 
 }
@@ -818,11 +822,13 @@
 
 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
 {
-	if (sm->state == &merged ||
-	    strcmp(sm->state->name, "(-1)") == 0 ||
-	    strcmp(sm->state->name, "empty") == 0 ||
-	    strcmp(sm->state->name, "0") == 0)
+	sval_t sval;
+
+	if (!estate_rl(sm->state) ||
+	    (estate_get_single_value(sm->state, &sval) &&
+	     (sval.value == -1 || sval.value == 0)))
 		return;
+
 	sql_insert_caller_info(call, BUF_SIZE, param, printed_name, sm->state->name);
 }
 
@@ -834,14 +840,28 @@
  */
 static void print_returned_allocations(int return_id, char *return_ranges, struct expression *expr)
 {
-	char buf[16];
-	int size;
+	const char *param_math;
+	struct range_list *rl;
+	char buf[64];
+	sval_t sval;
 
-	size = get_array_size_bytes(expr);
-	if (!size)
+	rl = get_array_size_bytes_rl(expr);
+	param_math = get_allocation_math(expr);
+	if (!rl && !param_math)
 		return;
 
-	snprintf(buf, sizeof(buf), "%d", size);
+	if (!param_math &&
+	    rl_to_sval(rl, &sval) &&
+	    (sval.value == -1 || sval.value == 0))
+		return;
+
+	if (param_math)
+		snprintf(buf, sizeof(buf), "%s[%s]", show_rl(rl), param_math);
+	else
+		snprintf(buf, sizeof(buf), "%s", show_rl(rl));
+
+	// FIXME: don't store if you can guess the size from the type
+	// FIXME: return if we allocate a parameter $0->bar
 	sql_insert_return_states(return_id, return_ranges, BUF_SIZE, -1, "", buf);
 }
 
@@ -872,6 +892,7 @@
 	set_dynamic_states(my_size_id);
 
 	add_unmatched_state_hook(my_size_id, &unmatched_size_state);
+	add_merge_hook(my_size_id, &merge_estates);
 
 	select_caller_info_hook(set_param_buf_size, BUF_SIZE);
 	select_return_states_hook(BUF_SIZE, &db_returns_buf_size);
@@ -905,13 +926,14 @@
 		add_allocation_function("__alloc_bootmem", &match_alloc, 0);
 		add_allocation_function("alloc_bootmem", &match_alloc, 0);
 		add_allocation_function("kmap", &match_page, 0);
+		add_allocation_function("kmap_atomic", &match_page, 0);
 		add_allocation_function("get_zeroed_page", &match_page, 0);
 		add_allocation_function("alloc_page", &match_page, 0);
-		add_allocation_function("page_address", &match_page, 0);
-		add_allocation_function("lowmem_page_address", &match_page, 0);
 		add_allocation_function("alloc_pages", &match_alloc_pages, 1);
 		add_allocation_function("alloc_pages_current", &match_alloc_pages, 1);
 		add_allocation_function("__get_free_pages", &match_alloc_pages, 1);
+		add_allocation_function("dma_alloc_contiguous", &match_alloc, 1);
+		add_allocation_function("dma_alloc_coherent", &match_alloc, 1);
 	}
 
 	add_allocation_function("strndup", match_strndup, 0);
--- old/usr/src/tools/smatch/src/smatch_common_functions.c	Mon Nov 18 13:19:08 2019
+++ new/usr/src/tools/smatch/src/smatch_common_functions.c	Mon Nov 18 13:19:08 2019
@@ -69,16 +69,15 @@
 static int match_sprintf(struct expression *call, void *_arg, struct range_list **rl)
 {
 	int str_arg = PTR_INT(_arg);
-	int size;
+	int min, max;
 
-	size = get_formatted_string_size(call, str_arg);
-	if (size <= 0) {
+	min = get_formatted_string_min_size(call, str_arg);
+	max = get_formatted_string_size(call, str_arg);
+	if (min < 0 || max < 0) {
 		*rl = alloc_whole_rl(&ulong_ctype);
 	} else {
-		/* FIXME:  This is bogus.  get_formatted_string_size() should be
-		   returning a range_list.  Also it should not add the NUL. */
-		size--;
-		*rl = alloc_rl(ll_to_sval(0), ll_to_sval(size));
+		*rl = alloc_rl(ll_to_sval(min), ll_to_sval(max));
+		*rl = cast_rl(get_type(call), *rl);
 	}
 	return 1;
 }
--- old/usr/src/tools/smatch/src/smatch_comparison.c	Mon Nov 18 13:19:09 2019
+++ new/usr/src/tools/smatch/src/smatch_comparison.c	Mon Nov 18 13:19:09 2019
@@ -57,6 +57,15 @@
 	return vs->sym;
 }
 
+static const char *show_comparison(int comparison)
+{
+	if (comparison == IMPOSSIBLE_COMPARISON)
+		return "impossible";
+	if (comparison == UNKNOWN_COMPARISON)
+		return "unknown";
+	return show_special(comparison);
+}
+
 struct smatch_state *alloc_compare_state(
 		struct expression *left,
 		const char *left_var, struct var_sym_list *left_vsl,
@@ -68,7 +77,7 @@
 	struct compare_data *data;
 
 	state = __alloc_smatch_state(0);
-	state->name = alloc_sname(show_special(comparison));
+	state->name = alloc_sname(show_comparison(comparison));
 	data = __alloc_compare_data(0);
 	data->left = left;
 	data->left_var = alloc_sname(left_var);
@@ -84,7 +93,7 @@
 int state_to_comparison(struct smatch_state *state)
 {
 	if (!state || !state->data)
-		return 0;
+		return UNKNOWN_COMPARISON;
 	return ((struct compare_data *)state->data)->comparison;
 }
 
@@ -94,8 +103,8 @@
 int flip_comparison(int op)
 {
 	switch (op) {
-	case 0:
-		return 0;
+	case UNKNOWN_COMPARISON:
+		return UNKNOWN_COMPARISON;
 	case '<':
 		return '>';
 	case SPECIAL_UNSIGNED_LT:
@@ -116,6 +125,8 @@
 		return '<';
 	case SPECIAL_UNSIGNED_GT:
 		return SPECIAL_UNSIGNED_LT;
+	case IMPOSSIBLE_COMPARISON:
+		return UNKNOWN_COMPARISON;
 	default:
 		sm_perror("unhandled comparison %d", op);
 		return op;
@@ -125,8 +136,8 @@
 int negate_comparison(int op)
 {
 	switch (op) {
-	case 0:
-		return 0;
+	case UNKNOWN_COMPARISON:
+		return UNKNOWN_COMPARISON;
 	case '<':
 		return SPECIAL_GTE;
 	case SPECIAL_UNSIGNED_LT:
@@ -147,6 +158,8 @@
 		return SPECIAL_LTE;
 	case SPECIAL_UNSIGNED_GT:
 		return SPECIAL_UNSIGNED_LTE;
+	case IMPOSSIBLE_COMPARISON:
+		return UNKNOWN_COMPARISON;
 	default:
 		sm_perror("unhandled comparison %d", op);
 		return op;
@@ -159,7 +172,7 @@
 	struct symbol *type = &int_ctype;
 
 	if (!left_rl || !right_rl)
-		return 0;
+		return UNKNOWN_COMPARISON;
 
 	if (type_positive_bits(rl_type(left_rl)) > type_positive_bits(type))
 		type = rl_type(left_rl);
@@ -188,7 +201,7 @@
 	if (sval_cmp(left_min, right_max) == 0)
 		return SPECIAL_GTE;
 
-	return 0;
+	return UNKNOWN_COMPARISON;
 }
 
 static int comparison_from_extra(struct expression *a, struct expression *b)
@@ -196,9 +209,9 @@
 	struct range_list *left, *right;
 
 	if (!get_implied_rl(a, &left))
-		return 0;
+		return UNKNOWN_COMPARISON;
 	if (!get_implied_rl(b, &right))
-		return 0;
+		return UNKNOWN_COMPARISON;
 
 	return rl_comparison(left, right);
 }
@@ -221,29 +234,32 @@
 {
 	struct compare_data *data = sm->state->data;
 	struct range_list *left_rl, *right_rl;
-	int op;
+	int op = UNKNOWN_COMPARISON;
 
 	if (!data)
 		return &undefined;
 
+	if (is_impossible_path()) {
+		op = IMPOSSIBLE_COMPARISON;
+		goto alloc;
+	}
+
 	if (strstr(data->left_var, " orig"))
 		left_rl = get_orig_rl(data->left_vsl);
 	else if (!get_implied_rl_var_sym(data->left_var, vsl_to_sym(data->left_vsl), &left_rl))
-		return &undefined;
+		goto alloc;
 
 	if (strstr(data->right_var, " orig"))
 		right_rl = get_orig_rl(data->right_vsl);
 	else if (!get_implied_rl_var_sym(data->right_var, vsl_to_sym(data->right_vsl), &right_rl))
-		return &undefined;
+		goto alloc;
 
 	op = rl_comparison(left_rl, right_rl);
-	if (op)
-		return alloc_compare_state(
-				data->left, data->left_var, data->left_vsl,
-				op,
-				data->right, data->right_var, data->right_vsl);
 
-	return &undefined;
+alloc:
+	return alloc_compare_state(data->left, data->left_var, data->left_vsl,
+				   op,
+				   data->right, data->right_var, data->right_vsl);
 }
 
 /* remove_unsigned_from_comparison() is obviously a hack. */
@@ -271,9 +287,14 @@
 {
 	int LT, EQ, GT;
 
-	if (!one || !two)
-		return 0;
+	if (one == UNKNOWN_COMPARISON || two == UNKNOWN_COMPARISON)
+		return UNKNOWN_COMPARISON;
 
+	if (one == IMPOSSIBLE_COMPARISON)
+		return two;
+	if (two == IMPOSSIBLE_COMPARISON)
+		return one;
+
 	one = remove_unsigned_from_comparison(one);
 	two = remove_unsigned_from_comparison(two);
 
@@ -321,7 +342,7 @@
 	}
 
 	if (LT && EQ && GT)
-		return 0;
+		return UNKNOWN_COMPARISON;
 	if (LT && EQ)
 		return SPECIAL_LTE;
 	if (LT && GT)
@@ -332,17 +353,13 @@
 		return SPECIAL_GTE;
 	if (GT)
 		return '>';
-	return 0;
+	return UNKNOWN_COMPARISON;
 }
 
 /*
- * This is for if you have "a < b" and "b <= c".  Or in other words,
- * "a < b <= c".  You would call this like get_combined_comparison('<', '<=').
+ * This is for if you have "a < b" and "b <= c" and you want to see how "a
+ * compares to c".  You would call this like get_combined_comparison('<', '<=').
  * The return comparison would be '<'.
- *
- * This function is different from merge_comparisons(), for example:
- * merge_comparison('<', '==') returns '<='
- * get_combined_comparison('<', '==') returns '<'
  */
 int combine_comparisons(int left_compare, int right_compare)
 {
@@ -400,144 +417,148 @@
 			return SPECIAL_GTE;
 		return '>';
 	}
-	return 0;
+	return UNKNOWN_COMPARISON;
 }
 
-int filter_comparison(int orig, int op)
+/*
+ * This is mostly used when you know from extra state that a <= b but you
+ * know from comparisons that a != b so then if take the intersection then
+ * we know that a < b.  The name is taken from the fact that the intersection
+ * of < and <= is <.
+ */
+int comparison_intersection(int left_compare, int right_compare)
 {
-	if (orig == op)
-		return orig;
+	int LT, GT, EQ, NE, total;
 
-	orig = remove_unsigned_from_comparison(orig);
-	op = remove_unsigned_from_comparison(op);
+	if (left_compare == IMPOSSIBLE_COMPARISON ||
+	    right_compare == IMPOSSIBLE_COMPARISON)
+		return IMPOSSIBLE_COMPARISON;
 
-	switch (orig) {
-	case 0:
-		return op;
+	left_compare = remove_unsigned_from_comparison(left_compare);
+	right_compare = remove_unsigned_from_comparison(right_compare);
+
+	LT = GT = EQ = NE = total = 0;
+
+	/* Only one side is known. */
+	if (!left_compare)
+		return right_compare;
+	if (!right_compare)
+		return left_compare;
+
+	switch (left_compare) {
 	case '<':
-		switch (op) {
-		case '<':
-		case SPECIAL_LTE:
-		case SPECIAL_NOTEQUAL:
-			return '<';
-		}
-		return 0;
+		LT++;
+		total += 1;
+		break;
 	case SPECIAL_LTE:
-		switch (op) {
-		case '<':
-		case SPECIAL_LTE:
-		case SPECIAL_EQUAL:
-			return op;
-		case SPECIAL_NOTEQUAL:
-			return '<';
-		}
-		return 0;
+		LT++;
+		EQ++;
+		total += 2;
+		break;
 	case SPECIAL_EQUAL:
-		switch (op) {
-		case SPECIAL_LTE:
-		case SPECIAL_EQUAL:
-		case SPECIAL_GTE:
-		case SPECIAL_UNSIGNED_LTE:
-		case SPECIAL_UNSIGNED_GTE:
-			return SPECIAL_EQUAL;
-		}
-		return 0;
+		EQ++;
+		total += 1;
+		break;
 	case SPECIAL_NOTEQUAL:
-		switch (op) {
-		case '<':
-		case SPECIAL_LTE:
-			return '<';
-		case SPECIAL_UNSIGNED_LT:
-		case SPECIAL_UNSIGNED_LTE:
-			return SPECIAL_UNSIGNED_LT;
-		case SPECIAL_NOTEQUAL:
-			return op;
-		case '>':
-		case SPECIAL_GTE:
-			return '>';
-		case SPECIAL_UNSIGNED_GT:
-		case SPECIAL_UNSIGNED_GTE:
-			return SPECIAL_UNSIGNED_GT;
-		}
-		return 0;
+		NE++;
+		total += 1;
+		break;
 	case SPECIAL_GTE:
-		switch (op) {
-		case SPECIAL_LTE:
-			return SPECIAL_EQUAL;
-		case '>':
-		case SPECIAL_GTE:
-		case SPECIAL_EQUAL:
-			return op;
-		case SPECIAL_NOTEQUAL:
-			return '>';
-		}
-		return 0;
+		GT++;
+		EQ++;
+		total += 2;
+		break;
 	case '>':
-		switch (op) {
-		case '>':
-		case SPECIAL_GTE:
-		case SPECIAL_NOTEQUAL:
-			return '>';
-		}
-		return 0;
-	case SPECIAL_UNSIGNED_LT:
-		switch (op) {
-		case SPECIAL_UNSIGNED_LT:
-		case SPECIAL_UNSIGNED_LTE:
-		case SPECIAL_NOTEQUAL:
-			return SPECIAL_UNSIGNED_LT;
-		}
-		return 0;
-	case SPECIAL_UNSIGNED_LTE:
-		switch (op) {
-		case SPECIAL_UNSIGNED_LT:
-		case SPECIAL_UNSIGNED_LTE:
-		case SPECIAL_EQUAL:
-			return op;
-		case SPECIAL_NOTEQUAL:
-			return SPECIAL_UNSIGNED_LT;
-		case SPECIAL_UNSIGNED_GTE:
-			return SPECIAL_EQUAL;
-		}
-		return 0;
-	case SPECIAL_UNSIGNED_GTE:
-		switch (op) {
-		case SPECIAL_UNSIGNED_LTE:
-			return SPECIAL_EQUAL;
-		case SPECIAL_NOTEQUAL:
-			return SPECIAL_UNSIGNED_GT;
-		case SPECIAL_EQUAL:
-		case SPECIAL_UNSIGNED_GTE:
-		case SPECIAL_UNSIGNED_GT:
-			return op;
-		}
-		return 0;
-	case SPECIAL_UNSIGNED_GT:
-		switch (op) {
-		case SPECIAL_UNSIGNED_GT:
-		case SPECIAL_UNSIGNED_GTE:
-		case SPECIAL_NOTEQUAL:
-			return SPECIAL_UNSIGNED_GT;
-		}
-		return 0;
+		GT++;
+		total += 1;
+		break;
+	default:
+		return UNKNOWN_COMPARISON;
 	}
-	return 0;
+
+	switch (right_compare) {
+	case '<':
+		LT++;
+		total += 1;
+		break;
+	case SPECIAL_LTE:
+		LT++;
+		EQ++;
+		total += 2;
+		break;
+	case SPECIAL_EQUAL:
+		EQ++;
+		total += 1;
+		break;
+	case SPECIAL_NOTEQUAL:
+		NE++;
+		total += 1;
+		break;
+	case SPECIAL_GTE:
+		GT++;
+		EQ++;
+		total += 2;
+		break;
+	case '>':
+		GT++;
+		total += 1;
+		break;
+	default:
+		return UNKNOWN_COMPARISON;
+	}
+
+	if (LT == 2) {
+		if (EQ == 2)
+			return SPECIAL_LTE;
+		return '<';
+	}
+
+	if (GT == 2) {
+		if (EQ == 2)
+			return SPECIAL_GTE;
+		return '>';
+	}
+	if (EQ == 2)
+		return SPECIAL_EQUAL;
+	if (total == 2 && EQ && NE)
+		return IMPOSSIBLE_COMPARISON;
+	if (GT && LT)
+		return IMPOSSIBLE_COMPARISON;
+	if (GT && NE)
+		return '>';
+	if (LT && NE)
+		return '<';
+	if (NE == 2)
+		return SPECIAL_NOTEQUAL;
+	if (total == 2 && (LT || GT) && EQ)
+		return IMPOSSIBLE_COMPARISON;
+
+	return UNKNOWN_COMPARISON;
 }
 
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
-	struct compare_data *data = sm->state->data;
-	int other;
+	struct compare_data *data = cur->state->data;
+	int extra, new;
+	static bool in_recurse;
 
 	if (!data)
 		return;
-	other = get_comparison(data->left, data->right);
-	if (!other)
+
+	if (in_recurse)
 		return;
+	in_recurse = true;
+	extra = comparison_from_extra(data->left, data->right);
+	in_recurse = false;
+	if (!extra)
+		return;
+	new = comparison_intersection(extra, data->comparison);
+	if (new == data->comparison)
+		return;
 
-	set_state(compare_id, sm->name, NULL,
+	set_state(compare_id, cur->name, NULL,
 		  alloc_compare_state(data->left, data->left_var, data->left_vsl,
-				      other,
+				      new,
 				      data->right, data->right_var, data->right_vsl));
 }
 
@@ -546,13 +567,14 @@
 	struct compare_data *data = s1->data;
 	int op;
 
+	if (!data)
+		return &undefined;
+
 	op = merge_comparisons(state_to_comparison(s1), state_to_comparison(s2));
-	if (op)
-		return alloc_compare_state(
-				data->left, data->left_var, data->left_vsl,
-				op,
-				data->right, data->right_var, data->right_vsl);
-	return &undefined;
+	return alloc_compare_state(
+			data->left, data->left_var, data->left_vsl,
+			op,
+			data->right, data->right_var, data->right_vsl);
 }
 
 static struct smatch_state *alloc_link_state(struct string_list *links)
@@ -690,7 +712,11 @@
 			set_state(compare_id, tmp, NULL, new);
 			break;
 		default:
-			set_state(compare_id, tmp, NULL, &undefined);
+			new = alloc_compare_state(
+					data->left, data->left_var, data->left_vsl,
+					UNKNOWN_COMPARISON,
+					data->right, data->right_var, data->right_vsl);
+			set_state(compare_id, tmp, NULL, new);
 		}
 	} END_FOR_EACH_PTR(tmp);
 }
@@ -704,8 +730,15 @@
 	links = sm->state->data;
 
 	FOR_EACH_PTR(links, tmp) {
+		struct compare_data *data;
+		struct smatch_state *new;
+
 		state = get_state(compare_id, tmp, NULL);
+		if (!state || !state->data)
+			continue;
 
+		data = state->data;
+
 		switch (state_to_comparison(state)) {
 		case SPECIAL_EQUAL:
 		case SPECIAL_LTE:
@@ -712,9 +745,6 @@
 		case SPECIAL_UNSIGNED_LTE:
 		case '<':
 		case SPECIAL_UNSIGNED_LT: {
-			struct compare_data *data = state->data;
-			struct smatch_state *new;
-
 			if (preserve)
 				break;
 
@@ -726,7 +756,11 @@
 			break;
 			}
 		default:
-			set_state(compare_id, tmp, NULL, &undefined);
+			new = alloc_compare_state(
+					data->left, data->left_var, data->left_vsl,
+					UNKNOWN_COMPARISON,
+					data->right, data->right_var, data->right_vsl);
+			set_state(compare_id, tmp, NULL, new);
 		}
 	} END_FOR_EACH_PTR(tmp);
 }
@@ -739,7 +773,20 @@
 	links = sm->state->data;
 
 	FOR_EACH_PTR(links, tmp) {
-		set_state(compare_id, tmp, NULL, &undefined);
+		struct smatch_state *old, *new;
+
+		old = get_state(compare_id, tmp, NULL);
+		if (!old || !old->data) {
+			new = &undefined;
+		} else {
+			struct compare_data *data = old->data;
+
+			new = alloc_compare_state(
+					data->left, data->left_var, data->left_vsl,
+					UNKNOWN_COMPARISON,
+					data->right, data->right_var, data->right_vsl);
+		}
+		set_state(compare_id, tmp, NULL, new);
 	} END_FOR_EACH_PTR(tmp);
 	set_state(link_id, sm->name, sm->sym, &undefined);
 }
@@ -849,7 +896,7 @@
 		return;
 
 	op = rl_comparison(left, right);
-	if (!op)
+	if (op == UNKNOWN_COMPARISON)
 		return;
 
 	add_comparison(expr->unop, op, parent->right);
@@ -1016,8 +1063,8 @@
 		true_comparison = combine_comparisons(left_comparison, right_comparison);
 		false_comparison = combine_comparisons(left_false_comparison, right_comparison);
 
-		true_comparison = filter_comparison(orig_comparison, true_comparison);
-		false_comparison = filter_comparison(orig_comparison, false_comparison);
+		true_comparison = comparison_intersection(orig_comparison, true_comparison);
+		false_comparison = comparison_intersection(orig_comparison, false_comparison);
 
 		if (strcmp(left_var, right_var) > 0) {
 		  	struct expression *tmp_expr = left_expr;
@@ -1276,8 +1323,8 @@
 	}
 
 	orig_comparison = get_comparison(left_expr, right_expr);
-	op = filter_comparison(orig_comparison, op);
-	false_op = filter_comparison(orig_comparison, false_op);
+	op = comparison_intersection(orig_comparison, op);
+	false_op = comparison_intersection(orig_comparison, false_op);
 
 	snprintf(state_name, sizeof(state_name), "%s vs %s", left, right);
 	true_state = alloc_compare_state(
@@ -1334,7 +1381,6 @@
 		handle_comparison(new_left, expr->op, new_right, NULL, NULL);
 	}
 
-
 	redo = 0;
 	left = strip_parens(expr->left);
 	right = strip_parens(expr->right);
@@ -1618,7 +1664,7 @@
 	int ret = 0;
 
 	if (!one || !two)
-		return 0;
+		return UNKNOWN_COMPARISON;
 
 	if (strcmp(one, two) == 0)
 		return SPECIAL_EQUAL;
@@ -1646,10 +1692,12 @@
 {
 	char *one = NULL;
 	char *two = NULL;
-	int ret = 0;
+	int ret = UNKNOWN_COMPARISON;
+	int extra = UNKNOWN_COMPARISON;
 
-	if (!a || !b)
-		return 0;
+	if (a == UNKNOWN_COMPARISON ||
+	    b == UNKNOWN_COMPARISON)
+		return UNKNOWN_COMPARISON;
 
 	a = strip_parens(a);
 	b = strip_parens(b);
@@ -1677,7 +1725,7 @@
 		ret = get_comparison_strings(one, two);
 	}
 
-	if (!ret)
+	if (ret == UNKNOWN_COMPARISON)
 		goto free;
 
 	if ((is_plus_one(a) || is_minus_one(b)) && ret == '<')
@@ -1685,15 +1733,14 @@
 	else if ((is_minus_one(a) || is_plus_one(b)) && ret == '>')
 		ret = SPECIAL_GTE;
 	else
-		ret = 0;
+		ret = UNKNOWN_COMPARISON;
 
 free:
 	free_string(one);
 	free_string(two);
 
-	if (!ret && use_extra)
-		return comparison_from_extra(a, b);
-	return ret;
+	extra = comparison_from_extra(a, b);
+	return comparison_intersection(ret, extra);
 }
 
 int get_comparison(struct expression *a, struct expression *b)
@@ -1905,11 +1952,11 @@
 {
 	struct expression *arg;
 	int comparison;
-	char buf[4];
+	char buf[16];
 
 	if (!str_to_comparison_arg(range, call, &comparison, &arg))
 		return;
-	snprintf(buf, sizeof(buf), "%s", show_special(comparison));
+	snprintf(buf, sizeof(buf), "%s", show_comparison(comparison));
 	update_links_from_call(call, comparison, arg);
 	add_comparison(call, comparison, arg);
 }
@@ -1971,11 +2018,12 @@
 			continue;
 		snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
 		compare = get_comparison_strings(var, buf);
-		if (!compare)
+		if (compare == UNKNOWN_COMPARISON ||
+		    compare == IMPOSSIBLE_COMPARISON)
 			continue;
-		if (show_special(compare)[0] != starts_with)
+		if (show_comparison(compare)[0] != starts_with)
 			continue;
-		snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
+		snprintf(buf, sizeof(buf), "[%s$%d]", show_comparison(compare), i);
 		ret_str = alloc_sname(buf);
 		break;
 	} END_FOR_EACH_PTR(param);
@@ -2006,9 +2054,10 @@
 			continue;
 		snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
 		compare = get_comparison_strings(name, buf);
-		if (!compare)
+		if (compare == UNKNOWN_COMPARISON ||
+		    compare == IMPOSSIBLE_COMPARISON)
 			continue;
-		snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
+		snprintf(buf, sizeof(buf), "[%s$%d]", show_comparison(compare), i);
 		return alloc_sname(buf);
 	} END_FOR_EACH_PTR(param);
 
@@ -2049,7 +2098,7 @@
 		compare = get_comparison_strings(var, buf);
 		if (!compare)
 			continue;
-		snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
+		snprintf(buf, sizeof(buf), "[%s$%d]", show_comparison(compare), i);
 		ret_str = alloc_sname(buf);
 		break;
 	} END_FOR_EACH_PTR(param);
@@ -2128,7 +2177,9 @@
 			if (!sm)
 				continue;
 			data = sm->state->data;
-			if (!data || !data->comparison)
+			if (!data ||
+			    data->comparison == UNKNOWN_COMPARISON ||
+			    data->comparison == IMPOSSIBLE_COMPARISON)
 				continue;
 			arg_name = expr_to_var(arg);
 			if (!arg_name)
@@ -2153,7 +2204,7 @@
 			right_name = get_printed_param_name(expr, right_vs->var, right_vs->sym);
 			if (!right_name)
 				goto free;
-			snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(comparison), right_name);
+			snprintf(info_buf, sizeof(info_buf), "%s %s", show_comparison(comparison), right_name);
 			sql_insert_caller_info(expr, PARAM_COMPARE, i, "$", info_buf);
 
 free:
@@ -2203,7 +2254,7 @@
 		right_name = get_printed_param_name(call, right->var, right->sym);
 		if (!right_name)
 			continue;
-		snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_name);
+		snprintf(info_buf, sizeof(info_buf), "%s %s", show_comparison(data->comparison), right_name);
 		sql_insert_caller_info(call, PARAM_COMPARE, param, printed_name, info_buf);
 	} END_FOR_EACH_PTR(link);
 }
@@ -2274,7 +2325,9 @@
 			if (!sm)
 				continue;
 			data = sm->state->data;
-			if (!data || !data->comparison)
+			if (!data ||
+			    data->comparison == UNKNOWN_COMPARISON ||
+			    data->comparison == IMPOSSIBLE_COMPARISON)
 				continue;
 			if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
 			    ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
@@ -2316,7 +2369,7 @@
 			 * smatch_param_compare_limit.c.
 			 */
 
-			snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_buf);
+			snprintf(info_buf, sizeof(info_buf), "%s %s", show_comparison(data->comparison), right_buf);
 			sql_insert_return_states(return_id, return_ranges,
 					PARAM_COMPARE, left_param, left_buf, info_buf);
 		} END_FOR_EACH_PTR(link);
@@ -2493,7 +2546,7 @@
 	if (!state_op)
 		goto free;
 
-	if (!filter_comparison(remove_unsigned_from_comparison(state_op), op))
+	if (!comparison_intersection(remove_unsigned_from_comparison(state_op), op))
 		ret = 1;
 free:
 	free_string(left_name);
@@ -2591,37 +2644,47 @@
 		       struct state_list **false_stack)
 {
 	struct compare_data *data;
-	int istrue = 0;
-	int isfalse = 0;
+	int is_true = 0;
+	int is_false = 0;
 
 	if (!sm)
 		return;
 	data = sm->state->data;
-	if (!data) {
-		if (sm->merged) {
-			filter_by_sm(sm->left, op, true_stack, false_stack);
-			filter_by_sm(sm->right, op, true_stack, false_stack);
-		}
+	if (!data || data->comparison == UNKNOWN_COMPARISON)
+		goto split;
+	if (data->comparison == IMPOSSIBLE_COMPARISON)
 		return;
-	}
 
-	if (data->comparison &&
-	    data->comparison == filter_comparison(data->comparison, op))
-		istrue = 1;
+	/*
+	 * We want to check that "data->comparison" is totally inside "op".  So
+	 * if data->comparison is < and op is <= then that's true.  Or if
+	 * data->comparison is == and op is <= then that's true.  But if
+	 * data->comparison is <= and op is < than that's neither true nor
+	 * false.
+	 */
+	if (data->comparison == comparison_intersection(data->comparison, op))
+		is_true = 1;
+	if (data->comparison == comparison_intersection(data->comparison, negate_comparison(op)))
+		is_false = 1;
 
-	if (data->comparison &&
-	    data->comparison == filter_comparison(data->comparison, negate_comparison(op)))
-		isfalse = 1;
+	if (debug_implied()) {
+		sm_msg("%s: %s: op = '%s' negated '%s'. true_intersect = '%s' false_insersect = '%s' sm = '%s'",
+		       __func__,
+		       sm->state->name,
+		       alloc_sname(show_comparison(op)),
+		       alloc_sname(show_comparison(negate_comparison(op))),
+		       alloc_sname(show_comparison(comparison_intersection(data->comparison, op))),
+		       alloc_sname(show_comparison(comparison_intersection(data->comparison, negate_comparison(op)))),
+		       show_sm(sm));
+	}
 
-	if (istrue)
+	if (is_true)
 		add_ptr_list(true_stack, sm);
-	if (isfalse)
+	if (is_false)
 		add_ptr_list(false_stack, sm);
-
-	if (sm->merged) {
-		filter_by_sm(sm->left, op, true_stack, false_stack);
-		filter_by_sm(sm->right, op, true_stack, false_stack);
-	}
+split:
+	filter_by_sm(sm->left, op, true_stack, false_stack);
+	filter_by_sm(sm->right, op, true_stack, false_stack);
 }
 
 struct sm_state *comparison_implication_hook(struct expression *expr,
@@ -2665,7 +2728,7 @@
 	if (!*true_stack && !*false_stack)
 		return NULL;
 
-	if (option_debug)
+	if (debug_implied())
 		sm_msg("implications from comparison: (%s)", show_sm(sm));
 
 	return sm;
--- old/usr/src/tools/smatch/src/smatch_conditions.c	Mon Nov 18 13:19:09 2019
+++ new/usr/src/tools/smatch/src/smatch_conditions.c	Mon Nov 18 13:19:09 2019
@@ -78,12 +78,12 @@
 	struct expression *zero;
 
 	// if left is zero or right is zero
-	if (is_zero(expr->left)) {
+	if (expr_is_zero(expr->left)) {
 		zero = strip_expr(expr->left);
 		if (zero->type != EXPR_VALUE)
 			__split_expr(expr->left);
 		tmp = expr->right;
-	} else if (is_zero(expr->right)) {
+	} else if (expr_is_zero(expr->right)) {
 		zero = strip_expr(expr->left);
 		if (zero->type != EXPR_VALUE)
 			__split_expr(expr->right);
--- old/usr/src/tools/smatch/src/smatch_data/db/clear_user_data.sh	Mon Nov 18 13:19:10 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/clear_user_data.sh	Mon Nov 18 13:19:10 2019
@@ -1,5 +1,5 @@
 #!/bin/bash
 
-echo "delete from caller_info where type = 8017; delete from return_states where type = 8017;" | sqlite3 smatch_db.sqlite
+echo "delete from caller_info where type = 8017; delete from return_states where type = 8017 or type = 9017;" | sqlite3 smatch_db.sqlite
 
 
--- /dev/null	Mon Nov 18 13:19:10 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/copy_function_pointers.pl	Mon Nov 18 13:19:10 2019
@@ -0,0 +1,55 @@
+#!/usr/bin/perl -w
+
+use strict;
+use DBI;
+
+my $db_file = shift;
+if (!$db_file) {
+    print "usage: copy_function_pointers.pl <db file>\n";
+    exit(0);
+}
+
+my $db = DBI->connect("dbi:SQLite:$db_file", "", "", {AutoCommit => 0});
+
+my ($select, $function, $ptr);
+
+$select = $db->prepare('SELECT DISTINCT function, ptr FROM function_ptr WHERE function LIKE "% %";');
+
+my %ptrs;
+
+$select->execute();
+while (($function, $ptr) = $select->fetchrow_array()) {
+    $ptrs{"$function"}{'ptr'} = $ptr;
+    $ptrs{"$function"}{'done'} = 0;
+}
+
+sub copy_functions($);
+sub copy_functions($)
+{
+    my $src = shift;
+
+    if ($ptrs{"$src"}{'done'}) {
+        return;
+    }
+    $ptrs{"$src"}{'done'} = 1;
+
+    my $select = $db->prepare('SELECT distinct file, function FROM function_ptr WHERE ptr = ?;');
+    my $insert = $db->prepare('INSERT OR IGNORE INTO function_ptr VALUES (?, ?, ?, 1);');
+
+    $select->execute($src);
+    while (my ($file, $function) = $select->fetchrow_array()) {
+        if ($function =~ / /) {
+            copy_functions($function);
+            next;
+        }
+
+        $insert->execute($file, $function, $ptrs{"$src"}{'ptr'});
+    }
+}
+
+foreach my $key (keys(%ptrs)) {
+    copy_functions($key);
+}
+
+$db->commit();
+$db->disconnect();
--- old/usr/src/tools/smatch/src/smatch_data/db/create_db.sh	Mon Nov 18 13:19:10 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/create_db.sh	Mon Nov 18 13:19:10 2019
@@ -43,6 +43,7 @@
     ${bin_dir}/fixup_${PROJ}.sh $db_file
 fi
 
+${bin_dir}/copy_function_pointers.pl $db_file
 ${bin_dir}/remove_mixed_up_pointer_params.pl $db_file
 ${bin_dir}/delete_too_common_fn_ptr.sh $db_file
 ${bin_dir}/mark_function_ptrs_searchable.pl $db_file
--- old/usr/src/tools/smatch/src/smatch_data/db/fill_db_sql.pl	Mon Nov 18 13:19:10 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/fill_db_sql.pl	Mon Nov 18 13:19:10 2019
@@ -7,7 +7,7 @@
 my $warns = shift;
 my $db_file = shift;
 
-if (!defined($warns)) {
+if (!defined($db_file)) {
     print "usage:  $0 <-p=project> <smatch_warns.txt> <db_file>\n";
     exit(1);
 }
--- old/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh	Mon Nov 18 13:19:11 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh	Mon Nov 18 13:19:11 2019
@@ -41,6 +41,8 @@
 delete from caller_info where function = '__netdev_start_xmit' and type = 8017;
 delete from caller_info where function = '(struct packet_type)->func' and type = 8017;
 delete from caller_info where function = '(struct bio)->bi_end_io' and type = 8017;
+delete from caller_info where type = 8017 and key = '*\$->bi_private';
+delete from caller_info where type = 8017 and key = '\$->bi_private';
 delete from caller_info where caller = 'NF_HOOK_COND' and type = 8017;
 delete from caller_info where caller = 'NF_HOOK' and type = 8017;
 /* comparison doesn't deal with chunks, I guess.  */
@@ -50,6 +52,7 @@
 delete from caller_info where function = 'nf_tables_newexpr' and type = 8017 and key = '\$->family';
 delete from caller_info where caller = 'fb_set_var' and function = '(struct fb_ops)->fb_set_par' and type = 8017 and parameter = 0;
 delete from return_states where function = 'tty_lookup_driver' and parameter = 2 and type = 8017;
+delete from caller_info where function = 'iomap_apply' and type = 8017 and key = '*\$';
 
 insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 8017, 0, '\$', '1');
 insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 8017, 1, '\$', '1');
@@ -174,6 +177,9 @@
 /* Smatch sucks at loops */
 delete from return_states where function = 'ata_dev_next' and type = 103;
 
+/* The problem is that parsing big function pointers is hard. */
+delete from return_states where function = 'vfs_get_tree' and type = 1024;
+
 EOF
 
 # fixme: this is totally broken
--- old/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes	Mon Nov 18 13:19:11 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes	Mon Nov 18 13:19:11 2019
@@ -53,3 +53,7 @@
 array_index_mask_nospec 0-u64max u64max
 array_index_mask_nospec 0-u32max u32max
 nla_len (-4)-65531[$0->nla_len\ -\ 4] 0-65531[$0->nla_len\ -\ 4]
+__rounddown_pow_of_two 0-u64max 0-u64max[<=$0]
+__roundup_pow_of_two 0-u64max 0-u64max[>=$0]
+kthread_probe_data 0 0-u64max
+bus_for_each_dev (-4095)-1 (-4095)-1[r\ $3]
--- old/usr/src/tools/smatch/src/smatch_data/db/smdb.py	Mon Nov 18 13:19:12 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/smdb.py	Mon Nov 18 13:19:12 2019
@@ -7,6 +7,7 @@
 import sqlite3
 import sys
 import re
+import subprocess
 
 try:
     con = sqlite3.connect('smatch_db.sqlite')
@@ -25,6 +26,8 @@
     print "data_info <struct_type> <member> - information about a given data type"
     print "function_ptr <function> - which function pointers point to this"
     print "trace_param <function> <param> - trace where a parameter came from"
+    print "find_tagged <function> <param> - find the source of a tagged value (arm64)"
+    print "parse_warns_tagged <smatch_warns.txt> - parse warns file for summary of tagged issues (arm64)"
     print "locals <file> - print the local values in a file."
     sys.exit(1)
 
@@ -267,7 +270,7 @@
         if txt[0] == '-':
             parsed += 1
         for char in txt[parsed:]:
-            if char == '-':
+            if char == '-' or char == '[':
                 break
             parsed += 1
         val = txt[:parsed]
@@ -542,6 +545,107 @@
     for txt in cur:
         print "%-30s | %-30s | %s | %s" %(txt[0], txt[1], txt[2], txt[3])
 
+def rl_too_big(txt):
+    rl = txt_to_rl(txt)
+    ret = ""
+    for idx in range(len(rl)):
+        cur_max = rl[idx][1]
+        if (cur_max > 0xFFFFFFFFFFFFFF):
+            return 1
+
+    return 0
+
+def rl_has_min_untagged(txt):
+    rl = txt_to_rl(txt)
+    ret = ""
+    for idx in range(len(rl)):
+        cur_min = rl[idx][0]
+        if (cur_min == 0xff80000000000000):
+            return 1
+
+    return 0
+
+def rl_is_tagged(txt):
+    if not rl_too_big(txt):
+        return 0
+
+    if rl_has_min_untagged(txt):
+        return 0
+
+    return 1
+
+def rl_is_treat_untagged(txt):
+    if "[u]" in txt:
+        return 1;
+
+    return 0
+
+def parse_warns_tagged(filename):
+    proc = subprocess.Popen(['cat %s | grep "potentially tagged" | sort | uniq' %(filename)], shell=True, stdout=subprocess.PIPE)
+    while True:
+        line = proc.stdout.readline()
+        if not line:
+            break
+
+	linepos = re.search("([^\s]+)", line).group(1)
+	groupre = re.search("potentially tagged address \(([^,]+), ([^,]+), ([^\)]+)\)", line)
+	groupre.group(1)
+
+	func = groupre.group(1)
+	param = int(groupre.group(2))
+	var = groupre.group(3)
+
+	if ("end" in var or "size" in var or "len" in var):
+		continue
+
+	print "\n%s (func: %s, param: %d:%s) may be caused by:" %(linepos, func, param, var)
+
+	if (param != -1):
+		if not find_tagged(func, param, 0, []):
+			print "    %s (param %d) (can't walk call tree)" % (func, param)
+	else:
+		print "    %s (variable %s (can't walk call tree)" % (func, var)
+
+def find_tagged(func, param, caller_call_id, printed):
+
+    callers = {}
+    cur = con.cursor()
+    ptrs = get_function_pointers(func)
+    found = 0
+
+    for ptr in ptrs:
+        cur.execute("select call_id, value from caller_info where function = '%s' and parameter=%d and type=%d" %(ptr, param, type_to_int("DATA_SOURCE")))
+
+        for row in cur:
+            if (row[1][0] == '$'):
+                if row[0] not in callers:
+                    callers[row[0]] = {}
+                callers[row[0]]["param"] = int(row[1][1])
+
+    for ptr in ptrs:
+        cur.execute("select caller, call_id, value from caller_info where function = '%s' and parameter=%d and type=%d" %(ptr, param, type_to_int("USER_DATA")))
+
+        for row in cur:
+            if not rl_is_tagged(row[2]):
+                continue
+	    if rl_is_treat_untagged(row[2]):
+	        continue
+            found = 1
+            if row[1] not in callers:
+                callers[row[1]] = {}
+            if "param" not in callers[row[1]]:
+                line = "    %s (param ?) -> %s (param %d)" % (row[0], func, param)
+                if line not in printed:
+                        printed.append(line)
+                        print line
+                continue
+            if row[0] not in printed:
+                printed.append(row[0])
+                if not find_tagged(row[0], callers[row[1]]["param"], row[1], printed):
+                    print "    %s (param %d)" % (row[0], param)
+
+    return found
+
 def trace_callers(func, param):
     sources = []
     prev_type = 0
@@ -574,8 +678,8 @@
     sources = trace_callers(func, param)
     for path in sources:
 
-        if len(path[1]) and path[1][0] == 'p' and path[1][1] == ' ':
-            p = int(path[1][2:])
+        if len(path[1]) and path[1][0] == '$':
+            p = int(re.findall('\d+', path[1][1:])[0])
             trace_param_helper(path[0], p, indent + 2)
         elif len(path[0]) and path[0][0] == '%':
             print "  %s%s" %(" " * indent, path[1])
@@ -641,6 +745,13 @@
 elif sys.argv[1] == "call_tree":
     func = sys.argv[2]
     print_call_tree(func)
+elif sys.argv[1] == "find_tagged":
+    func = sys.argv[2]
+    param = int(sys.argv[3])
+    find_tagged(func, param, 0, [])
+elif sys.argv[1] == "parse_warns_tagged":
+    filename = sys.argv[2]
+    parse_warns_tagged(filename)
 elif sys.argv[1] == "where":
     if len(sys.argv) == 3:
         struct_type = "%"
@@ -677,9 +788,5 @@
         struct_type = sys.argv[2]
         member = sys.argv[3]
     constraint(struct_type, member)
-elif sys.argv[1] == "test":
-    filename = sys.argv[2]
-    func = sys.argv[3]
-    caller_info_values(filename, func)
 else:
     usage()
--- old/usr/src/tools/smatch/src/smatch_data/db/vim_smdb	Mon Nov 18 13:19:12 2019
+++ new/usr/src/tools/smatch/src/smatch_data/db/vim_smdb	Mon Nov 18 13:19:12 2019
@@ -26,7 +26,21 @@
 
 rm -f $DIR/$next
 rm -f $DIR/.${i}.swp
-smdb $* > $DIR/$i
 
+func=""
+if [[ "$3" != "" ]] ; then
+	func="$3"
+elif [[ "$2" != "" ]] ; then
+	func="$2"
+elif [[ "$1" != "" ]] ; then
+	func="$1"
+fi
+
+echo "$func" >> $DIR/history
+tail -n 7 $DIR/history | tac | perl -ne 's/\n/ /; print' | perl -ne 's/ $//; print' > $DIR/$i
+echo "" >> $DIR/$i
+echo "==========================" >> $DIR/$i
+smdb $* >> $DIR/$i
+
 echo "$DIR/$i" > $DIR/cur
 
--- old/usr/src/tools/smatch/src/smatch_data/kernel.bit_shifters.remove	Mon Nov 18 13:19:12 2019
+++ new/usr/src/tools/smatch/src/smatch_data/kernel.bit_shifters.remove	Mon Nov 18 13:19:12 2019
@@ -5,5 +5,7 @@
 V4L2_TUNER_MODE_SAP 2
 V4L2_TUNER_MODE_LANG1 3
 V4L2_TUNER_MODE_LANG1_LANG2 4
-
 MBX_INTERRUPT 1
+HWTSTAMP_TX_ON 1
+LOCK_USAGE_READ_MASK 1
+LOCK_USAGE_DIR_MASK 2
--- old/usr/src/tools/smatch/src/smatch_data/kernel.check_string_condition.ignore	Mon Nov 18 13:19:13 2019
+++ new/usr/src/tools/smatch/src/smatch_data/kernel.check_string_condition.ignore	Mon Nov 18 13:19:13 2019
@@ -1,1 +1,2 @@
 TRACE_EVENT
+WARN_ON_ONCE
--- old/usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params	Mon Nov 18 13:19:13 2019
+++ new/usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params	Mon Nov 18 13:19:13 2019
@@ -2,6 +2,7 @@
 clear_bit
 __clear_bit
 __set_bit
+test_bit
 test_and_set_bit
 find_last_bit
 change_bit
--- old/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects	Mon Nov 18 13:19:13 2019
+++ new/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects	Mon Nov 18 13:19:13 2019
@@ -8,6 +8,7 @@
 ADD_STA_STATS
 ARCH_DLINFO
 AWDATA
+CONVERT_COMMON_TCP_SOCK_FIELDS
 ENCODE
 ENCODE_DATA
 ENCODE_STR
@@ -50,6 +51,7 @@
 RADEON_WAIT_UNTIL_2D_IDLE
 RADEON_WAIT_UNTIL_3D_IDLE
 RADEON_WAIT_UNTIL_IDLE
+rcu_assign_pointer
 RCU_INIT_POINTER
 READ64
 rtnl_dereference
@@ -67,5 +69,6 @@
 unsafe_get_user
 unsafe_put_user
 VIA_OUT_RING_QW
+WREG32_SOC15_DPG_MODE_2_0
 WRITE64
 Z
--- old/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param	Mon Nov 18 13:19:14 2019
+++ new/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param	Mon Nov 18 13:19:14 2019
@@ -109,3 +109,6 @@
 smb_word_op 5
 atl1c_read_phy_reg 2
 adf7242_read_reg 2
+tfp410_readb 2
+asus_wmi_get_devstate 2
+e1000_read_nvm 2
--- old/usr/src/tools/smatch/src/smatch_data/kernel.unreachable.ignore	Mon Nov 18 13:19:14 2019
+++ new/usr/src/tools/smatch/src/smatch_data/kernel.unreachable.ignore	Mon Nov 18 13:19:14 2019
@@ -23,3 +23,6 @@
 netdev_for_each_lower_dev
 for_each_clear_bit_from
 idr_for_each_entry_continue
+for_each_engine_masked
+drm_mm_for_each_hole
+for_each_set_bit
--- old/usr/src/tools/smatch/src/smatch_db.c	Mon Nov 18 13:19:14 2019
+++ new/usr/src/tools/smatch/src/smatch_db.c	Mon Nov 18 13:19:14 2019
@@ -508,17 +508,19 @@
 void sql_select_return_states(const char *cols, struct expression *call,
 	int (*callback)(void*, int, char**, char**), void *info)
 {
+	struct expression *fn;
 	int row_count = 0;
 
 	if (is_fake_call(call))
 		return;
 
-	if (call->fn->type != EXPR_SYMBOL || !call->fn->symbol || is_local_symbol(call->fn)) {
+	fn = strip_expr(call->fn);
+	if (fn->type != EXPR_SYMBOL || !fn->symbol || is_local_symbol(fn)) {
 		sql_select_return_states_pointer(cols, call, callback, info);
 		return;
 	}
 
-	if (inlinable(call->fn)) {
+	if (inlinable(fn)) {
 		mem_sql(callback, info,
 			"select %s from return_states where call_id = '%lu' order by return_id, type;",
 			cols, (unsigned long)call);
@@ -526,12 +528,12 @@
 	}
 
 	run_sql(get_row_count, &row_count, "select count(*) from return_states where %s;",
-		get_static_filter(call->fn->symbol));
+		get_static_filter(fn->symbol));
 	if (row_count > 3000)
 		return;
 
 	run_sql(callback, info, "select %s from return_states where %s order by file, return_id, type;",
-		cols, get_static_filter(call->fn->symbol));
+		cols, get_static_filter(fn->symbol));
 }
 
 #define CALL_IMPLIES 0
@@ -718,6 +720,33 @@
 	return ret_info.return_range_list;
 }
 
+/*
+ * This is used when we have a function that takes a function pointer as a
+ * parameter.  "frob(blah, blah, my_function);"  We know that the return values
+ * from frob() come from my_funcion() so we want to find the possible returns
+ * of my_function(), but we don't know which arguments are passed to it.
+ *
+ */
+struct range_list *db_return_vals_no_args(struct expression *expr)
+{
+	struct return_info ret_info = {};
+
+	if (!expr || expr->type != EXPR_SYMBOL)
+		return NULL;
+
+	ret_info.static_returns_call = expr;
+	ret_info.return_type = get_type(expr);
+	ret_info.return_type = get_real_base_type(ret_info.return_type);
+	if (!ret_info.return_type)
+		return NULL;
+
+	run_sql(db_return_callback, &ret_info,
+		"select distinct return from return_states where %s;",
+		get_static_filter(expr->symbol));
+
+	return ret_info.return_range_list;
+}
+
 static void match_call_marker(struct expression *expr)
 {
 	struct symbol *type;
@@ -1106,8 +1135,7 @@
 		if (ptr_list_size((struct ptr_list *)ptr_names) > 20) {
 			__free_ptr_list((struct ptr_list **)&ptr_names);
 			__free_ptr_list((struct ptr_list **)&ptr_names_done);
-			stree = __pop_fake_cur_stree();
-			free_stree(&stree);
+			__free_fake_cur_stree();
 			return;
 		}
 
@@ -1124,6 +1152,7 @@
 		__unnullify_path();
 		data.prev_func_id = -1;
 		data.ignore = 0;
+		data.results = 0;
 
 		FOR_EACH_PTR(ptr_names, ptr) {
 			run_sql(caller_info_callback, &data,
@@ -1261,6 +1290,29 @@
 			   call_implies_callbacks);
 }
 
+static char *get_fn_param_str(struct expression *expr)
+{
+	struct expression *tmp;
+	int param;
+	char buf[32];
+
+	tmp = get_assigned_expr(expr);
+	if (tmp)
+		expr = tmp;
+	expr = strip_expr(expr);
+	if (!expr || expr->type != EXPR_CALL)
+		return NULL;
+	expr = strip_expr(expr->fn);
+	if (!expr || expr->type != EXPR_SYMBOL)
+		return NULL;
+	param = get_param_num(expr);
+	if (param < 0)
+		return NULL;
+
+	snprintf(buf, sizeof(buf), "[r $%d]", param);
+	return alloc_sname(buf);
+}
+
 static char *get_return_compare_is_param(struct expression *expr)
 {
 	char *var;
@@ -1306,6 +1358,7 @@
 	struct range_list *rl;
 	char *return_ranges;
 	sval_t sval;
+	char *fn_param_str;
 	char *compare_str;
 	char *math_str;
 	char buf[128];
@@ -1321,6 +1374,7 @@
 		return sval_to_str_or_err_ptr(sval);
 	}
 
+	fn_param_str = get_fn_param_str(expr);
 	compare_str = expr_equal_to_param(expr, -1);
 	math_str = get_value_in_terms_of_parameter_math(expr);
 
@@ -1337,6 +1391,10 @@
 	}
 	*rl_p = rl;
 
+	if (fn_param_str) {
+		snprintf(buf, sizeof(buf), "%s%s", return_ranges, fn_param_str);
+		return alloc_sname(buf);
+	}
 	if (compare_str) {
 		snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
 		return alloc_sname(buf);
@@ -1851,8 +1909,6 @@
 	struct sm_state *tmp;
 	int ret = 0;
 	int nr_possible, nr_states;
-	char *compare_str = NULL;
-	char buf[128];
 	struct state_list *already_handled = NULL;
 
 	if (!sm || !sm->merged)
@@ -1881,12 +1937,6 @@
 
 		return_ranges = get_return_ranges_str(expr, &ret_rl);
 		set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(ret_rl));
-		compare_str = get_return_compare_str(expr);
-		if (compare_str) {
-			snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
-			return_ranges = alloc_sname(buf);
-		}
-
 		return_id++;
 		FOR_EACH_PTR(returned_state_callbacks, cb) {
 			cb->callback(return_id, (char *)return_ranges, expr);
@@ -2014,6 +2064,7 @@
 	nr_states = get_db_state_count();
 	if (nr_states >= 10000) {
 		match_return_info(return_id, (char *)return_ranges, expr);
+		print_limited_param_set(return_id, (char *)return_ranges, expr);
 		mark_all_params_untracked(return_id, (char *)return_ranges, expr);
 		return;
 	}
@@ -2287,19 +2338,26 @@
 	static char string[256];
 	char *start;
 	char *p = *str;
-	int len;
+	int len, i, j;
 
 	if (*p == '\0')
 		return NULL;
 	start = p;
 
-	while (*p != '\0' && *p != ' ' && *p != '\n')
+	while (*p != '\0' && *p != '\n') {
+		if (*p == '\\' && *(p + 1) == ' ') {
+			p += 2;
+			continue;
+		}
+		if (*p == ' ')
+			break;
 		p++;
+	}
 
 	len = p - start;
-	if (len > 256) {
-		memcpy(string, start, 255);
-		string[255] = '\0';
+	if (len >= sizeof(string)) {
+		memcpy(string, start, sizeof(string));
+		string[sizeof(string) - 1] = '\0';
 		sm_ierror("return_fix: '%s' too long", string);
 		**str = '\0';
 		return NULL;
@@ -2306,6 +2364,12 @@
 	}
 	memcpy(string, start, len);
 	string[len] = '\0';
+	for (i = 0; i < sizeof(string) - 1; i++) {
+		if (string[i] == '\\' && string[i + 1] == ' ') {
+			for (j = i; string[j] != '\0'; j++)
+				string[j] = string[j + 1];
+		}
+	}
 	if (*p != '\0')
 		p++;
 	*str = p;
@@ -2499,7 +2563,7 @@
 
 	if (strcmp(state_name, param_name) == 0) {
 		snprintf(buf, sizeof(buf), "%s$", add_star ? "*" : "");
-		return buf;
+		return alloc_sname(buf);
 	}
 
 	if (state_name[name_len] == '-' && /* check for '-' from "->" */
@@ -2506,7 +2570,7 @@
 	    strncmp(state_name, param_name, name_len) == 0) {
 		snprintf(buf, sizeof(buf), "%s$%s",
 			 add_star ? "*" : "", state_name + name_len);
-		return buf;
+		return alloc_sname(buf);
 	}
 	return NULL;
 }
--- old/usr/src/tools/smatch/src/smatch_estate.c	Mon Nov 18 13:19:15 2019
+++ new/usr/src/tools/smatch/src/smatch_estate.c	Mon Nov 18 13:19:15 2019
@@ -53,6 +53,9 @@
 	if (estate_capped(s1) && estate_capped(s2))
 		estate_set_capped(tmp);
 
+	if (estate_treat_untagged(s1) && estate_treat_untagged(s2))
+		estate_set_treat_untagged(tmp);
+
 	return tmp;
 }
 
@@ -116,7 +119,7 @@
 
 int estate_has_hard_max(struct smatch_state *state)
 {
-	if (!state)
+	if (!state || !estate_rl(state))
 		return 0;
 	return get_dinfo(state)->hard_max;
 }
@@ -154,6 +157,23 @@
 	get_dinfo(state)->capped = true;
 }
 
+bool estate_treat_untagged(struct smatch_state *state)
+{
+	if (!state)
+		return false;
+
+	/* impossible states are capped */
+	if (!estate_rl(state))
+		return true;
+
+	return get_dinfo(state)->treat_untagged;
+}
+
+void estate_set_treat_untagged(struct smatch_state *state)
+{
+	get_dinfo(state)->treat_untagged = true;
+}
+
 sval_t estate_min(struct smatch_state *state)
 {
 	return rl_min(estate_rl(state));
@@ -204,6 +224,8 @@
 		return 0;
 	if (estate_capped(one) != estate_capped(two))
 		return 0;
+	if (estate_treat_untagged(one) != estate_treat_untagged(two))
+		return 0;
 	if (strcmp(one->name, two->name) == 0)
 		return 1;
 	return 0;
@@ -234,6 +256,8 @@
 {
 	sval_t min, max;
 
+	if (!estate_rl(state))
+		return 0;
 	min = rl_min(estate_rl(state));
 	max = rl_max(estate_rl(state));
 	if (sval_cmp(min, max) != 0)
--- old/usr/src/tools/smatch/src/smatch_expressions.c	Mon Nov 18 13:19:15 2019
+++ new/usr/src/tools/smatch/src/smatch_expressions.c	Mon Nov 18 13:19:15 2019
@@ -162,6 +162,82 @@
 	return ret;
 }
 
+static struct expression *get_expression_from_base_and_str(struct expression *base, const char *addition)
+{
+	struct expression *ret = NULL;
+	struct token *token, *prev, *end;
+	char *alloc;
+
+	if (addition[0] == '\0')
+		return base;
+
+	alloc = alloc_string_newline(addition);
+
+	token = tokenize_buffer(alloc, strlen(alloc), &end);
+	if (!token)
+		goto free;
+	if (token_type(token) != TOKEN_STREAMBEGIN)
+		goto free;
+	token = token->next;
+
+	ret = base;
+	while (token_type(token) == TOKEN_SPECIAL &&
+	       (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
+		prev = token;
+		token = token->next;
+		if (token_type(token) != TOKEN_IDENT)
+			goto free;
+		switch (prev->special) {
+		case SPECIAL_DEREFERENCE:
+			ret = deref_expression(ret);
+			ret = member_expression(ret, '*', token->ident);
+			break;
+		case '.':
+			ret = member_expression(ret, '.', token->ident);
+			break;
+		default:
+			goto free;
+		}
+		token = token->next;
+	}
+
+	if (token_type(token) != TOKEN_STREAMEND)
+		goto free;
+
+free:
+	free_string(alloc);
+
+	return ret;
+}
+
+struct expression *gen_expression_from_name_sym(const char *name, struct symbol *sym)
+{
+	struct expression *base;
+	int skip = 0;
+	struct expression *ret;
+
+	if (!name || !sym)
+		return NULL;
+
+	base = symbol_expression(sym);
+	while (name[skip] != '\0' && name[skip] != '.' && name[skip] != '-')
+		skip++;
+
+	ret = get_expression_from_base_and_str(base, name + skip);
+	if (ret) {
+		char *new = expr_to_str(ret);
+
+		/*
+		 * FIXME: this sometimes changes "foo->bar.a.b->c" into
+		 * "foo->bar.a.b.c".  I don't know why...  :(
+		 *
+		 */
+		if (!new || strcmp(name, new) != 0)
+			return NULL;
+	}
+	return ret;
+}
+
 struct expression *gen_expression_from_key(struct expression *arg, const char *key)
 {
 	struct expression *ret;
--- old/usr/src/tools/smatch/src/smatch_extra.c	Mon Nov 18 13:19:16 2019
+++ new/usr/src/tools/smatch/src/smatch_extra.c	Mon Nov 18 13:19:16 2019
@@ -99,12 +99,86 @@
 	call_extra_hooks(extra_nomod_hooks, name, sym, expr, state);
 }
 
+static void set_union_info(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
+{
+	struct symbol *type, *tmp, *inner_type, *inner, *new_type;
+	struct expression *deref, *member_expr;
+	struct smatch_state *new;
+	int offset, inner_offset;
+	static bool in_recurse;
+	char *member_name;
+
+	if (__in_fake_assign)
+		return;
+
+	if (in_recurse)
+		return;
+	in_recurse = true;
+
+	if (!expr || expr->type != EXPR_DEREF || !expr->member)
+		goto done;
+	offset = get_member_offset_from_deref(expr);
+	if (offset < 0)
+		goto done;
+
+	deref = strip_expr(expr->deref);
+	type = get_type(deref);
+	if (type_is_ptr(type))
+		type = get_real_base_type(type);
+	if (!type || type->type != SYM_STRUCT)
+		goto done;
+
+	FOR_EACH_PTR(type->symbol_list, tmp) {
+		inner_type = get_real_base_type(tmp);
+		if (!inner_type || inner_type->type != SYM_UNION)
+			continue;
+
+		inner = first_ptr_list((struct ptr_list *)inner_type->symbol_list);
+		if (!inner || !inner->ident)
+			continue;
+
+		inner_offset = get_member_offset(type, inner->ident->name);
+		if (inner_offset < offset)
+			continue;
+		if (inner_offset > offset)
+			goto done;
+
+		FOR_EACH_PTR(inner_type->symbol_list, inner) {
+			struct symbol *tmp_type;
+
+			if (!inner->ident || inner->ident == expr->member)
+				continue;
+			tmp_type = get_real_base_type(inner);
+			if (tmp_type && tmp_type->type == SYM_STRUCT)
+				continue;
+			member_expr = deref;
+			if (tmp->ident)
+				member_expr = member_expression(member_expr, '.', tmp->ident);
+			member_expr = member_expression(member_expr, expr->op, inner->ident);
+			member_name = expr_to_var(member_expr);
+			if (!member_name)
+				continue;
+			new_type = get_real_base_type(inner);
+			new = alloc_estate_rl(cast_rl(new_type, estate_rl(state)));
+			set_extra_mod_helper(member_name, sym, member_expr, new);
+			free_string(member_name);
+		} END_FOR_EACH_PTR(inner);
+	} END_FOR_EACH_PTR(tmp);
+
+done:
+	in_recurse = false;
+}
+
 static bool in_param_set;
 void set_extra_mod_helper(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
 {
+	if (!expr)
+		expr = gen_expression_from_name_sym(name, sym);
 	remove_from_equiv(name, sym);
+	set_union_info(name, sym, expr, state);
 	call_extra_mod_hooks(name, sym, expr, state);
-	if ((__in_fake_assign || in_param_set) &&
+	update_mtag_data(expr, state);
+	if (in_param_set &&
 	    estate_is_unknown(state) && !get_state(SMATCH_EXTRA, name, sym))
 		return;
 	set_state(SMATCH_EXTRA, name, sym, state);
@@ -172,7 +246,7 @@
 	return NULL;
 }
 
-static char *get_long_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
+static char *get_long_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
 {
 	struct expression *tmp;
 	struct sm_state *sm;
@@ -196,6 +270,8 @@
 	return NULL;
 
 found:
+	if (!use_stack && name[tmp->symbol->ident->len] != '-')
+		return NULL;
 	snprintf(buf, sizeof(buf), "%s%s", sm->name, name + tmp->symbol->ident->len);
 	*new_sym = sm->sym;
 	return alloc_string(buf);
@@ -224,7 +300,7 @@
 	if (len >= sizeof(buf) - 2)
 		return NULL;
 
-	while (len >= 1) {
+	while (use_stack && len >= 1) {
 		if (buf[len] == '>' && buf[len - 1] == '-') {
 			len--;
 			buf[len] = '\0';
@@ -235,7 +311,7 @@
 		len--;
 	}
 
-	ret = get_long_name_sym(name, sym, new_sym);
+	ret = get_long_name_sym(name, sym, new_sym, use_stack);
 	if (ret)
 		return ret;
 
@@ -258,9 +334,9 @@
 	struct symbol *new_sym;
 
 	set_extra_mod_helper(name, sym, expr, state);
-	new_name = get_other_name_sym(name, sym, &new_sym);
+	new_name = get_other_name_sym_nostack(name, sym, &new_sym);
 	if (new_name && new_sym)
-		set_extra_mod_helper(new_name, new_sym, expr, state);
+		set_extra_mod_helper(new_name, new_sym, NULL, state);
 	free_string(new_name);
 }
 
@@ -1231,20 +1307,14 @@
 
 	struct expression *expr;
 	struct symbol *type;
-	int state = 0;
 
 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
-		switch (state) {
-		case 0: /* identifier */
-		case 1: /* constraint */
-			state++;
+		if (expr->type != EXPR_ASM_OPERAND) {
+			sm_perror("unexpected asm param type %d", expr->type);
 			continue;
-		case 2: /* expression */
-			state = 0;
-			type = get_type(strip_expr(expr));
-			set_extra_expr_mod(expr, alloc_estate_whole(type));
-			continue;
 		}
+		type = get_type(strip_expr(expr->expr));
+		set_extra_expr_mod(expr->expr, alloc_estate_whole(type));
 	} END_FOR_EACH_PTR(expr);
 }
 
@@ -1280,6 +1350,8 @@
 {
 	if (expr->type != EXPR_PREOP)
 		return;
+	if (getting_address(expr))
+		return;
 	/* it's saying that foo[1] = bar dereferences foo[1] */
 	if (is_array(expr))
 		return;
@@ -2203,7 +2275,7 @@
 	start = &buf[0];
 	while (*start == '*') {
 		start++;
-		state = get_state(SMATCH_EXTRA, start, sym);
+		state = __get_state(SMATCH_EXTRA, start, sym);
 		if (!state)
 			continue;
 		if (!estate_rl(state))
@@ -2373,12 +2445,14 @@
 	struct range_list *rl;
 	sval_t dummy;
 
-	if (estate_is_whole(sm->state))
+	if (estate_is_whole(sm->state) || !estate_rl(sm->state))
 		return;
 	if (filter_unused_param_value_info(call, param, printed_name, sm))
 		return;
 	rl = estate_rl(sm->state);
 	rl = intersect_with_real_abs_var_sym(sm->name, sm->sym, rl);
+	if (!rl)
+		return;
 	sql_insert_caller_info(call, PARAM_VALUE, param, printed_name, show_rl(rl));
 	if (!estate_get_single_value(sm->state, &dummy)) {
 		if (estate_has_hard_max(sm->state))
@@ -2569,7 +2643,7 @@
 
 static void db_param_add_set(struct expression *expr, int param, char *key, char *value, enum info_type op)
 {
-	struct expression *arg;
+	struct expression *arg, *gen_expr;
 	char *name;
 	char *other_name = NULL;
 	struct symbol *sym, *other_sym;
@@ -2589,9 +2663,12 @@
 
 	arg_type = get_arg_type_from_key(expr->fn, param, arg, key);
 	param_type = get_member_type_from_key(arg, key);
+	if (param_type && param_type->type == SYM_STRUCT)
+		return;
 	name = get_variable_from_key(arg, key, &sym);
 	if (!name || !sym)
 		goto free;
+	gen_expr = gen_expression_from_key(arg, key);
 
 	state = get_state(SMATCH_EXTRA, name, sym);
 	if (state)
@@ -2605,9 +2682,9 @@
 		new = rl_union(new, added);
 
 	other_name = get_other_name_sym_nostack(name, sym, &other_sym);
-	set_extra_mod(name, sym, NULL, alloc_estate_rl(new));
+	set_extra_mod(name, sym, gen_expr, alloc_estate_rl(new));
 	if (other_name && other_sym)
-		set_extra_mod(other_name, other_sym, NULL, alloc_estate_rl(new));
+		set_extra_mod(other_name, other_sym, gen_expr, alloc_estate_rl(new));
 free:
 	free_string(other_name);
 	free_string(name);
--- old/usr/src/tools/smatch/src/smatch_extra.h	Mon Nov 18 13:19:16 2019
+++ new/usr/src/tools/smatch/src/smatch_extra.h	Mon Nov 18 13:19:16 2019
@@ -31,6 +31,7 @@
 	sval_t fuzzy_max;
 	unsigned int hard_max:1;
 	unsigned int capped:1;
+	unsigned int treat_untagged:1;
 };
 DECLARE_ALLOCATOR(data_info);
 
@@ -73,6 +74,8 @@
 int rl_has_sval(struct range_list *rl, sval_t sval);
 int ranges_equiv(struct data_range *one, struct data_range *two);
 
+bool is_err_ptr(sval_t sval);
+
 int rl_equiv(struct range_list *one, struct range_list *two);
 int is_whole_rl(struct range_list *rl);
 int is_unknown_ptr(struct range_list *rl);
@@ -146,6 +149,8 @@
 int estate_get_hard_max(struct smatch_state *state, sval_t *sval);
 bool estate_capped(struct smatch_state *state);
 void estate_set_capped(struct smatch_state *state);
+bool estate_treat_untagged(struct smatch_state *state);
+void estate_set_treat_untagged(struct smatch_state *state);
 
 int estate_get_single_value(struct smatch_state *state, sval_t *sval);
 struct smatch_state *get_implied_estate(struct expression *expr);
@@ -211,6 +216,7 @@
 struct expression *compare_expression(struct expression *left, int op, struct expression *right);
 struct expression *unknown_value_expression(struct expression *expr);
 int is_fake_call(struct expression *expr);
+struct expression *gen_expression_from_name_sym(const char *name, struct symbol *sym);
 struct expression *gen_expression_from_key(struct expression *arg, const char *key);
 void free_tmp_expressions(void);
 void expr_set_parent_expr(struct expression *expr, struct expression *parent);
--- old/usr/src/tools/smatch/src/smatch_flow.c	Mon Nov 18 13:19:17 2019
+++ new/usr/src/tools/smatch/src/smatch_flow.c	Mon Nov 18 13:19:17 2019
@@ -44,6 +44,7 @@
 static int last_goto_statement_handled;
 int __expr_stmt_count;
 int __in_function_def;
+int __in_unmatched_hook;
 static struct expression_list *switch_expr_stack = NULL;
 static struct expression_list *post_op_stack = NULL;
 
@@ -460,6 +461,8 @@
 
 		__fake_struct_member_assignments(expr);
 
+		/* Re-examine ->right for inlines.  See the commit message */
+		right = strip_expr(expr->right);
 		if (expr->op == '=' && right->type == EXPR_CALL)
 			__pass_to_client(expr, CALL_ASSIGNMENT_HOOK);
 
@@ -527,8 +530,8 @@
 			break;
 		if (handle__builtin_choose_expr(expr))
 			break;
-		split_expr_list(expr->args, expr);
 		__split_expr(expr->fn);
+		split_expr_list(expr->args, expr);
 		if (is_inline_func(expr->fn))
 			add_inline_function(expr->fn->symbol);
 		if (inlinable(expr->fn))
@@ -569,6 +572,7 @@
 	default:
 		break;
 	};
+	__pass_to_client(expr, EXPR_HOOK_AFTER);
 	pop_expression(&big_expression_stack);
 }
 
@@ -700,7 +704,7 @@
 	__merge_gotos(loop_name, NULL);
 	__split_stmt(stmt->iterator_statement);
 	__merge_continues();
-	if (!is_zero(stmt->iterator_post_condition))
+	if (!expr_is_zero(stmt->iterator_post_condition))
 		__save_gotos(loop_name, NULL);
 
 	if (is_forever_loop(stmt)) {
@@ -1614,21 +1618,20 @@
 
 static void save_flow_state(void)
 {
-	__add_ptr_list(&backup, INT_PTR(loop_num << 2), 0);
-	__add_ptr_list(&backup, INT_PTR(loop_count << 2), 0);
-	__add_ptr_list(&backup, INT_PTR(final_pass << 2), 0);
+	__add_ptr_list(&backup, INT_PTR(loop_num << 2));
+	__add_ptr_list(&backup, INT_PTR(loop_count << 2));
+	__add_ptr_list(&backup, INT_PTR(final_pass << 2));
 
-	__add_ptr_list(&backup, big_statement_stack, 0);
-	__add_ptr_list(&backup, big_expression_stack, 0);
-	__add_ptr_list(&backup, big_condition_stack, 0);
-	__add_ptr_list(&backup, switch_expr_stack, 0);
+	__add_ptr_list(&backup, big_statement_stack);
+	__add_ptr_list(&backup, big_expression_stack);
+	__add_ptr_list(&backup, big_condition_stack);
+	__add_ptr_list(&backup, switch_expr_stack);
 
-	__add_ptr_list(&backup, cur_func_sym, 0);
+	__add_ptr_list(&backup, cur_func_sym);
 
-	__add_ptr_list(&backup, __prev_stmt, 0);
-	__add_ptr_list(&backup, __cur_stmt, 0);
-	__add_ptr_list(&backup, __next_stmt, 0);
-
+	__add_ptr_list(&backup, __prev_stmt);
+	__add_ptr_list(&backup, __cur_stmt);
+	__add_ptr_list(&backup, __next_stmt);
 }
 
 static void *pop_backup(void)
--- old/usr/src/tools/smatch/src/smatch_function_hooks.c	Mon Nov 18 13:19:17 2019
+++ new/usr/src/tools/smatch/src/smatch_function_hooks.c	Mon Nov 18 13:19:17 2019
@@ -373,7 +373,7 @@
 	db_info->ret_state = state;
 }
 
-static bool fake_a_param_assignment(struct expression *expr, const char *return_str)
+static bool fake_a_param_assignment(struct expression *expr, const char *return_str, struct smatch_state *orig)
 {
 	struct expression *arg, *left, *right, *tmp, *fake_assign;
 	char *p;
@@ -437,6 +437,26 @@
 	__in_fake_parameter_assign++;
 	__split_expr(fake_assign);
 	__in_fake_parameter_assign--;
+
+	/*
+	 * If the return is "0-65531[$0->nla_len - 4]" the faked expression
+	 * is maybe (-4)-65531 but we know it is in the 0-65531 range so both
+	 * parts have to be considered.  We use _nomod() because it's not really
+	 * another modification, it's just a clarification.
+	 *
+	 */
+	if (estate_rl(orig)) {
+		struct smatch_state *faked;
+		struct range_list *rl;
+
+		faked = get_extra_state(left);
+		if (estate_rl(faked)) {
+			rl = rl_intersection(estate_rl(faked), estate_rl(orig));
+			if (rl)
+				set_extra_expr_nomod(expr, alloc_estate_rl(rl));
+		}
+	}
+
 	return true;
 }
 
@@ -449,9 +469,10 @@
 		return;
 
 	state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
-	set_extra_expr_mod(expr, state);
+	if (!fake_a_param_assignment(db_info->expr, db_info->ret_str, state))
+		set_extra_expr_mod(expr, state);
+
 	db_info->ret_state = NULL;
-	fake_a_param_assignment(db_info->expr, db_info->ret_str);
 	db_info->ret_str = NULL;
 }
 
@@ -1092,7 +1113,6 @@
 		__add_return_to_param_mapping(db_info->expr, ret_str);
 	}
 
-
 	FOR_EACH_PTR(db_return_states_list, tmp) {
 		if (tmp->type == type)
 			tmp->callback(db_info->expr, param, key, value);
@@ -1170,12 +1190,14 @@
 static void match_function_call(struct expression *expr)
 {
 	struct call_back_list *call_backs;
+	struct expression *fn;
 
-	if (expr->fn->type == EXPR_SYMBOL && expr->fn->symbol) {
-		call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
+	fn = strip_expr(expr->fn);
+	if (fn->type == EXPR_SYMBOL && fn->symbol) {
+		call_backs = search_callback(func_hash, (char *)fn->symbol->ident->name);
 		if (call_backs)
 			call_call_backs(call_backs, REGULAR_CALL,
-					expr->fn->symbol->ident->name, expr);
+					fn->symbol->ident->name, expr);
 	}
 	db_return_states_call(expr);
 }
--- old/usr/src/tools/smatch/src/smatch_function_ptrs.c	Mon Nov 18 13:19:18 2019
+++ new/usr/src/tools/smatch/src/smatch_function_ptrs.c	Mon Nov 18 13:19:18 2019
@@ -50,6 +50,46 @@
 	return alloc_string(arg->string->data);
 }
 
+static int xxx_is_array(struct expression *expr)
+{
+	struct symbol *type;
+
+	expr = strip_expr(expr);
+	if (!expr)
+		return 0;
+
+	if (expr->type == EXPR_PREOP && expr->op == '*') {
+		expr = strip_expr(expr->unop);
+		if (!expr)
+			return 0;
+		if (expr->type == EXPR_BINOP && expr->op == '+')
+			return 1;
+	}
+
+	if (expr->type != EXPR_BINOP || expr->op != '+')
+		return 0;
+
+	type = get_type(expr->left);
+	if (!type)
+		return 0;
+	if (type->type != SYM_ARRAY && type->type != SYM_PTR)
+		return 0;
+
+	return 1;
+}
+
+static struct expression *xxx_get_array_base(struct expression *expr)
+{
+	if (!xxx_is_array(expr))
+		return NULL;
+	expr = strip_expr(expr);
+	if (expr->type == EXPR_PREOP && expr->op == '*')
+		expr = strip_expr(expr->unop);
+	if (expr->type != EXPR_BINOP || expr->op != '+')
+		return NULL;
+	return strip_parens(expr->left);
+}
+
 static char *get_array_ptr(struct expression *expr)
 {
 	struct expression *array;
@@ -57,7 +97,7 @@
 	char *name;
 	char buf[256];
 
-	array = get_array_base(expr);
+	array = xxx_get_array_base(expr);
 
 	if (array) {
 		name = get_member_name(array);
@@ -78,7 +118,7 @@
 	}
 
 	expr = get_assigned_expr(expr);
-	array = get_array_base(expr);
+	array = xxx_get_array_base(expr);
 	if (!array)
 		return NULL;
 	name = expr_to_var(array);
@@ -141,7 +181,7 @@
 {
 	char *name;
 
-	if (is_zero(expr))
+	if (expr_is_zero(expr))
 		return NULL;
 
 	expr = strip_expr(expr);
@@ -255,6 +295,12 @@
 		if (!type)
 			return 0;
 	}
+	/* pointer to a pointer */
+	if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
+		type = get_real_base_type(type);
+		if (!type)
+			return 0;
+	}
 	if (type->type == SYM_FN)
 		return 1;
 	if (type == &ulong_ctype && expr->type == EXPR_DEREF)
@@ -279,7 +325,8 @@
 		right = strip_expr(right->unop);
 
 	if (right->type != EXPR_SYMBOL &&
-	    right->type != EXPR_DEREF)
+	    right->type != EXPR_DEREF &&
+	    right->type != EXPR_CALL)
 		return;
 
 	if (!can_hold_function_ptr(right) ||
--- old/usr/src/tools/smatch/src/smatch_helper.c	Mon Nov 18 13:19:18 2019
+++ new/usr/src/tools/smatch/src/smatch_helper.c	Mon Nov 18 13:19:18 2019
@@ -39,6 +39,19 @@
 	return tmp;
 }
 
+char *alloc_string_newline(const char *str)
+{
+	char *tmp;
+	int len;
+
+	if (!str)
+		return NULL;
+	len = strlen(str);
+	tmp = malloc(len + 2);
+	snprintf(tmp, len + 2, "%s\n", str);
+	return tmp;
+}
+
 void free_string(char *str)
 {
 	free(str);
@@ -276,10 +289,13 @@
 		return;
 	}
 	case EXPR_VALUE: {
+		sval_t sval = {};
 		char tmp[25];
 
 		*complicated = 1;
-		snprintf(tmp, 25, "%lld", expr->value);
+		if (!get_value(expr, &sval))
+			return;
+		snprintf(tmp, 25, "%s", sval_to_numstr(sval));
 		append(buf, tmp, len);
 		return;
 	}
@@ -589,7 +605,7 @@
 	return 0;
 }
 
-int is_zero(struct expression *expr)
+int expr_is_zero(struct expression *expr)
 {
 	sval_t sval;
 
@@ -818,24 +834,21 @@
 	return 0;
 }
 
-int getting_address(void)
+int getting_address(struct expression *expr)
 {
-	struct expression *tmp;
-	int i = 0;
-	int dot_ops = 0;
+	int deref_count = 0;
 
-	FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
-		if (!i++)
-			continue;
-		if (tmp->type == EXPR_PREOP && tmp->op == '(')
-			continue;
-		if (tmp->op == '.' && !dot_ops++)
-			continue;
-		if (tmp->op == '&')
-			return 1;
-		return 0;
-	} END_FOR_EACH_PTR_REVERSE(tmp);
-	return 0;
+	while ((expr = expr_get_parent_expr(expr))) {
+		if (expr->type == EXPR_PREOP && expr->op == '*') {
+			/* &foo->bar->baz dereferences "foo->bar" */
+			if (deref_count == 0)
+				deref_count++;
+			return false;
+		}
+		if (expr->type == EXPR_PREOP && expr->op == '&')
+			return true;
+	}
+	return false;
 }
 
 int get_struct_and_member(struct expression *expr, const char **type, const char **member)
--- old/usr/src/tools/smatch/src/smatch_hooks.c	Mon Nov 18 13:19:19 2019
+++ new/usr/src/tools/smatch/src/smatch_hooks.c	Mon Nov 18 13:19:19 2019
@@ -18,6 +18,7 @@
 #include "smatch.h"
 
 enum data_type {
+	NO_DATA,
 	EXPR_PTR,
 	STMT_PTR,
 	SYMBOL_PTR,
@@ -26,16 +27,62 @@
 
 struct hook_container {
 	int hook_type;
-	enum data_type data_type;
+	int owner;
 	void *fn;
 };
 ALLOCATOR(hook_container, "hook functions");
 DECLARE_PTR_LIST(hook_func_list, struct hook_container);
+
+typedef void (expr_func)(struct expression *expr);
+typedef void (stmt_func)(struct statement *stmt);
+typedef void (sym_func)(struct symbol *sym);
+typedef void (sym_list_func)(struct symbol_list *sym_list);
+
 static struct hook_func_list *merge_funcs;
 static struct hook_func_list *unmatched_state_funcs;
 static struct hook_func_list *hook_array[NUM_HOOKS] = {};
-void (**pre_merge_hooks)(struct sm_state *sm);
+static const enum data_type data_types[NUM_HOOKS] = {
+	[EXPR_HOOK] = EXPR_PTR,
+	[EXPR_HOOK_AFTER] = EXPR_PTR,
+	[STMT_HOOK] = STMT_PTR,
+	[STMT_HOOK_AFTER] = STMT_PTR,
+	[SYM_HOOK] = EXPR_PTR,
+	[STRING_HOOK] = EXPR_PTR,
+	[DECLARATION_HOOK] = SYMBOL_PTR,
+	[ASSIGNMENT_HOOK] = EXPR_PTR,
+	[ASSIGNMENT_HOOK_AFTER] = EXPR_PTR,
+	[RAW_ASSIGNMENT_HOOK] = EXPR_PTR,
+	[GLOBAL_ASSIGNMENT_HOOK] = EXPR_PTR,
+	[CALL_ASSIGNMENT_HOOK] = EXPR_PTR,
+	[MACRO_ASSIGNMENT_HOOK] = EXPR_PTR,
+	[BINOP_HOOK] = EXPR_PTR,
+	[OP_HOOK] = EXPR_PTR,
+	[LOGIC_HOOK] = EXPR_PTR,
+	[PRELOOP_HOOK] = STMT_PTR,
+	[CONDITION_HOOK] = EXPR_PTR,
+	[SELECT_HOOK] = EXPR_PTR,
+	[WHOLE_CONDITION_HOOK] = EXPR_PTR,
+	[FUNCTION_CALL_HOOK] = EXPR_PTR,
+	[CALL_HOOK_AFTER_INLINE] = EXPR_PTR,
+	[FUNCTION_CALL_HOOK_AFTER_DB] = EXPR_PTR,
+	[DEREF_HOOK] = EXPR_PTR,
+	[CASE_HOOK] = NO_DATA,
+	[ASM_HOOK] = STMT_PTR,
+	[CAST_HOOK] = EXPR_PTR,
+	[SIZEOF_HOOK] = EXPR_PTR,
+	[BASE_HOOK] = SYMBOL_PTR,
+	[FUNC_DEF_HOOK] = SYMBOL_PTR,
+	[AFTER_DEF_HOOK] = SYMBOL_PTR,
+	[END_FUNC_HOOK] = SYMBOL_PTR,
+	[AFTER_FUNC_HOOK] = SYMBOL_PTR,
+	[RETURN_HOOK] = EXPR_PTR,
+	[INLINE_FN_START] = EXPR_PTR,
+	[INLINE_FN_END] = EXPR_PTR,
+	[END_FILE_HOOK] = SYM_LIST_PTR,
+};
 
+void (**pre_merge_hooks)(struct sm_state *cur, struct sm_state *other);
+
 struct scope_container {
 	void *fn;
 	void *data;
@@ -51,116 +98,7 @@
 
 	container->hook_type = type;
 	container->fn = func;
-	switch (type) {
-	case EXPR_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case STMT_HOOK:
-		container->data_type = STMT_PTR;
-		break;
-	case STMT_HOOK_AFTER:
-		container->data_type = STMT_PTR;
-		break;
-	case SYM_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case STRING_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case DECLARATION_HOOK:
-		container->data_type = SYMBOL_PTR;
-		break;
-	case ASSIGNMENT_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case ASSIGNMENT_HOOK_AFTER:
-		container->data_type = EXPR_PTR;
-		break;
-	case RAW_ASSIGNMENT_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case GLOBAL_ASSIGNMENT_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case CALL_ASSIGNMENT_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case MACRO_ASSIGNMENT_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case BINOP_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case OP_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case LOGIC_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case PRELOOP_HOOK:
-		container->data_type = STMT_PTR;
-		break;
-	case CONDITION_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case SELECT_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case WHOLE_CONDITION_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case FUNCTION_CALL_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case CALL_HOOK_AFTER_INLINE:
-		container->data_type = EXPR_PTR;
-		break;
-	case FUNCTION_CALL_HOOK_AFTER_DB:
-		container->data_type = EXPR_PTR;
-		break;
-	case DEREF_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case CASE_HOOK:
-		/* nothing needed */
-		break;
-	case ASM_HOOK:
-		container->data_type = STMT_PTR;
-		break;
-	case CAST_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case SIZEOF_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case BASE_HOOK:
-		container->data_type = SYMBOL_PTR;
-		break;
-	case FUNC_DEF_HOOK:
-		container->data_type = SYMBOL_PTR;
-		break;
-	case AFTER_DEF_HOOK:
-		container->data_type = SYMBOL_PTR;
-		break;
-	case END_FUNC_HOOK:
-		container->data_type = SYMBOL_PTR;
-		break;
-	case AFTER_FUNC_HOOK:
-		container->data_type = SYMBOL_PTR;
-		break;
-	case RETURN_HOOK:
-		container->data_type = EXPR_PTR;
-		break;
-	case INLINE_FN_START:
-		container->data_type = EXPR_PTR;
-		break;
-	case INLINE_FN_END:
-		container->data_type = EXPR_PTR;
-		break;
-	case END_FILE_HOOK:
-		container->data_type = SYM_LIST_PTR;
-		break;
-	}
+
 	add_ptr_list(&hook_array[type], container);
 }
 
@@ -167,7 +105,7 @@
 void add_merge_hook(int client_id, merge_func_t *func)
 {
 	struct hook_container *container = __alloc_hook_container(0);
-	container->data_type = client_id;
+	container->owner = client_id;
 	container->fn = func;
 	add_ptr_list(&merge_funcs, container);
 }
@@ -175,44 +113,34 @@
 void add_unmatched_state_hook(int client_id, unmatched_func_t *func)
 {
 	struct hook_container *container = __alloc_hook_container(0);
-	container->data_type = client_id;
+	container->owner = client_id;
 	container->fn = func;
 	add_ptr_list(&unmatched_state_funcs, container);
 }
 
-void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *sm))
+void add_pre_merge_hook(int client_id, void (*hook)(struct sm_state *cur, struct sm_state *other))
 {
 	pre_merge_hooks[client_id] = hook;
 }
 
-static void pass_to_client(void *fn)
-{
-	typedef void (expr_func)();
-	((expr_func *) fn)();
-}
-
 static void pass_expr_to_client(void *fn, void *data)
 {
-	typedef void (expr_func)(struct expression *expr);
-	((expr_func *) fn)((struct expression *) data);
+	((expr_func *)fn)((struct expression *)data);
 }
 
 static void pass_stmt_to_client(void *fn, void *data)
 {
-	typedef void (stmt_func)(struct statement *stmt);
-	((stmt_func *) fn)((struct statement *) data);
+	((stmt_func *)fn)((struct statement *)data);
 }
 
 static void pass_sym_to_client(void *fn, void *data)
 {
-	typedef void (sym_func)(struct symbol *sym);
-	((sym_func *) fn)((struct symbol *) data);
+	((sym_func *)fn)((struct symbol *)data);
 }
 
 static void pass_sym_list_to_client(void *fn, void *data)
 {
-	typedef void (sym_func)(struct symbol_list *sym_list);
-	((sym_func *) fn)((struct symbol_list *) data);
+	((sym_list_func *)fn)((struct symbol_list *)data);
 }
 
 void __pass_to_client(void *data, enum hook_type type)
@@ -219,9 +147,8 @@
 {
 	struct hook_container *container;
 
-
 	FOR_EACH_PTR(hook_array[type], container) {
-		switch (container->data_type) {
+		switch (data_types[type]) {
 		case EXPR_PTR:
 			pass_expr_to_client(container->fn, data);
 			break;
@@ -238,15 +165,6 @@
 	} END_FOR_EACH_PTR(container);
 }
 
-void __pass_to_client_no_data(enum hook_type type)
-{
-	struct hook_container *container;
-
-	FOR_EACH_PTR(hook_array[type], container) {
-		pass_to_client(container->fn);
-	} END_FOR_EACH_PTR(container);
-}
-
 void __pass_case_to_client(struct expression *switch_expr,
 			   struct range_list *rl)
 {
@@ -255,7 +173,7 @@
 	struct hook_container *container;
 
 	FOR_EACH_PTR(hook_array[CASE_HOOK], container) {
-		((case_func *) container->fn)(switch_expr, rl);
+		((case_func *)container->fn)(switch_expr, rl);
 	} END_FOR_EACH_PTR(container);
 }
 
@@ -264,7 +182,7 @@
 	struct hook_container *tmp;
 
 	FOR_EACH_PTR(merge_funcs, tmp) {
-		if (tmp->data_type == client_id)
+		if (tmp->owner == client_id)
 			return 1;
 	} END_FOR_EACH_PTR(tmp);
 	return 0;
@@ -285,8 +203,8 @@
 	}
 
 	FOR_EACH_PTR(merge_funcs, tmp) {
-		if (tmp->data_type == owner)
-			return ((merge_func_t *) tmp->fn)(s1, s2);
+		if (tmp->owner == owner)
+			return ((merge_func_t *)tmp->fn)(s1, s2);
 	} END_FOR_EACH_PTR(tmp);
 	return &undefined;
 }
@@ -296,19 +214,19 @@
 	struct hook_container *tmp;
 
 	FOR_EACH_PTR(unmatched_state_funcs, tmp) {
-		if (tmp->data_type == sm->owner)
-			return ((unmatched_func_t *) tmp->fn)(sm);
+		if (tmp->owner == sm->owner)
+			return ((unmatched_func_t *)tmp->fn)(sm);
 	} END_FOR_EACH_PTR(tmp);
 	return &undefined;
 }
 
-void call_pre_merge_hook(struct sm_state *sm)
+void call_pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
-	if (sm->owner >= num_checks)
+	if (cur->owner >= num_checks)
 		return;
 
-	if (pre_merge_hooks[sm->owner])
-		pre_merge_hooks[sm->owner](sm);
+	if (pre_merge_hooks[cur->owner])
+		pre_merge_hooks[cur->owner](cur, other);
 }
 
 static struct scope_hook_list *pop_scope_hook_list(struct scope_hook_stack **stack)
@@ -355,7 +273,7 @@
 
 	hook_list = pop_scope_hook_list(&scope_hooks);
 	FOR_EACH_PTR(hook_list, tmp) {
-		((scope_hook *) tmp->fn)(tmp->data);
+		((scope_hook *)tmp->fn)(tmp->data);
 		__free_scope_container(tmp);
 	} END_FOR_EACH_PTR(tmp);
 }
--- old/usr/src/tools/smatch/src/smatch_implied.c	Mon Nov 18 13:19:19 2019
+++ new/usr/src/tools/smatch/src/smatch_implied.c	Mon Nov 18 13:19:19 2019
@@ -58,7 +58,6 @@
  * a pool:  a pool is an slist that has been merged with another slist.
  */
 
-#include <sys/time.h>
 #include <time.h>
 #include "smatch.h"
 #include "smatch_slist.h"
@@ -71,6 +70,11 @@
 #define implied_debug 0
 #define DIMPLIED(msg...) do { if (implied_debug) printf(msg); } while (0)
 
+bool debug_implied(void)
+{
+	return implied_debug;
+}
+
 /*
  * tmp_range_list():
  * It messes things up to free range list allocations.  This helper fuction
@@ -298,13 +302,14 @@
 {
 	int free_checked = 0;
 	struct state_list *checked_states = NULL;
-	struct timeval now;
+	struct timeval now, diff;
 
 	if (!sm)
 		return;
 
 	gettimeofday(&now, NULL);
-	if (now.tv_usec - start_time->tv_usec > 1000000) {
+	timersub(&now, start_time, &diff);
+	if (diff.tv_sec >= 1) {
 		if (implied_debug) {
 			sm_msg("debug: %s: implications taking too long.  (%s %s %s)",
 			       __func__, sm->state->name, show_special(comparison), show_rl(rl));
@@ -451,7 +456,7 @@
 	struct sm_state *left;
 	struct sm_state *right;
 	int removed = 0;
-	struct timeval now;
+	struct timeval now, diff;
 
 	if (!sm)
 		return NULL;
@@ -458,7 +463,8 @@
 	if (*bail)
 		return NULL;
 	gettimeofday(&now, NULL);
-	if (now.tv_usec - start->tv_usec > 3000000) {
+	timersub(&now, start, &diff);
+	if (diff.tv_sec >= 3) {
 		DIMPLIED("%s: implications taking too long: %s\n", __func__, sm_state_info(sm));
 		*bail = 1;
 		return NULL;
@@ -599,14 +605,6 @@
 	*false_states = filter_stack(sm, pre_stree, true_stack, false_stack);
 	free_slist(&true_stack);
 	free_slist(&false_stack);
-	if (implied_debug) {
-		printf("These are the implied states for the true path: (%s (%s) %s %s)\n",
-		       sm->name, sm->state->name, show_special(comparison), show_rl(rl));
-		__print_stree(*true_states);
-		printf("These are the implied states for the false path: (%s (%s) %s %s)\n",
-		       sm->name, sm->state->name, show_special(comparison), show_rl(rl));
-		__print_stree(*false_states);
-	}
 
 	gettimeofday(&time_after, NULL);
 	sec = time_after.tv_sec - time_before.tv_sec;
@@ -797,6 +795,12 @@
 				   struct stree **implied_true,
 				   struct stree **implied_false)
 {
+	sval_t sval;
+
+	/* If the expression is known then it has no implications.  */
+	if (get_implied_value(expr, &sval))
+		return true;
+
 	if (expr->type == EXPR_COMPARE)
 		return handle_comparison(expr, implied_true, implied_false);
 	else
@@ -883,6 +887,18 @@
 {
 	struct sm_state *sm;
 
+	if (implied_debug &&
+	    (expr || saved_implied_true || saved_implied_false)) {
+		char *name;
+
+		name = expr_to_str(expr);
+		printf("These are the implied states for the true path: (%s)\n", name);
+		__print_stree(saved_implied_true);
+		printf("These are the implied states for the false path: (%s)\n", name);
+		__print_stree(saved_implied_false);
+		free_string(name);
+	}
+
 	FOR_EACH_SM(saved_implied_true, sm) {
 		__set_true_false_sm(sm, NULL);
 	} END_FOR_EACH_SM(sm);
--- old/usr/src/tools/smatch/src/smatch_integer_overflow.c	Mon Nov 18 13:19:19 2019
+++ new/usr/src/tools/smatch/src/smatch_integer_overflow.c	Mon Nov 18 13:19:19 2019
@@ -184,7 +184,7 @@
 	struct smatch_state *state;
 	char *name;
 	struct symbol *sym;
-	int ret;
+	int ret = 1;
 
 	type = get_type(expr);
 	if (!type)
--- old/usr/src/tools/smatch/src/smatch_kernel_user_data.c	Mon Nov 18 13:19:20 2019
+++ new/usr/src/tools/smatch/src/smatch_kernel_user_data.c	Mon Nov 18 13:19:20 2019
@@ -83,31 +83,23 @@
 	return alloc_estate_empty();
 }
 
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
-	struct smatch_state *user;
+	struct smatch_state *user = cur->state;
 	struct smatch_state *extra;
 	struct smatch_state *state;
 	struct range_list *rl;
-	sval_t dummy;
-	sval_t sval_100;
 
-	sval_100.value = 100;
-	sval_100.type = &int_ctype;
-
-	user = __get_state(my_id, sm->name, sm->sym);
-	if (!user || !estate_rl(user))
-		return;
-	extra = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
+	extra = __get_state(SMATCH_EXTRA, cur->name, cur->sym);
 	if (!extra)
 		return;
 	rl = rl_intersection(estate_rl(user), estate_rl(extra));
-	if (rl_to_sval(rl, &dummy))
-		rl = NULL;
 	state = alloc_estate_rl(clone_rl(rl));
-	if (estate_capped(user) || is_capped_var_sym(sm->name, sm->sym))
+	if (estate_capped(user) || is_capped_var_sym(cur->name, cur->sym))
 		estate_set_capped(state);
-	set_state(my_id, sm->name, sm->sym, state);
+	if (estate_treat_untagged(user))
+		estate_set_treat_untagged(state);
+	set_state(my_id, cur->name, cur->sym, state);
 }
 
 static void extra_nomod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
@@ -124,6 +116,8 @@
 	new = alloc_estate_rl(rl);
 	if (estate_capped(user))
 		estate_set_capped(new);
+	if (estate_treat_untagged(user))
+		estate_set_treat_untagged(new);
 	set_state(my_id, name, sym, new);
 }
 
@@ -181,6 +175,28 @@
 	return true;  /* not actually user data */
 }
 
+bool user_rl_treat_untagged(struct expression *expr)
+{
+	struct smatch_state *state;
+	struct range_list *rl;
+	sval_t sval;
+
+	expr = strip_expr(expr);
+	if (!expr)
+		return false;
+	if (get_value(expr, &sval))
+		return true;
+
+	state = get_state_expr(my_id, expr);
+	if (state)
+		return estate_treat_untagged(state);
+
+	if (get_user_rl(expr, &rl))
+		return false;  /* uncapped user data */
+
+	return true;  /* not actually user data */
+}
+
 static void tag_inner_struct_members(struct expression *expr, struct symbol *member)
 {
 	struct expression *edge_member;
@@ -546,7 +562,7 @@
 		return 0;
 
 	name = expr_to_var(expr->right);
-	if (!name || strcmp(name, "__val_gu") != 0)
+	if (!name || (strcmp(name, "__val_gu") != 0 && strcmp(name, "__gu_val") != 0))
 		goto free;
 	set_state_expr(my_id, expr->left, alloc_estate_whole(get_type(expr->left)));
 	ret = 1;
@@ -582,6 +598,8 @@
 		state = alloc_estate_rl(rl);
 		if (user_rl_capped(binop_expr))
 			estate_set_capped(state);
+		if (user_rl_treat_untagged(expr->left))
+			estate_set_treat_untagged(state);
 		set_state_expr(my_id, expr->left, state);
 		return true;
 	}
@@ -623,8 +641,11 @@
 
 	rl = cast_rl(get_type(expr->left), rl);
 	state = alloc_estate_rl(rl);
+
 	if (user_rl_capped(expr->right))
 		estate_set_capped(state);
+	if (user_rl_treat_untagged(expr->right))
+		estate_set_treat_untagged(state);
 	set_state_expr(my_id, expr->left, state);
 
 	return;
@@ -660,15 +681,10 @@
 static struct range_list *strip_negatives(struct range_list *rl)
 {
 	sval_t min = rl_min(rl);
-	sval_t minus_one;
-	sval_t over;
+	sval_t minus_one = { .type = rl_type(rl), .value = -1 };
+	sval_t over = { .type = rl_type(rl), .value = INT_MAX + 1ULL };
 	sval_t max = sval_type_max(rl_type(rl));
 
-	minus_one.type = rl_type(rl);
-	minus_one.value = INT_MAX + 1ULL;
-	over.type = rl_type(rl);
-	over.value = -1;
-
 	if (!rl)
 		return NULL;
 
@@ -1020,8 +1036,10 @@
 	if (!get_user_rl(expr, &rl))
 		return NULL;
 	rl = cast_rl(type, rl);
-	snprintf(buf, sizeof(buf), "%s%s",
-		 show_rl(rl), user_rl_capped(expr) ? "[c]" : "");
+	snprintf(buf, sizeof(buf), "%s%s%s",
+		 show_rl(rl),
+		 user_rl_capped(expr) ? "[c]" : "",
+		 user_rl_treat_untagged(expr) ? "[u]" : "");
 	return buf;
 }
 
@@ -1093,8 +1111,9 @@
 	if (!rl)
 		return;
 
-	snprintf(buf, sizeof(buf), "%s%s", show_rl(rl),
-		 estate_capped(sm->state) ? "[c]" : "");
+	snprintf(buf, sizeof(buf), "%s%s%s", show_rl(rl),
+		 estate_capped(sm->state) ? "[c]" : "",
+		 estate_treat_untagged(sm->state) ? "[u]" : "");
 	sql_insert_caller_info(call, USER_DATA, param, printed_name, buf);
 }
 
@@ -1133,6 +1152,13 @@
 	return false;
 }
 
+static bool param_data_treat_untagged(const char *value)
+{
+	if (strstr(value, ",u") || strstr(value, "[u"))
+		return true;
+	return false;
+}
+
 static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
 {
 	struct range_list *rl = NULL;
@@ -1180,6 +1206,8 @@
 	state = alloc_estate_rl(rl);
 	if (param_data_capped(value) || is_capped(expr))
 		estate_set_capped(state);
+	if (param_data_treat_untagged(value) || sym->ctype.as == 5)
+		estate_set_treat_untagged(state);
 	set_state(my_id, fullname, sym, state);
 }
 
@@ -1252,6 +1280,8 @@
 	state = alloc_estate_rl(rl);
 	if (param_data_capped(value))
 		estate_set_capped(state);
+	if (param_data_treat_untagged(value))
+		estate_set_treat_untagged(state);
 	set_state(my_id, name, sym, state);
 free:
 	free_string(name);
@@ -1359,9 +1389,10 @@
 		if (strcmp(param_name, "$") == 0)  /* The -1 param is handled after the loop */
 			continue;
 
-		snprintf(buf, sizeof(buf), "%s%s",
+		snprintf(buf, sizeof(buf), "%s%s%s",
 			 show_rl(estate_rl(sm->state)),
-			 estate_capped(sm->state) ? "[c]" : "");
+			 estate_capped(sm->state) ? "[c]" : "",
+			 estate_treat_untagged(sm->state) ? "[u]" : "");
 		sql_insert_return_states(return_id, return_ranges,
 					 func_gets_user_data ? USER_DATA_SET : USER_DATA,
 					 param, param_name, buf);
@@ -1381,9 +1412,10 @@
 			return_found = true;
 		if (strcmp(param_name, "*$") == 0)
 			pointed_at_found = true;
-		snprintf(buf, sizeof(buf), "%s%s",
+		snprintf(buf, sizeof(buf), "%s%s%s",
 			 show_rl(estate_rl(sm->state)),
-			 estate_capped(sm->state) ? "[c]" : "");
+			 estate_capped(sm->state) ? "[c]" : "",
+			 estate_treat_untagged(sm->state) ? "[u]" : "");
 		sql_insert_return_states(return_id, return_ranges,
 					 func_gets_user_data ? USER_DATA_SET : USER_DATA,
 					 -1, param_name, buf);
@@ -1391,8 +1423,10 @@
 
 	/* This if for "return ntohl(foo);" */
 	if (!return_found && get_user_rl(expr, &rl)) {
-		snprintf(buf, sizeof(buf), "%s%s",
-			 show_rl(rl), user_rl_capped(expr) ? "[c]" : "");
+		snprintf(buf, sizeof(buf), "%s%s%s",
+			 show_rl(rl),
+			 user_rl_capped(expr) ? "[c]" : "",
+			 user_rl_treat_untagged(expr) ? "[u]" : "");
 		sql_insert_return_states(return_id, return_ranges,
 					 func_gets_user_data ? USER_DATA_SET : USER_DATA,
 					 -1, "$", buf);
@@ -1512,3 +1546,4 @@
 		return;
 	select_caller_info_hook(set_called, INTERNAL);
 }
+
--- old/usr/src/tools/smatch/src/smatch_local_values.c	Mon Nov 18 13:19:20 2019
+++ /dev/null	Mon Nov 18 13:19:20 2019
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2013 Oracle.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
- */
-
-#include "scope.h"
-#include "smatch.h"
-#include "smatch_slist.h"
-#include "smatch_extra.h"
-
-static int my_id;
-
-/*
- * I'm going to store the states of local data at the end of each function.
- * Then at the end of the file, I'll combine the possible range lists for
- * each state and store the value in the on-disk database.
- *
- * One issue is that when I read the data back from the in-memory database at
- * the end of the file, then I don't have access to type information.  I'll just
- * cast everything to "long long" for now, I guess.  We'll see how that works.
- */
-
-static char *db_vals;
-static int get_vals(void *unused, int argc, char **argv, char **azColName)
-{
-	db_vals = alloc_string(argv[0]);
-	return 0;
-}
-
-static int is_array_symbol(struct expression *expr)
-{
-	struct symbol *type;
-
-	if (!expr || expr->type != EXPR_SYMBOL)
-		return 0;
-	type = get_type(expr);
-	if (!type)
-		return 0;
-	if (type->type == SYM_ARRAY)
-		return 1;
-	return 0;
-}
-
-int get_local_rl(struct expression *expr, struct range_list **rl)
-{
-	char *name;
-	struct range_list *tmp;
-
-	if (!is_static(expr))
-		return 0;
-	if (is_array_symbol(expr))
-		return 0;
-	name = expr_to_var(expr);
-	if (!name)
-		return 0;
-
-	db_vals = NULL;
-	run_sql(get_vals, NULL,
-		"select value from local_values where file = '%s' and variable = '%s';",
-		get_filename(), name);
-	free_string(name);
-	if (!db_vals)
-		return 0;
-	str_to_rl(&llong_ctype, db_vals, &tmp);
-	*rl = cast_rl(get_type(expr), tmp);
-	free_string(db_vals);
-
-	return 1;
-}
-
-int get_local_max_helper(struct expression *expr, sval_t *sval)
-{
-	struct range_list *rl;
-
-	if (!get_local_rl(expr, &rl))
-		return 0;
-	*sval = rl_max(rl);
-	return 1;
-}
-
-int get_local_min_helper(struct expression *expr, sval_t *sval)
-{
-	struct range_list *rl;
-
-	if (!get_local_rl(expr, &rl))
-		return 0;
-	*sval = rl_min(rl);
-	return 1;
-}
-
-static struct smatch_state *unmatched_state(struct sm_state *sm)
-{
-	return alloc_estate_empty();
-}
-
-static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
-{
-	struct smatch_state *old;
-	struct smatch_state *new;
-
-	if (!sym || !(sym->ctype.modifiers & MOD_STATIC))
-		return;
-	old = get_state(my_id, name, sym);
-	if (old)
-		new = merge_estates(old, state);
-	else
-		new = state;
-	set_state(my_id, name, sym, new);
-}
-
-static void process_states(void)
-{
-	struct sm_state *sm;
-	struct smatch_state *extra;
-	struct range_list *rl;
-
-	FOR_EACH_SM(__get_cur_stree(), sm) {
-		if (sm->owner != my_id)
-			continue;
-		extra = get_state(SMATCH_EXTRA, sm->name, sm->sym);
-		if (extra && estate_rl(extra))
-			rl = rl_intersection(estate_rl(sm->state), estate_rl(extra));
-		else
-			rl = estate_rl(sm->state);
-		rl = cast_rl(&llong_ctype, rl);
-		mem_sql(NULL, NULL,
-			"insert into local_values values ('%s', '%s', '%s', %lu);",
-			get_filename(), sm->name, show_rl(rl),
-			(unsigned long)sm->sym);
-	} END_FOR_EACH_SM(sm);
-}
-
-static int get_initial_value_sym(struct symbol *sym, char *name, sval_t *sval)
-{
-	struct expression *expr_symbol, *deref, *tmp;
-	char *member_name;
-
-	if (!sym)
-		return 0;
-
-	if (!sym->initializer) {
-		*sval = sval_type_val(&llong_ctype, 0);
-		return 1;
-	}
-	if (sym->initializer->type != EXPR_INITIALIZER)
-		return get_value(sym->initializer, sval);
-
-	expr_symbol = symbol_expression(sym);
-	FOR_EACH_PTR(sym->initializer->expr_list, tmp) {
-		if (tmp->type != EXPR_IDENTIFIER) /* how to handle arrays?? */
-			continue;
-		deref = member_expression(expr_symbol, '.', tmp->expr_ident);
-		member_name = expr_to_var(deref);
-		if (!member_name)
-			continue;
-		if (strcmp(name, member_name) == 0) {
-			free_string(member_name);
-			return get_value(tmp->ident_expression, sval);
-		}
-		free_string(member_name);
-	} END_FOR_EACH_PTR(tmp);
-
-	return 0;
-}
-
-static char *cur_name;
-static struct symbol *cur_symbol;
-static struct range_list *cur_rl;
-static void add_current_local(void)
-{
-	sval_t initial;
-
-	if (!get_initial_value_sym(cur_symbol, cur_name, &initial)) {
-		free_string(cur_name);
-		cur_name = NULL;
-		cur_rl = NULL;
-		return;
-	}
-	add_range(&cur_rl, initial, initial);
-	if (!is_whole_rl(cur_rl))
-		sql_insert_local_values(cur_name, show_rl(cur_rl));
-	free_string(cur_name);
-	cur_name = NULL;
-	cur_rl = NULL;
-}
-
-static int save_final_values(void *unused, int argc, char **argv, char **azColName)
-{
-	char *name = argv[0];
-	char *sym_str = argv[1];
-	char *value = argv[2];
-	struct range_list *rl;
-
-	if (!cur_name) {
-		cur_name = alloc_string(name);
-		cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10);
-	} else if (strcmp(cur_name, name) != 0) {
-		add_current_local();
-		cur_name = alloc_string(name);
-		cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10);
-		cur_rl = NULL;
-	}
-
-	str_to_rl(&llong_ctype, value, &rl);
-	cur_rl = rl_union(cur_rl, rl);
-
-	return 0;
-}
-
-static void match_end_file(struct symbol_list *sym_list)
-{
-	mem_sql(save_final_values, NULL,
-		"select distinct variable, symbol, value from local_values order by variable;");
-	if (cur_name)
-		add_current_local();
-}
-
-void register_local_values(int id)
-{
-	my_id = id;
-
-	if (!option_info)
-		return;
-
-	set_dynamic_states(my_id);
-	add_extra_mod_hook(&extra_mod_hook);
-	add_unmatched_state_hook(my_id, &unmatched_state);
-	add_merge_hook(my_id, &merge_estates);
-	all_return_states_hook(&process_states);
-	add_hook(match_end_file, END_FILE_HOOK);
-	mem_sql(NULL, NULL, "alter table local_values add column symbol integer;");
-}
--- old/usr/src/tools/smatch/src/smatch_math.c	Mon Nov 18 13:19:20 2019
+++ new/usr/src/tools/smatch/src/smatch_math.c	Mon Nov 18 13:19:20 2019
@@ -31,6 +31,8 @@
 static sval_t zero  = {.type = &int_ctype, {.value = 0} };
 static sval_t one   = {.type = &int_ctype, {.value = 1} };
 
+static int fast_math_only;
+
 struct range_list *rl_zero(void)
 {
 	static struct range_list *zero_perm;
@@ -856,7 +858,7 @@
 		return get_rl_sval(expr->cond_false, implied, recurse_cnt, res, res_sval);
 
 	/* this becomes a problem with deeply nested conditional statements */
-	if (low_on_memory())
+	if (fast_math_only || low_on_memory())
 		return false;
 
 	type = get_type(expr);
@@ -947,8 +949,6 @@
 		state = get_real_absolute_state(expr);
 		if (state && state->data && !estate_is_whole(state))
 			return clone_rl(estate_rl(state));
-		if (get_local_rl(expr, &rl) && !is_whole_rl(rl))
-			return rl;
 		if (get_mtag_rl(expr, &rl))
 			return rl;
 		if (get_db_type_rl(expr, &rl) && !is_whole_rl(rl))
@@ -1008,8 +1008,6 @@
 		if (!state) {
 			if (implied == RL_HARD)
 				return false;
-			if (get_local_rl(expr, res))
-				return true;
 			if (get_mtag_rl(expr, res))
 				return true;
 			if (get_db_type_rl(expr, res))
@@ -1060,8 +1058,6 @@
 			return true;
 		}
 
-		if (get_local_rl(expr, res))
-			return true;
 		if (get_mtag_rl(expr, res))
 			return true;
 		if (get_db_type_rl(expr, res))
@@ -1516,6 +1512,16 @@
 	memset(cached_results, 0, sizeof(cached_results));
 }
 
+void set_fast_math_only(void)
+{
+	fast_math_only++;
+}
+
+void clear_fast_math_only(void)
+{
+	fast_math_only--;
+}
+
 /*
  * Don't cache EXPR_VALUE because values are fast already.
  *
@@ -1760,6 +1766,12 @@
 	if (!expr)
 		return 0;
 
+	if (__inline_fn && get_param_num(expr) >= 0) {
+		if (get_implied_value(expr, &tmp) && tmp.value)
+			return 1;
+		return 0;
+	}
+
 	if (get_value(expr, &tmp) && tmp.value)
 		return 1;
 
@@ -1768,10 +1780,18 @@
 
 int known_condition_false(struct expression *expr)
 {
+	sval_t tmp;
+
 	if (!expr)
 		return 0;
 
-	if (is_zero(expr))
+	if (__inline_fn && get_param_num(expr) >= 0) {
+		if (get_implied_value(expr, &tmp) && tmp.value == 0)
+			return 1;
+		return 0;
+	}
+
+	if (expr_is_zero(expr))
 		return 1;
 
 	return 0;
--- old/usr/src/tools/smatch/src/smatch_mem_tracker.c	Mon Nov 18 13:19:21 2019
+++ new/usr/src/tools/smatch/src/smatch_mem_tracker.c	Mon Nov 18 13:19:21 2019
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Oracle.
+ * Copyright 2019 Joyent, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,15 +19,18 @@
 #include "smatch.h"
 #include <fcntl.h>
 #include <unistd.h>
+#ifdef __sun
 #include <sys/procfs.h>
+#endif
 
 static int my_id;
-static int my_fd = -2;
 
 static unsigned long max_size;
 
+#ifdef __sun
 unsigned long get_mem_kb(void)
 {
+	static int my_fd = -2;
 	prpsinfo_t pbuf;
 
 	if (my_fd == -2) {
@@ -43,7 +47,25 @@
 
 	return (pbuf.pr_rssize);
 }
+#else
+unsigned long get_mem_kb(void)
+{
+	FILE *file;
+	char buf[1024] = "0";
+	unsigned long size;
 
+	file = fopen("/proc/self/statm", "r");
+	if (!file)
+	        return 0;
+	fread(buf, 1, sizeof(buf), file);
+	fclose(file);
+
+	size = strtoul(buf, NULL, 10);
+	size = size * sysconf(_SC_PAGESIZE) / 1024;
+	return size;
+}
+#endif
+
 static void match_end_func(struct symbol *sym)
 {
 	unsigned long size;
--- old/usr/src/tools/smatch/src/smatch_modification_hooks.c	Mon Nov 18 13:19:21 2019
+++ new/usr/src/tools/smatch/src/smatch_modification_hooks.c	Mon Nov 18 13:19:21 2019
@@ -143,9 +143,6 @@
 	char *name;
 	struct symbol *sym;
 
-	if (late == LATE)
-		update_mtag_data(expr);
-
 	name = expr_to_known_chunk_sym(expr, &sym);
 	if (!name)
 		goto free;
@@ -156,7 +153,7 @@
 
 static void db_param_add(struct expression *expr, int param, char *key, char *value)
 {
-	struct expression *arg, *gen_expr;
+	struct expression *arg;
 	char *name, *other_name;
 	struct symbol *sym, *other_sym;
 
@@ -169,10 +166,6 @@
 	if (!arg)
 		return;
 
-	gen_expr = gen_expression_from_key(arg, key);
-	if (gen_expr)
-		update_mtag_data(gen_expr);
-
 	name = get_variable_from_key(arg, key, &sym);
 	if (!name || !sym)
 		goto free;
@@ -226,23 +219,14 @@
 static void asm_expr(struct statement *stmt, int late)
 {
 	struct expression *expr;
-	int state = 0;
 
 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
-		switch (state) {
-		case 0: /* identifier */
-		case 1: /* constraint */
-			state++;
+		if (expr->type != EXPR_ASM_OPERAND)
 			continue;
-		case 2: /* expression */
-			state = 0;
-			call_modification_hooks(expr, NULL, late);
-			continue;
-		}
+		call_modification_hooks(expr->expr, NULL, late);
 	} END_FOR_EACH_PTR(expr);
 }
 
-
 static void match_assign_early(struct expression *expr)
 {
 	match_assign(expr, EARLY);
--- old/usr/src/tools/smatch/src/smatch_mtag.c	Mon Nov 18 13:19:21 2019
+++ new/usr/src/tools/smatch/src/smatch_mtag.c	Mon Nov 18 13:19:22 2019
@@ -347,7 +347,7 @@
 			if (tmp < 0)
 				return 0;
 			tmp_offset += tmp;
-			expr = expr->deref;
+			expr = strip_expr(expr->deref);
 		}
 		*offset = tmp_offset;
 		if (expr->type == EXPR_PREOP && expr->op == '*') {
--- old/usr/src/tools/smatch/src/smatch_mtag_data.c	Mon Nov 18 13:19:22 2019
+++ new/usr/src/tools/smatch/src/smatch_mtag_data.c	Mon Nov 18 13:19:22 2019
@@ -69,6 +69,18 @@
 	return 0;
 }
 
+static bool is_ignored_macro(struct expression *expr)
+{
+	char *macro;
+
+	macro = get_macro_name(expr->pos);
+	if (!macro)
+		return false;
+	if (strcmp(macro, "EXPORT_SYMBOL") == 0)
+		return true;
+	return false;
+}
+
 static void insert_mtag_data(mtag_t tag, int offset, struct range_list *rl)
 {
 	rl = clone_rl_permanent(rl);
@@ -79,14 +91,33 @@
 		tag, offset, DATA_VALUE, (unsigned long)rl);
 }
 
-void update_mtag_data(struct expression *expr)
+static bool invalid_type(struct symbol *type)
 {
-	struct range_list *orig, *new, *rl;
+	if (!type)
+		return true;
+	if (type == &void_ctype)
+		return true;
+	if (type->type == SYM_STRUCT ||
+	    type->type == SYM_ARRAY ||
+	    type->type == SYM_UNION)
+		return true;
+	return false;
+}
+
+void update_mtag_data(struct expression *expr, struct smatch_state *state)
+{
+	struct range_list *orig, *new;
 	struct symbol *type;
 	char *name;
 	mtag_t tag;
 	int offset;
 
+	if (!expr)
+		return;
+	if (is_local_variable(expr))
+		return;
+	if (is_ignored_macro(expr))
+		return;
 	name = expr_to_var(expr);
 	if (is_kernel_param(name)) {
 		free_string(name);
@@ -98,15 +129,11 @@
 		return;
 
 	type = get_type(expr);
-	if ((offset == 0) &&
-	    (!type || type == &void_ctype ||
-	     type->type == SYM_STRUCT || type->type == SYM_UNION || type->type == SYM_ARRAY))
+	if (offset == 0 && invalid_type(type))
 		return;
 
-	get_absolute_rl(expr, &rl);
-
 	orig = select_orig(tag, offset);
-	new = rl_union(orig, rl);
+	new = rl_union(orig, estate_rl(state));
 	insert_mtag_data(tag, offset, new);
 }
 
@@ -117,6 +144,8 @@
 	int offset;
 	char *name;
 
+	if (is_ignored_macro(expr))
+		return;
 	name = expr_to_var(expr->left);
 	if (is_kernel_param(name)) {
 		free_string(name);
@@ -188,10 +217,6 @@
 	int ret;
 	int i;
 
-	if (!type || type == &void_ctype ||
-	    (type->type == SYM_STRUCT || type->type == SYM_ARRAY || type->type == SYM_UNION))
-		return 0;
-
 	for (i = 0; i < ARRAY_SIZE(cached_results); i++) {
 		if (merged == cached_results[i].tag) {
 			if (cached_results[i].rl) {
@@ -235,6 +260,8 @@
 	mtag_t tag;
 	int offset;
 
+	if (is_local_variable(expr))
+		return 0;
 	if (!expr_to_mtag_offset(expr, &tag, &offset))
 		return 0;
 	if (offset >= MTAG_OFFSET_MASK)
@@ -241,7 +268,7 @@
 		return 0;
 
 	type = get_type(expr);
-	if (!type)
+	if (invalid_type(type))
 		return 0;
 
 	return get_rl_from_mtag_offset(tag, offset, type, rl);
--- old/usr/src/tools/smatch/src/smatch_nul_terminator.c	Mon Nov 18 13:19:22 2019
+++ new/usr/src/tools/smatch/src/smatch_nul_terminator.c	Mon Nov 18 13:19:22 2019
@@ -69,6 +69,24 @@
 	set_terminated(array, &terminated);
 }
 
+static struct smatch_state *get_terminated_state_var_sym(const char *name, struct symbol *sym)
+{
+	struct sm_state *sm, *tmp;
+
+	sm = get_sm_state(my_id, name, sym);
+	if (!sm)
+		return NULL;
+	if (sm->state == &terminated || sm->state == &unterminated)
+		return sm->state;
+
+	FOR_EACH_PTR(sm->possible, tmp) {
+		if (tmp->state == &unterminated)
+			return &unterminated;
+	} END_FOR_EACH_PTR(tmp);
+
+	return NULL;
+}
+
 static struct smatch_state *get_terminated_state(struct expression *expr)
 {
 	struct sm_state *sm, *tmp;
@@ -240,6 +258,13 @@
 	free_string(name);
 }
 
+bool is_nul_terminated_var_sym(const char *name, struct symbol *sym)
+{
+	if (get_terminated_state_var_sym(name, sym) == &terminated)
+		return 1;
+	return 0;
+}
+
 bool is_nul_terminated(struct expression *expr)
 {
 	if (get_terminated_state(expr) == &terminated)
--- old/usr/src/tools/smatch/src/smatch_param_filter.c	Mon Nov 18 13:19:23 2019
+++ new/usr/src/tools/smatch/src/smatch_param_filter.c	Mon Nov 18 13:19:23 2019
@@ -66,29 +66,28 @@
 	if (parent_is_gone_var_sym(sm->name, sm->sym))
 		return alloc_estate_empty();
 
-	state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+	state = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
 	if (state)
 		return state;
 	return alloc_estate_whole(estate_type(sm->state));
 }
 
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
 {
-	struct smatch_state *extra, *mine;
+	struct smatch_state *extra;
 	struct range_list *rl;
 
-	if (estate_rl(sm->state))
+	if (estate_rl(other->state))
 		return;
 
-	extra = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+	extra = get_state(SMATCH_EXTRA, cur->name, cur->sym);
 	if (!extra)
 		return;
-	mine = get_state(my_id, sm->name, sm->sym);
 
-	rl = rl_intersection(estate_rl(extra), estate_rl(mine));
-	if (rl_equiv(rl, estate_rl(mine)))
+	rl = rl_intersection(estate_rl(extra), estate_rl(cur->state));
+	if (rl_equiv(rl, estate_rl(cur->state)))
 		return;
-	set_state(my_id, sm->name, sm->sym, alloc_estate_rl(clone_rl(rl)));
+	set_state(my_id, cur->name, cur->sym, alloc_estate_rl(clone_rl(rl)));
 }
 
 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
--- old/usr/src/tools/smatch/src/smatch_param_limit.c	Mon Nov 18 13:19:23 2019
+++ new/usr/src/tools/smatch/src/smatch_param_limit.c	Mon Nov 18 13:19:23 2019
@@ -66,7 +66,7 @@
 {
 	struct smatch_state *state;
 
-	state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+	state = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
 	if (state)
 		return state;
 	return alloc_estate_whole(estate_type(sm->state));
@@ -116,15 +116,14 @@
 	 * pointer and it's like, "Sorry bro, that's not possible."
 	 *
 	 */
-	rl = rl_intersection(estate_rl(state), valid_ptr_rl);
-	if (!rl)
-		return estate_rl(state);
-
+	rl = estate_rl(state);
 	FOR_EACH_PTR(rl, drange) {
 		if (drange->min.value != drange->max.value)
 			continue;
-		if (drange->min.value > -4096 && drange->min.value <= 0)
+		if (drange->min.value == 0)
 			continue;
+		if (is_err_ptr(drange->min))
+			continue;
 		return rl_union(valid_ptr_rl, rl);
 	} END_FOR_EACH_PTR(drange);
 
--- old/usr/src/tools/smatch/src/smatch_param_set.c	Mon Nov 18 13:19:23 2019
+++ new/usr/src/tools/smatch/src/smatch_param_set.c	Mon Nov 18 13:19:23 2019
@@ -130,6 +130,24 @@
 	free_string(name);
 }
 
+static char *get_two_dots(const char *name)
+{
+	static char buf[80];
+	int i, cnt = 0;
+
+	for (i = 0; i < sizeof(buf); i++) {
+		if (name[i] == '.') {
+			cnt++;
+			if (cnt >= 2) {
+				buf[i] = '\0';
+				return buf;
+			}
+		}
+		buf[i] = name[i];
+	}
+	return NULL;
+}
+
 /*
  * This relies on the fact that these states are stored so that
  * foo->bar is before foo->bar->baz.
@@ -154,7 +172,7 @@
 	return 0;
 }
 
-static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
+static void print_return_value_param_helper(int return_id, char *return_ranges, struct expression *expr, int limit)
 {
 	struct sm_state *sm;
 	struct smatch_state *extra;
@@ -164,11 +182,13 @@
 	struct string_list *set_list = NULL;
 	char *math_str;
 	char buf[256];
+	char two_dot[80] = "";
+	int count = 0;
 
 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
 		if (!estate_rl(sm->state))
 			continue;
-		extra = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+		extra = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
 		if (extra) {
 			rl = rl_intersection(estate_rl(sm->state), estate_rl(extra));
 			if (!rl)
@@ -196,7 +216,19 @@
 			insert_string(&set_list, (char *)sm->name);
 			continue;
 		}
+		if (limit) {
+			char *new = get_two_dots(param_name);
 
+			if (new) {
+				if (strcmp(new, two_dot) == 0)
+					continue;
+				strncpy(two_dot, new, sizeof(two_dot));
+				sql_insert_return_states(return_id, return_ranges,
+					 PARAM_SET, param, new, "s64min-s64max");
+				continue;
+			}
+		}
+
 		math_str = get_value_in_terms_of_parameter_math_var_sym(sm->name, sm->sym);
 		if (math_str) {
 			snprintf(buf, sizeof(buf), "%s[%s]", show_rl(rl), math_str);
@@ -215,6 +247,8 @@
 		sql_insert_return_states(return_id, return_ranges,
 					 param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET,
 					 param, param_name, show_rl(rl));
+		if (limit && ++count > limit)
+			break;
 
 	} END_FOR_EACH_SM(sm);
 
@@ -221,22 +255,58 @@
 	free_ptr_list((struct ptr_list **)&set_list);
 }
 
+static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
+{
+	print_return_value_param_helper(return_id, return_ranges, expr, 0);
+}
+
+void print_limited_param_set(int return_id, char *return_ranges, struct expression *expr)
+{
+	print_return_value_param_helper(return_id, return_ranges, expr, 1000);
+}
+
+static int possibly_empty(struct sm_state *sm)
+{
+	struct sm_state *tmp;
+
+	FOR_EACH_PTR(sm->possible, tmp) {
+		if (strcmp(tmp->name, "") == 0)
+			return 1;
+	} END_FOR_EACH_PTR(tmp);
+	return 0;
+}
+
 int param_was_set_var_sym(const char *name, struct symbol *sym)
 {
 	struct sm_state *sm;
-	int len;
+	char buf[80];
+	int len, i;
 
-	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
-		if (sm->sym != sym)
+	if (!name)
+		return 0;
+
+	len = strlen(name);
+	if (len >= sizeof(buf))
+		len = sizeof(buf) - 1;
+
+	for (i = 0; i <= len; i++) {
+		if (name[i] != '-' && name[i] != '\0')
 			continue;
-		len = strlen(sm->name);
-		if (strncmp(sm->name, name, len) != 0)
+
+		memcpy(buf, name, i);
+		buf[i] = '\0';
+
+		sm = get_sm_state(my_id, buf, sym);
+		if (!sm)
 			continue;
-		if (name[len] == '\0' ||
-		    name[len] == '-')
-			return 1;
-	} END_FOR_EACH_SM(sm);
+		if (possibly_empty(sm))
+			continue;
+		return 1;
+	}
 
+	if (name[0] == '*')
+		return param_was_set_var_sym(name + 1, sym);
+
 	return 0;
 }
 
--- old/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c	Mon Nov 18 13:19:24 2019
+++ new/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c	Mon Nov 18 13:19:24 2019
@@ -76,18 +76,6 @@
 	return &merged;
 }
 
-static bool is_local_var(struct expression *expr)
-{
-	struct symbol *sym;
-
-	if (!expr || expr->type != EXPR_SYMBOL)
-		return false;
-	sym = expr->symbol;
-	if (!(sym->ctype.modifiers & MOD_TOPLEVEL))
-		return true;
-	return false;
-}
-
 static void match_assign(struct expression *expr)
 {
 	struct expression *left;
@@ -100,7 +88,7 @@
 	if (expr->op != '=')
 		return;
 	left = strip_expr(expr->left);
-	if (is_local_var(left))
+	if (is_local_variable(left))
 		return;
 	right_sym = expr_to_sym(expr->right);
 	if (!right_sym)
--- old/usr/src/tools/smatch/src/smatch_param_used.c	Mon Nov 18 13:19:24 2019
+++ new/usr/src/tools/smatch/src/smatch_param_used.c	Mon Nov 18 13:19:24 2019
@@ -31,12 +31,16 @@
 
 	if (!option_info)
 		return;
-	if (__in_fake_assign || __in_fake_parameter_assign || __in_function_def)
+
+	if (__in_fake_assign || __in_fake_parameter_assign || __in_function_def || __in_unmatched_hook)
 		return;
 
 	arg = get_param_num_from_sym(sym);
-	if (arg >= 0)
-		set_state_stree(&used_stree, my_id, name, sym, &used);
+	if (arg < 0)
+		return;
+	if (param_was_set_var_sym(name, sym))
+		return;
+	set_state_stree(&used_stree, my_id, name, sym, &used);
 }
 
 static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused)
@@ -45,13 +49,19 @@
 	char *name;
 	int arg_nr;
 
+	if (!option_info)
+		return;
+
 	name = get_variable_from_key(arg, key, &sym);
 	if (!name || !sym)
 		goto free;
 
 	arg_nr = get_param_num_from_sym(sym);
-	if (arg_nr >= 0)
-		set_state_stree(&used_stree, my_id, name, sym, &used);
+	if (arg_nr < 0)
+		goto free;
+	if (param_was_set_var_sym(name, sym))
+		goto free;
+	set_state_stree(&used_stree, my_id, name, sym, &used);
 free:
 	free_string(name);
 }
--- old/usr/src/tools/smatch/src/smatch_parse_call_math.c	Mon Nov 18 13:19:24 2019
+++ new/usr/src/tools/smatch/src/smatch_parse_call_math.c	Mon Nov 18 13:19:24 2019
@@ -588,6 +588,9 @@
 		BUF_SIZE, sql_filter);
 	if (!buf_size_recipe || strcmp(buf_size_recipe, "invalid") == 0)
 		return NULL;
+	/* Known sizes should be handled in smatch_buf_size.c */
+	if (!strchr(buf_size_recipe, '$'))
+		return NULL;
 	return swap_format(expr, buf_size_recipe);
 }
 
@@ -601,26 +604,10 @@
 	set_state_expr(my_id, expr->left, alloc_state_sname(sname));
 }
 
-static void match_returns_call(int return_id, char *return_ranges, struct expression *call)
+const char *get_allocation_math(struct expression *expr)
 {
-	char *sname;
-
-	sname = get_allocation_recipe_from_call(call);
-	if (option_debug)
-		sm_msg("sname = %s", sname);
-	if (!sname)
-		return;
-
-	sql_insert_return_states(return_id, return_ranges, BUF_SIZE, -1, "",
-			sname);
-}
-
-static void print_returned_allocations(int return_id, char *return_ranges, struct expression *expr)
-{
 	struct expression *tmp;
 	struct smatch_state *state;
-	struct symbol *sym;
-	char *name;
 	int cnt = 0;
 
 	expr = strip_expr(expr);
@@ -630,25 +617,16 @@
 		expr = strip_expr(tmp);
 	}
 	if (!expr)
-		return;
+		return NULL;
 
-	if (expr->type == EXPR_CALL) {
-		match_returns_call(return_id, return_ranges, expr);
-		return;
-	}
+	if (expr->type == EXPR_CALL)
+		return get_allocation_recipe_from_call(expr);
 
-	name = expr_to_var_sym(expr, &sym);
-	if (!name || !sym)
-		goto free;
-
-	state = get_state(my_id, name, sym);
+	state = get_state_expr(my_id, expr);
 	if (!state || !state->data)
-		goto free;
+		return NULL;
 
-	sql_insert_return_states(return_id, return_ranges, BUF_SIZE, -1, "",
-			state->name);
-free:
-	free_string(name);
+	return state->name;
 }
 
 void register_parse_call_math(int id)
@@ -663,6 +641,5 @@
 		add_function_assign_hook(alloc_functions[i].func, &match_alloc,
 				         INT_PTR(alloc_functions[i].param));
 	add_hook(&match_call_assignment, CALL_ASSIGNMENT_HOOK);
-	add_split_return_callback(print_returned_allocations);
 }
 
--- old/usr/src/tools/smatch/src/smatch_ranges.c	Mon Nov 18 13:19:25 2019
+++ new/usr/src/tools/smatch/src/smatch_ranges.c	Mon Nov 18 13:19:25 2019
@@ -26,7 +26,7 @@
 			 "permanent ranges", perm_data_range);
 __DECLARE_ALLOCATOR(struct ptr_list, rl_ptrlist);
 
-static bool is_err_ptr(sval_t sval)
+bool is_err_ptr(sval_t sval)
 {
 	if (option_project != PROJ_KERNEL)
 		return false;
@@ -249,6 +249,13 @@
 	c++;
 
 	param = strtoll(c, (char **)&c, 10);
+	/*
+	 * FIXME: handle parameter math.  [==$1 + 100]
+	 *
+	 */
+	if (*c == ' ')
+		return 0;
+
 	if (*c == ',' || *c == ']')
 		c++; /* skip the ']' character */
 	if (endp)
@@ -342,6 +349,9 @@
 	struct symbol *cast_type;
 	sval_t min, max;
 
+	if (comparison == UNKNOWN_COMPARISON)
+		return;
+
 	cast_type = rl_type(left_orig);
 	if (sval_type_max(rl_type(left_orig)).uvalue < sval_type_max(rl_type(right_orig)).uvalue)
 		cast_type = rl_type(right_orig);
@@ -394,6 +404,10 @@
 	struct range_list *casted_start, *right_orig;
 	int comparison;
 
+	/* For when we have a function that takes a function pointer. */
+	if (!call || call->type != EXPR_CALL)
+		return start_rl;
+
 	if (!str_to_comparison_arg_helper(c, call, &comparison, &arg, endp))
 		return start_rl;
 
@@ -491,6 +505,21 @@
 	return c;
 }
 
+static struct range_list *get_param_return_rl(struct expression *call, const char *call_math)
+{
+	struct expression *arg;
+	int param;
+
+	call_math += 3;
+	param = atoi(call_math);
+
+	arg = get_argument_from_call_expr(call->args, param);
+	if (!arg)
+		return NULL;
+
+	return db_return_vals_no_args(arg);
+}
+
 static void str_to_rl_helper(struct expression *call, struct symbol *type, const char *str, const char **endp, struct range_list **rl)
 {
 	struct range_list *rl_tmp = NULL;
@@ -592,6 +621,12 @@
 		goto cast;
 
 	call_math = jump_to_call_math(value);
+	if (call_math && call_math[0] == 'r') {
+		math_rl = get_param_return_rl(call, call_math);
+		if (math_rl)
+			rl = rl_intersection(rl, math_rl);
+		goto cast;
+	}
 	if (call_math && parse_call_math_rl(call, call_math, &math_rl)) {
 		rl = rl_intersection(rl, math_rl);
 		goto cast;
@@ -651,7 +686,7 @@
 {
 	struct data_range *drange;
 
-	if (ptr_list_empty(rl))
+	if (ptr_list_empty((struct ptr_list *)rl))
 		return 0;
 	drange = first_ptr_list((struct ptr_list *)rl);
 	if (sval_is_min(drange->min) && sval_is_max(drange->max))
@@ -682,7 +717,7 @@
 {
 	struct data_range *drange;
 
-	if (ptr_list_empty(rl))
+	if (ptr_list_empty((struct ptr_list *)rl))
 		return 0;
 	drange = first_ptr_list((struct ptr_list *)rl);
 	if (sval_unsigned(drange->min) &&
@@ -704,7 +739,7 @@
 
 	ret.type = &llong_ctype;
 	ret.value = LLONG_MIN;
-	if (ptr_list_empty(rl))
+	if (ptr_list_empty((struct ptr_list *)rl))
 		return ret;
 	drange = first_ptr_list((struct ptr_list *)rl);
 	return drange->min;
@@ -717,7 +752,7 @@
 
 	ret.type = &llong_ctype;
 	ret.value = LLONG_MAX;
-	if (ptr_list_empty(rl))
+	if (ptr_list_empty((struct ptr_list *)rl))
 		return ret;
 	drange = last_ptr_list((struct ptr_list *)rl);
 	return drange->max;
@@ -1190,6 +1225,8 @@
 	struct data_range *tmp_left, *tmp_right;
 	struct symbol *type;
 
+	if (comparison == UNKNOWN_COMPARISON)
+		return 1;
 	if (!get_implied_rl(left, &rl_left))
 		return 1;
 	if (!get_implied_rl(right, &rl_right))
@@ -1247,7 +1284,7 @@
 	struct data_range *left_tmp, *right_tmp;
 	struct symbol *type;
 
-	if (!left_ranges || !right_ranges)
+	if (!left_ranges || !right_ranges || comparison == UNKNOWN_COMPARISON)
 		return 1;
 
 	type = rl_type(left_ranges);
@@ -1273,7 +1310,7 @@
 	struct data_range *left_tmp, *right_tmp;
 	struct symbol *type;
 
-	if (!left_ranges || !right_ranges)
+	if (!left_ranges || !right_ranges || comparison == UNKNOWN_COMPARISON)
 		return 1;
 
 	type = rl_type(left_ranges);
@@ -1847,70 +1884,23 @@
 	return ret;
 }
 
-static struct range_list *handle_AND_rl_sval(struct range_list *rl, sval_t sval)
-{
-	struct range_list *known_rl;
-	sval_t zero = { 0 };
-	sval_t min;
-
-	zero.type = sval.type;
-	zero.value = 0;
-
-	if (sm_fls64(rl_max(rl).uvalue) < find_first_zero_bit(sval.uvalue) &&
-	    sm_fls64(rl_min(rl).uvalue) < find_first_zero_bit(sval.uvalue))
-		return rl;
-
-	min = sval_lowest_set_bit(sval);
-
-	if (min.value != 0) {
-		sval_t max, mod;
-
-		max = rl_max(rl);
-		mod = sval_binop(max, '%', min);
-		if (mod.value) {
-			max = sval_binop(max, '-', mod);
-			max.value++;
-			if (max.value > 0 && sval_cmp(max, rl_max(rl)) < 0)
-				rl = remove_range(rl, max, rl_max(rl));
-		}
-	}
-
-	known_rl = alloc_rl(min, sval);
-
-	rl = rl_intersection(rl, known_rl);
-	zero = rl_min(rl);
-	zero.value = 0;
-	add_range(&rl, zero, zero);
-
-	return rl;
-}
-
-static struct range_list *fudge_AND_rl(struct range_list *rl)
-{
-	struct range_list *ret;
-	sval_t min;
-
-	min = sval_lowest_set_bit(rl_min(rl));
-	ret = clone_rl(rl);
-	add_range(&ret, min, rl_min(rl));
-
-	return ret;
-}
-
 static struct range_list *handle_AND_rl(struct range_list *left, struct range_list *right)
 {
-	sval_t sval, zero;
+	struct bit_info *one, *two;
 	struct range_list *rl;
+	sval_t min, max, zero;
+	unsigned long long bits;
 
-	if (rl_to_sval(left, &sval))
-		return handle_AND_rl_sval(right, sval);
-	if (rl_to_sval(right, &sval))
-		return handle_AND_rl_sval(left, sval);
+	one = rl_to_binfo(left);
+	two = rl_to_binfo(right);
+	bits = one->possible & two->possible;
 
-	left = fudge_AND_rl(left);
-	right = fudge_AND_rl(right);
+	max = rl_max(left);
+	max.uvalue = bits;
+	min = sval_lowest_set_bit(max);
 
-	rl = rl_intersection(left, right);
+	rl = alloc_rl(min, max);
+
 	zero = rl_min(rl);
 	zero.value = 0;
 	add_range(&rl, zero, zero);
@@ -2148,7 +2138,6 @@
 		break;
 	default:
 		sm_perror(" unhandled comparison %d", op);
-		return;
 	}
 
 	if (left_true_rl) {
--- old/usr/src/tools/smatch/src/smatch_real_absolute.c	Mon Nov 18 13:19:25 2019
+++ new/usr/src/tools/smatch/src/smatch_real_absolute.c	Mon Nov 18 13:19:25 2019
@@ -36,22 +36,32 @@
 
 static int my_id;
 
-static void pre_merge_hook(struct sm_state *sm)
+static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
 {
 	struct smatch_state *abs;
+	struct range_list *rl;
+
+	abs = get_state(my_id, name, sym);
+	if (!abs || !estate_rl(abs))
+		return;
+	rl = rl_intersection(estate_rl(abs), estate_rl(state));
+	set_state(my_id, name, sym, alloc_estate_rl(clone_rl(rl)));
+}
+
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
+{
 	struct smatch_state *extra;
 	struct range_list *rl;
 
-	extra = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+	extra = get_state(SMATCH_EXTRA, cur->name, cur->sym);
 	if (!extra || !estate_rl(extra))
 		return;
-	abs = get_state(my_id, sm->name, sm->sym);
-	if (!abs || !estate_rl(abs)) {
-		set_state(my_id, sm->name, sm->sym, clone_estate(extra));
+	if (!estate_rl(cur->state)) {
+		set_state(my_id, cur->name, cur->sym, clone_estate(extra));
 		return;
 	}
-	rl = rl_intersection(estate_rl(abs), estate_rl(extra));
-	set_state(my_id, sm->name, sm->sym, alloc_estate_rl(clone_rl(rl)));
+	rl = rl_intersection(estate_rl(cur->state), estate_rl(extra));
+	set_state(my_id, cur->name, cur->sym, alloc_estate_rl(clone_rl(rl)));
 }
 
 static struct smatch_state *empty_state(struct sm_state *sm)
@@ -59,11 +69,6 @@
 	return alloc_estate_empty();
 }
 
-static void reset(struct sm_state *sm, struct expression *mod_expr)
-{
-	set_state(my_id, sm->name, sm->sym, alloc_estate_whole(estate_type(sm->state)));
-}
-
 static int in_iterator_pre_statement(void)
 {
 	struct statement *stmt;
@@ -124,7 +129,7 @@
 
 struct smatch_state *get_real_absolute_state_var_sym(const char *name, struct symbol *sym)
 {
-	return get_state(my_id, name, sym);
+	return __get_state(my_id, name, sym);
 }
 
 void register_real_absolute(int id)
@@ -135,7 +140,7 @@
 	add_pre_merge_hook(my_id, &pre_merge_hook);
 	add_unmatched_state_hook(my_id, &empty_state);
 	add_merge_hook(my_id, &merge_estates);
-	add_modification_hook(my_id, &reset);
+	add_extra_mod_hook(&extra_mod_hook);
 
 	add_hook(&match_assign, ASSIGNMENT_HOOK);
 }
--- old/usr/src/tools/smatch/src/smatch_returns.c	Mon Nov 18 13:19:26 2019
+++ new/usr/src/tools/smatch/src/smatch_returns.c	Mon Nov 18 13:19:26 2019
@@ -59,12 +59,13 @@
 static void call_hooks(void)
 {
 	struct return_states_callback *rs_cb;
+	struct stree *orig;
 
-	__set_fake_cur_stree_fast(all_return_states);
+	orig = __swap_cur_stree(all_return_states);
 	FOR_EACH_PTR(callback_list, rs_cb) {
 		rs_cb->callback();
 	} END_FOR_EACH_PTR(rs_cb);
-	__pop_fake_cur_stree_fast();
+	__swap_cur_stree(orig);
 }
 
 static void match_return(int return_id, char *return_ranges, struct expression *expr)
@@ -116,14 +117,8 @@
 
 static void free_resources(struct symbol *sym)
 {
-	struct stree *tmp;
-
 	free_stree(&all_return_states);
-
-	FOR_EACH_PTR(return_stree_stack, tmp) {
-		free_stree(&tmp);
-	} END_FOR_EACH_PTR(tmp);
-	free_stree_stack(&return_stree_stack);
+	free_stack_and_strees(&return_stree_stack);
 }
 
 void register_returns_early(int id)
--- old/usr/src/tools/smatch/src/smatch_scripts/build_generic_data.sh	Mon Nov 18 13:19:26 2019
+++ new/usr/src/tools/smatch/src/smatch_scripts/build_generic_data.sh	Mon Nov 18 13:19:26 2019
@@ -52,8 +52,15 @@
     fi
 fi
 
-make -j${NR_CPU} CHECK="$BIN_DIR/smatch --call-tree --info --param-mapper --spammy --file-output" $TARGET
+if [[ ! -z $ARCH ]]; then
+	KERNEL_ARCH="ARCH=$ARCH"
+fi
+if [[ ! -z $CROSS_COMPILE ]] ; then
+	KERNEL_CROSS_COMPILE="CROSS_COMPILE=$CROSS_COMPILE"
+fi
 
+make $KERNEL_ARCH $KERNEL_CROSS_COMPILE -j${NR_CPU} CHECK="$BIN_DIR/smatch --call-tree --info --param-mapper --spammy --file-output" $TARGET
+
 find -name \*.c.smatch -exec cat \{\} \; -exec rm \{\} \; > smatch_warns.txt
 
 for i in $SCRIPT_DIR/gen_* ; do
--- old/usr/src/tools/smatch/src/smatch_scripts/gen_dma_funcs.sh	Mon Nov 18 13:19:26 2019
+++ new/usr/src/tools/smatch/src/smatch_scripts/gen_dma_funcs.sh	Mon Nov 18 13:19:26 2019
@@ -22,6 +22,7 @@
 echo '// generated by `gen_dma_funcs.sh`' >> $outfile
 ${bin_dir}/trace_params.pl $file usb_control_msg 6 >> $tmp
 ${bin_dir}/trace_params.pl $file usb_fill_bulk_urb 3 >> $tmp
+${bin_dir}/trace_params.pl $file dma_map_single 1 >> $tmp
 cat $tmp | sort -u > $tmp2
 mv $tmp2 $tmp
 cat $tmp $remove $remove 2> /dev/null | sort | uniq -u >> $outfile
--- old/usr/src/tools/smatch/src/smatch_scripts/gen_rosenberg_funcs.sh	Mon Nov 18 13:19:27 2019
+++ new/usr/src/tools/smatch/src/smatch_scripts/gen_rosenberg_funcs.sh	Mon Nov 18 13:19:27 2019
@@ -21,7 +21,11 @@
 echo "// list of copy_to_user function and buffer parameters." > $outfile
 echo '// generated by `gen_rosenberg_funcs.sh`' >> $outfile
 ${bin_dir}/trace_params.pl $file copy_to_user 1 >> $tmp
+${bin_dir}/trace_params.pl $file rds_info_copy 1 >> $tmp
 ${bin_dir}/trace_params.pl $file nla_put 3 >> $tmp
+${bin_dir}/trace_params.pl $file snd_timer_user_append_to_tqueue 1 >> $tmp
+${bin_dir}/trace_params.pl $file __send_signal 1 >> $tmp
+
 cat $tmp | sort -u > $tmp2
 mv $tmp2 $tmp
 cat $tmp $remove $remove 2> /dev/null | sort | uniq -u >> $outfile
--- old/usr/src/tools/smatch/src/smatch_scripts/kchecker	Mon Nov 18 13:19:27 2019
+++ new/usr/src/tools/smatch/src/smatch_scripts/kchecker	Mon Nov 18 13:19:27 2019
@@ -70,4 +70,11 @@
     rm -f $oname
 fi
 
-make C=2 $ENDIAN CHECK="$PRE $CMD $POST" $oname
+if [[ ! -z $ARCH ]]; then
+	KERNEL_ARCH="ARCH=$ARCH"
+fi
+if [[ ! -z $CROSS_COMPILE ]] ; then
+	KERNEL_CROSS_COMPILE="CROSS_COMPILE=$CROSS_COMPILE"
+fi
+
+make $KERNEL_CROSS_COMPILE $KERNEL_ARCH C=2 $ENDIAN CHECK="$PRE $CMD $POST" $oname
--- old/usr/src/tools/smatch/src/smatch_scripts/summarize_errs.sh	Mon Nov 18 13:19:27 2019
+++ new/usr/src/tools/smatch/src/smatch_scripts/summarize_errs.sh	Mon Nov 18 13:19:27 2019
@@ -28,7 +28,7 @@
     echo -n "What do you think?:  "
     read ans
     if echo $ans | grep ^$ > /dev/null ; then
-        continue
+        return
     fi 
 
     #store the result
--- old/usr/src/tools/smatch/src/smatch_scripts/test_generic.sh	Mon Nov 18 13:19:28 2019
+++ new/usr/src/tools/smatch/src/smatch_scripts/test_generic.sh	Mon Nov 18 13:19:28 2019
@@ -52,9 +52,16 @@
     exit 1
 fi
 
-make clean
+if [[ ! -z $ARCH ]]; then
+	KERNEL_ARCH="ARCH=$ARCH"
+fi
+if [[ ! -z $CROSS_COMPILE ]] ; then
+	KERNEL_CROSS_COMPILE="CROSS_COMPILE=$CROSS_COMPILE"
+fi
+
+make $KERNEL_ARCH $KERNEL_CROSS_COMPILE clean
 find -name \*.c.smatch -exec rm \{\} \;
-make -j${NR_CPU} $ENDIAN -k CHECK="$CMD --file-output $*" \
+make $KERNEL_ARCH $KERNEL_CROSS_COMPILE -j${NR_CPU} $ENDIAN -k CHECK="$CMD --file-output $*" \
 	C=1 $TARGET 2>&1 | tee $LOG
 find -name \*.c.smatch -exec cat \{\} \; -exec rm \{\} \; > $WLOG
 
--- old/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh	Mon Nov 18 13:19:28 2019
+++ new/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh	Mon Nov 18 13:19:28 2019
@@ -56,9 +56,16 @@
     exit 1
 fi
 
-make clean
+if [[ ! -z $ARCH ]]; then
+	KERNEL_ARCH="ARCH=$ARCH"
+fi
+if [[ ! -z $CROSS_COMPILE ]] ; then
+	KERNEL_CROSS_COMPILE="CROSS_COMPILE=$CROSS_COMPILE"
+fi
+
+make $KERNEL_ARCH $KERNEL_CROSS_COMPILE clean
 find -name \*.c.smatch -exec rm \{\} \;
-make -j${NR_CPU} $ENDIAN -k CHECK="$CMD -p=kernel --file-output --succeed $*" \
+make $KERNEL_ARCH $KERNEL_CROSS_COMPILE -j${NR_CPU} $ENDIAN -k CHECK="$CMD -p=kernel --file-output --succeed $*" \
 	C=1 $BUILD_PARAM $TARGET 2>&1 | tee $LOG
 BUILD_STATUS=${PIPESTATUS[0]}
 find -name \*.c.smatch -exec cat \{\} \; -exec rm \{\} \; > $WLOG
--- old/usr/src/tools/smatch/src/smatch_slist.c	Mon Nov 18 13:19:28 2019
+++ new/usr/src/tools/smatch/src/smatch_slist.c	Mon Nov 18 13:19:28 2019
@@ -41,8 +41,9 @@
 	if (!sm)
 		return "<none>";
 
-	pos = snprintf(buf, sizeof(buf), "[%s] '%s' = '%s'",
-		       check_name(sm->owner), sm->name, show_state(sm->state));
+	pos = snprintf(buf, sizeof(buf), "[%s] %s = '%s'%s",
+		       check_name(sm->owner), sm->name, show_state(sm->state),
+		       sm->merged ? " [merged]" : "");
 	if (pos > sizeof(buf))
 		goto truncate;
 
@@ -691,6 +692,8 @@
 	AvlIter one_iter;
 	AvlIter two_iter;
 
+	__set_cur_stree_readonly();
+
 	avl_iter_begin(&one_iter, *one, FORWARD);
 	avl_iter_begin(&two_iter, *two, FORWARD);
 
@@ -699,7 +702,9 @@
 			break;
 		if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
 			__set_fake_cur_stree_fast(*two);
+			__in_unmatched_hook++;
 			tmp_state = __client_unmatched_state_function(one_iter.sm);
+			__in_unmatched_hook--;
 			__pop_fake_cur_stree_fast();
 			sm = alloc_state_no_name(one_iter.sm->owner, one_iter.sm->name,
 						  one_iter.sm->sym, tmp_state);
@@ -710,7 +715,9 @@
 			avl_iter_next(&two_iter);
 		} else {
 			__set_fake_cur_stree_fast(*one);
+			__in_unmatched_hook++;
 			tmp_state = __client_unmatched_state_function(two_iter.sm);
+			__in_unmatched_hook--;
 			__pop_fake_cur_stree_fast();
 			sm = alloc_state_no_name(two_iter.sm->owner, two_iter.sm->name,
 						  two_iter.sm->sym, tmp_state);
@@ -719,6 +726,8 @@
 		}
 	}
 
+	__set_cur_stree_writable();
+
 	FOR_EACH_PTR(add_to_one, sm) {
 		avl_insert(one, sm);
 	} END_FOR_EACH_PTR(sm);
@@ -733,29 +742,38 @@
 
 static void call_pre_merge_hooks(struct stree **one, struct stree **two)
 {
-	struct sm_state *sm, *other;
+	struct sm_state *sm, *cur;
+	struct stree *new;
 
-	save_all_states();
+	__in_unmatched_hook++;
 
-	__swap_cur_stree(*one);
+	__set_fake_cur_stree_fast(*one);
+	__push_fake_cur_stree();
 	FOR_EACH_SM(*two, sm) {
-		other = get_sm_state(sm->owner, sm->name, sm->sym);
-		if (other == sm)
+		cur = get_sm_state(sm->owner, sm->name, sm->sym);
+		if (cur == sm)
 			continue;
-		call_pre_merge_hook(sm);
+		call_pre_merge_hook(cur, sm);
 	} END_FOR_EACH_SM(sm);
-	*one = clone_stree(__get_cur_stree());
+	new = __pop_fake_cur_stree();
+	overwrite_stree(new, one);
+	free_stree(&new);
+	__pop_fake_cur_stree_fast();
 
-	__swap_cur_stree(*two);
+	__set_fake_cur_stree_fast(*two);
+	__push_fake_cur_stree();
 	FOR_EACH_SM(*one, sm) {
-		other = get_sm_state(sm->owner, sm->name, sm->sym);
-		if (other == sm)
+		cur = get_sm_state(sm->owner, sm->name, sm->sym);
+		if (cur == sm)
 			continue;
-		call_pre_merge_hook(sm);
+		call_pre_merge_hook(cur, sm);
 	} END_FOR_EACH_SM(sm);
-	*two = clone_stree(__get_cur_stree());
+	new = __pop_fake_cur_stree();
+	overwrite_stree(new, two);
+	free_stree(&new);
+	__pop_fake_cur_stree_fast();
 
-	restore_all_states();
+	__in_unmatched_hook--;
 }
 
 static void clone_pool_havers_stree(struct stree **stree)
--- old/usr/src/tools/smatch/src/smatch_states.c	Mon Nov 18 13:19:29 2019
+++ new/usr/src/tools/smatch/src/smatch_states.c	Mon Nov 18 13:19:29 2019
@@ -44,6 +44,7 @@
 struct smatch_state false_state = { .name = "false" };
 
 static struct stree *cur_stree; /* current states */
+static struct stree *fast_overlay;
 
 static struct stree_stack *true_stack; /* states after a t/f branch */
 static struct stree_stack *false_stack;
@@ -80,6 +81,16 @@
 	return 0;
 }
 
+void __set_cur_stree_readonly(void)
+{
+	read_only++;
+}
+
+void __set_cur_stree_writable(void)
+{
+	read_only--;
+}
+
 struct sm_state *set_state(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
 {
 	struct sm_state *ret;
@@ -130,10 +141,12 @@
 	return ret;
 }
 
-void __swap_cur_stree(struct stree *stree)
+struct stree *__swap_cur_stree(struct stree *stree)
 {
-	free_stree(&cur_stree);
+	struct stree *orig = cur_stree;
+
 	cur_stree = stree;
+	return orig;
 }
 
 void __push_fake_cur_stree(void)
@@ -160,15 +173,18 @@
 
 void __set_fake_cur_stree_fast(struct stree *stree)
 {
-	push_stree(&pre_cond_stack, cur_stree);
-	cur_stree = stree;
-	read_only = 1;
+	if (fast_overlay) {
+		sm_perror("cannot nest fast overlay");
+		return;
+	}
+	fast_overlay = stree;
+	set_fast_math_only();
 }
 
 void __pop_fake_cur_stree_fast(void)
 {
-	cur_stree = pop_stree(&pre_cond_stack);
-	read_only = 0;
+	fast_overlay = NULL;
+	clear_fast_math_only();
 }
 
 void __merge_stree_into_cur(struct stree *stree)
@@ -289,7 +305,12 @@
 
 struct smatch_state *__get_state(int owner, const char *name, struct symbol *sym)
 {
-	return get_state_stree(cur_stree, owner, name, sym);
+	struct sm_state *sm;
+
+	sm = get_sm_state(owner, name, sym);
+	if (!sm)
+		return NULL;
+	return sm->state;
 }
 
 struct smatch_state *get_state(int owner, const char *name, struct symbol *sym)
@@ -343,6 +364,12 @@
 
 struct sm_state *get_sm_state(int owner, const char *name, struct symbol *sym)
 {
+	struct sm_state *ret;
+
+	ret = get_sm_state_stree(fast_overlay, owner, name, sym);
+	if (ret)
+		return ret;
+
 	return get_sm_state_stree(cur_stree, owner, name, sym);
 }
 
@@ -593,39 +620,39 @@
 
 void save_all_states(void)
 {
-	__add_ptr_list(&backup, cur_stree, 0);
+	__add_ptr_list(&backup, cur_stree);
 	cur_stree = NULL;
 
-	__add_ptr_list(&backup, true_stack, 0);
+	__add_ptr_list(&backup, true_stack);
 	true_stack = NULL;
-	__add_ptr_list(&backup, false_stack, 0);
+	__add_ptr_list(&backup, false_stack);
 	false_stack = NULL;
-	__add_ptr_list(&backup, pre_cond_stack, 0);
+	__add_ptr_list(&backup, pre_cond_stack);
 	pre_cond_stack = NULL;
 
-	__add_ptr_list(&backup, cond_true_stack, 0);
+	__add_ptr_list(&backup, cond_true_stack);
 	cond_true_stack = NULL;
-	__add_ptr_list(&backup, cond_false_stack, 0);
+	__add_ptr_list(&backup, cond_false_stack);
 	cond_false_stack = NULL;
 
-	__add_ptr_list(&backup, fake_cur_stree_stack, 0);
+	__add_ptr_list(&backup, fake_cur_stree_stack);
 	fake_cur_stree_stack = NULL;
 
-	__add_ptr_list(&backup, break_stack, 0);
+	__add_ptr_list(&backup, break_stack);
 	break_stack = NULL;
-	__add_ptr_list(&backup, fake_break_stack, 0);
+	__add_ptr_list(&backup, fake_break_stack);
 	fake_break_stack = NULL;
 
-	__add_ptr_list(&backup, switch_stack, 0);
+	__add_ptr_list(&backup, switch_stack);
 	switch_stack = NULL;
-	__add_ptr_list(&backup, remaining_cases, 0);
+	__add_ptr_list(&backup, remaining_cases);
 	remaining_cases = NULL;
-	__add_ptr_list(&backup, default_stack, 0);
+	__add_ptr_list(&backup, default_stack);
 	default_stack = NULL;
-	__add_ptr_list(&backup, continue_stack, 0);
+	__add_ptr_list(&backup, continue_stack);
 	continue_stack = NULL;
 
-	__add_ptr_list(&backup, goto_stack, 0);
+	__add_ptr_list(&backup, goto_stack);
 	goto_stack = NULL;
 }
 
--- old/usr/src/tools/smatch/src/smatch_struct_assignment.c	Mon Nov 18 13:19:29 2019
+++ new/usr/src/tools/smatch/src/smatch_struct_assignment.c	Mon Nov 18 13:19:29 2019
@@ -167,7 +167,8 @@
 	if (type->type != SYM_BASETYPE)
 		return;
 	right = strip_expr(right);
-	if (!right)
+	type = get_type(right);
+	if (!right || !type || type->type == SYM_ARRAY)
 		right = unknown_value_expression(left);
 	assign = assign_expression(left, '=', right);
 	split_fake_expr(assign);
@@ -404,7 +405,7 @@
 	if (expr->op != '=')
 		return;
 
-	if (is_zero(expr->right))
+	if (expr_is_zero(expr->right))
 		return;
 
 	left_type = get_type(expr->left);
--- old/usr/src/tools/smatch/src/smatch_type.c	Mon Nov 18 13:19:29 2019
+++ new/usr/src/tools/smatch/src/smatch_type.c	Mon Nov 18 13:19:29 2019
@@ -398,7 +398,7 @@
 	if (!sym || sym->type != SYM_FN)
 		return 0;
 	sym = get_base_type(sym);
-	if (sym->type == SYM_PTR)
+	if (sym && sym->type == SYM_PTR)
 		return 1;
 	return 0;
 }
@@ -496,20 +496,16 @@
 	return ret;
 }
 
-int is_local_variable(struct expression *expr)
+bool is_local_variable(struct expression *expr)
 {
 	struct symbol *sym;
-	char *name;
 
-	name = expr_to_var_sym(expr, &sym);
-	free_string(name);
-	if (!sym || !sym->scope || !sym->scope->token || !cur_func_sym)
-		return 0;
-	if (cmp_pos(sym->scope->token->pos, cur_func_sym->pos) < 0)
-		return 0;
-	if (is_static(expr))
-		return 0;
-	return 1;
+	if (!expr || expr->type != EXPR_SYMBOL || !expr->symbol)
+		return false;
+	sym = expr->symbol;
+	if (!(sym->ctype.modifiers & MOD_TOPLEVEL))
+		return true;
+	return false;
 }
 
 int types_equiv(struct symbol *one, struct symbol *two)
--- old/usr/src/tools/smatch/src/smatch_type_val.c	Mon Nov 18 13:19:30 2019
+++ new/usr/src/tools/smatch/src/smatch_type_val.c	Mon Nov 18 13:19:30 2019
@@ -227,13 +227,46 @@
 	return 1;
 }
 
-static int is_ignored_macro(void)
+static bool is_driver_data(void)
 {
+	static struct expression *prev_expr;
 	struct expression *expr;
 	char *name;
+	static bool prev_ret;
+	bool ret = false;
 
 	expr = get_faked_expression();
 	if (!expr || expr->type != EXPR_ASSIGNMENT)
+		return false;
+
+	if (expr == prev_expr)
+		return prev_ret;
+	prev_expr = expr;
+
+	name = expr_to_str(expr->right);
+	if (!name) {
+		prev_ret = false;
+		return false;
+	}
+
+	if (strstr(name, "get_drvdata(") ||
+	    strstr(name, "dev.driver_data") ||
+	    strstr(name, "dev->driver_data"))
+		ret = true;
+
+	free_string(name);
+
+	prev_ret = ret;
+	return ret;
+}
+
+static int is_ignored_macro(void)
+{
+	struct expression *expr;
+	char *name;
+
+	expr = get_faked_expression();
+	if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
 		return 0;
 	name = get_macro_name(expr->right->pos);
 	if (!name)
@@ -248,6 +281,20 @@
 		return 1;
 	if (strcmp(name, "hlist_entry") == 0)
 		return 1;
+	if (strcmp(name, "per_cpu_ptr") == 0)
+		return 1;
+	if (strcmp(name, "raw_cpu_ptr") == 0)
+		return 1;
+	if (strcmp(name, "this_cpu_ptr") == 0)
+		return 1;
+
+	if (strcmp(name, "TRACE_EVENT") == 0)
+		return 1;
+	if (strcmp(name, "DECLARE_EVENT_CLASS") == 0)
+		return 1;
+	if (strcmp(name, "DEFINE_EVENT") == 0)
+		return 1;
+
 	if (strstr(name, "for_each"))
 		return 1;
 	return 0;
@@ -266,10 +313,30 @@
 
 	if (sym_name_is("kmalloc", expr->fn))
 		return 1;
+	if (sym_name_is("vmalloc", expr->fn))
+		return 1;
+	if (sym_name_is("kvmalloc", expr->fn))
+		return 1;
+	if (sym_name_is("kmalloc_array", expr->fn))
+		return 1;
+	if (sym_name_is("vmalloc_array", expr->fn))
+		return 1;
+	if (sym_name_is("kvmalloc_array", expr->fn))
+		return 1;
+
+	if (sym_name_is("mmu_memory_cache_alloc", expr->fn))
+		return 1;
+	if (sym_name_is("kmem_alloc", expr->fn))
+		return 1;
+	if (sym_name_is("alloc_pages", expr->fn))
+		return 1;
+
 	if (sym_name_is("netdev_priv", expr->fn))
 		return 1;
 	if (sym_name_is("dev_get_drvdata", expr->fn))
 		return 1;
+	if (sym_name_is("i2c_get_clientdata", expr->fn))
+		return 1;
 
 	return 0;
 }
@@ -294,6 +361,9 @@
 	if (!left_type || !right_type)
 		return 0;
 
+	if (left_type->type == SYM_STRUCT && left_type == right_type)
+		return 1;
+
 	if (left_type->type != SYM_PTR &&
 	    left_type->type != SYM_ARRAY)
 		return 0;
@@ -396,6 +466,8 @@
 		return;
 
 	type = get_type(expr->left);
+	if (type && type->type == SYM_STRUCT)
+		return;
 	member = get_member_name(expr->left);
 	if (!member)
 		return;
@@ -416,6 +488,8 @@
 			goto free;
 		if (is_container_of())
 			goto free;
+		if (is_driver_data())
+			goto free;
 		add_fake_type_val(member, alloc_whole_rl(get_type(expr->left)), is_ignored_fake_assignment());
 		goto free;
 	}
@@ -501,24 +575,14 @@
 	struct expression *expr;
 	struct range_list *rl;
 	char *member;
-	int state = 0;
 
 	FOR_EACH_PTR(stmt->asm_outputs, expr) {
-		switch (state) {
-		case 0: /* identifier */
-		case 1: /* constraint */
-			state++;
+		member = get_member_name(expr->expr);
+		if (!member)
 			continue;
-		case 2: /* expression */
-			state = 0;
-			member = get_member_name(expr);
-			if (!member)
-				continue;
-			rl = alloc_whole_rl(get_type(expr));
-			add_type_val(member, rl);
-			free_string(member);
-			continue;
-		}
+		rl = alloc_whole_rl(get_type(expr->expr));
+		add_type_val(member, rl);
+		free_string(member);
 	} END_FOR_EACH_PTR(expr);
 }
 
@@ -542,6 +606,19 @@
 	if (!arg)
 		return;
 	type = get_member_type_from_key(arg, key);
+	/*
+	 * The situation here is that say we memset() a void pointer to zero
+	 * then that's returned to the called as "*$ = 0;" but on the caller's
+	 * side it's not void, it's a struct.
+	 *
+	 * So the question is should we be passing that slightly bogus
+	 * information back to the caller?  Maybe, maybe not, but either way we
+	 * are not going to record it here because a struct can't be zero.
+	 *
+	 */
+	if (type && type->type == SYM_STRUCT)
+		return;
+
 	if (arg->type != EXPR_PREOP || arg->op != '&')
 		return;
 	arg = strip_expr(arg->unop);
--- old/usr/src/tools/smatch/src/smatch_untracked_param.c	Mon Nov 18 13:19:30 2019
+++ new/usr/src/tools/smatch/src/smatch_untracked_param.c	Mon Nov 18 13:19:30 2019
@@ -268,31 +268,20 @@
 static void match_param_assign_in_asm(struct statement *stmt)
 {
 
-	struct expression *expr;
+	struct expression *tmp, *expr;
 	struct symbol *type;
-	int state = 0;
 	int param;
 
-	FOR_EACH_PTR(stmt->asm_inputs, expr) {
-		switch (state) {
-		case 0: /* identifier */
-		case 1: /* constraint */
-			state++;
+	FOR_EACH_PTR(stmt->asm_inputs, tmp) {
+		expr = strip_expr(tmp->expr);
+		type = get_type(expr);
+		if (!type || type->type != SYM_PTR)
 			continue;
-		case 2: /* expression */
-			state = 0;
-
-			expr = strip_expr(expr);
-			type = get_type(expr);
-			if (!type || type->type != SYM_PTR)
-				continue;
-			param = get_param_num(expr);
-			if (param < 0)
-				continue;
-			set_state_expr(my_id, expr, &untracked);
+		param = get_param_num(expr);
+		if (param < 0)
 			continue;
-		}
-	} END_FOR_EACH_PTR(expr);
+		set_state_expr(my_id, expr, &untracked);
+	} END_FOR_EACH_PTR(tmp);
 }
 
 static void match_inline_start(struct expression *expr)
--- old/usr/src/tools/smatch/src/sort.c	Mon Nov 18 13:19:30 2019
+++ new/usr/src/tools/smatch/src/sort.c	Mon Nov 18 13:19:30 2019
@@ -138,7 +138,7 @@
 	// 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) {
+	       cmp (PTR_ENTRY_NOTAG(b1, b1->nr - 1), PTR_ENTRY_NOTAG(b2,0)) < 0) {
 		// printf ("Skipping whole block.\n");
 		BEEN_THERE('H');
 		b1 = b1->next;
@@ -149,8 +149,8 @@
 	}
 
 	while (1) {
-		const void *d1 = PTR_ENTRY(b1,i1);
-		const void *d2 = PTR_ENTRY(b2,i2);
+		const void *d1 = PTR_ENTRY_NOTAG(b1,i1);
+		const void *d2 = PTR_ENTRY_NOTAG(b2,i2);
 
 		assert (i1 >= 0 && i1 < b1->nr);
 		assert (i2 >= 0 && i2 < b2->nr);
--- /dev/null	Mon Nov 18 13:19:31 2019
+++ new/usr/src/tools/smatch/src/sparse-llvm-dis	Mon Nov 18 13:19:31 2019
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# For testing sparse-llvm emitted bytecode
+
+set +e
+
+DIS=$("${LLVM_CONFIG:-llvm-config}" --bindir)/llvm-dis
+
+if [ $# -eq 0 ]; then
+	echo "$(basename $0): no input files"
+	exit 1
+fi
+
+DIRNAME=$(dirname $0)
+$DIRNAME/sparse-llvm "$@" | "$DIS" | grep -v '^target '
--- old/usr/src/tools/smatch/src/sparse-llvm.c	Mon Nov 18 13:19:31 2019
+++ new/usr/src/tools/smatch/src/sparse-llvm.c	Mon Nov 18 13:19:31 2019
@@ -21,62 +21,35 @@
 
 struct function {
 	LLVMBuilderRef			builder;
-	LLVMTypeRef			type;
 	LLVMValueRef			fn;
 	LLVMModuleRef			module;
 };
 
-static inline bool symbol_is_fp_type(struct symbol *sym)
-{
-	if (!sym)
-		return false;
+static LLVMTypeRef symbol_type(struct symbol *sym);
 
-	return sym->ctype.base_type == &fp_type;
-}
-
-static LLVMTypeRef symbol_type(LLVMModuleRef module, struct symbol *sym);
-
-static LLVMTypeRef func_return_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef func_return_type(struct symbol *sym)
 {
-	return symbol_type(module, sym->ctype.base_type);
+	return symbol_type(sym->ctype.base_type);
 }
 
-static LLVMTypeRef sym_func_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_func_type(struct symbol *sym)
 {
-	LLVMTypeRef *arg_type;
-	LLVMTypeRef func_type;
-	LLVMTypeRef ret_type;
+	int n_arg = symbol_list_size(sym->arguments);
+	LLVMTypeRef *arg_type = calloc(n_arg, sizeof(LLVMTypeRef));
+	LLVMTypeRef ret_type = func_return_type(sym);
 	struct symbol *arg;
-	int n_arg = 0;
+	int idx = 0;
 
-	/* to avoid strangeness with varargs [for now], we build
-	 * the function and type anew, for each call.  This
-	 * is probably wrong.  We should look up the
-	 * symbol declaration info.
-	 */
-
-	ret_type = func_return_type(module, sym);
-
-	/* count args, build argument type information */
 	FOR_EACH_PTR(sym->arguments, arg) {
-		n_arg++;
-	} END_FOR_EACH_PTR(arg);
-
-	arg_type = calloc(n_arg, sizeof(LLVMTypeRef));
-
-	int idx = 0;
-	FOR_EACH_PTR(sym->arguments, arg) {
 		struct symbol *arg_sym = arg->ctype.base_type;
 
-		arg_type[idx++] = symbol_type(module, arg_sym);
+		arg_type[idx++] = symbol_type(arg_sym);
 	} END_FOR_EACH_PTR(arg);
-	func_type = LLVMFunctionType(ret_type, arg_type, n_arg,
-				     sym->variadic);
 
-	return func_type;
+	return LLVMFunctionType(ret_type, arg_type, n_arg, sym->variadic);
 }
 
-static LLVMTypeRef sym_array_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_array_type(struct symbol *sym)
 {
 	LLVMTypeRef elem_type;
 	struct symbol *base_type;
@@ -85,7 +58,7 @@
 	/* empty struct is undefined [6.7.2.1(8)] */
 	assert(base_type->bit_size > 0);
 
-	elem_type = symbol_type(module, base_type);
+	elem_type = symbol_type(base_type);
 	if (!elem_type)
 		return NULL;
 
@@ -94,7 +67,7 @@
 
 #define MAX_STRUCT_MEMBERS 64
 
-static LLVMTypeRef sym_struct_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_struct_type(struct symbol *sym)
 {
 	LLVMTypeRef elem_types[MAX_STRUCT_MEMBERS];
 	struct symbol *member;
@@ -112,7 +85,7 @@
 
 		assert(nr < MAX_STRUCT_MEMBERS);
 
-		member_type = symbol_type(module, member);
+		member_type = symbol_type(member);
 
 		elem_types[nr++] = member_type; 
 	} END_FOR_EACH_PTR(member);
@@ -121,7 +94,7 @@
 	return ret;
 }
 
-static LLVMTypeRef sym_union_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_union_type(struct symbol *sym)
 {
 	LLVMTypeRef elements;
 	unsigned union_size;
@@ -138,7 +111,7 @@
 	return LLVMStructType(&elements, 1, 0 /* packed? */);
 }
 
-static LLVMTypeRef sym_ptr_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef sym_ptr_type(struct symbol *sym)
 {
 	LLVMTypeRef type;
 
@@ -146,7 +119,7 @@
 	if (is_void_type(sym->ctype.base_type))
 		type = LLVMInt8Type();
 	else
-		type = symbol_type(module, sym->ctype.base_type);
+		type = symbol_type(sym->ctype.base_type);
 
 	return LLVMPointerType(type, 0);
 }
@@ -155,7 +128,7 @@
 {
 	LLVMTypeRef ret = NULL;
 
-	if (symbol_is_fp_type(sym)) {
+	if (is_float_type(sym)) {
 		switch (sym->bit_size) {
 		case 32:
 			ret = LLVMFloatType();
@@ -199,13 +172,13 @@
 	return ret;
 }
 
-static LLVMTypeRef symbol_type(LLVMModuleRef module, struct symbol *sym)
+static LLVMTypeRef symbol_type(struct symbol *sym)
 {
 	LLVMTypeRef ret = NULL;
 
 	/* don't cache the result for SYM_NODE */
 	if (sym->type == SYM_NODE)
-		return symbol_type(module, sym->ctype.base_type);
+		return symbol_type(sym->ctype.base_type);
 
 	if (sym->aux)
 		return sym->aux;
@@ -212,26 +185,29 @@
 
 	switch (sym->type) {
 	case SYM_BITFIELD:
+		ret = LLVMIntType(sym->bit_size);
+		break;
+	case SYM_RESTRICT:
 	case SYM_ENUM:
-		ret = symbol_type(module, sym->ctype.base_type);
+		ret = symbol_type(sym->ctype.base_type);
 		break;
 	case SYM_BASETYPE:
 		ret = sym_basetype_type(sym);
 		break;
 	case SYM_PTR:
-		ret = sym_ptr_type(module, sym);
+		ret = sym_ptr_type(sym);
 		break;
 	case SYM_UNION:
-		ret = sym_union_type(module, sym);
+		ret = sym_union_type(sym);
 		break;
 	case SYM_STRUCT:
-		ret = sym_struct_type(module, sym);
+		ret = sym_struct_type(sym);
 		break;
 	case SYM_ARRAY:
-		ret = sym_array_type(module, sym);
+		ret = sym_array_type(sym);
 		break;
 	case SYM_FN:
-		ret = sym_func_type(module, sym);
+		ret = sym_func_type(sym);
 		break;
 	default:
 		assert(0);
@@ -242,10 +218,12 @@
 	return ret;
 }
 
-static LLVMTypeRef int_type_by_size(int size)
+static LLVMTypeRef insn_symbol_type(struct instruction *insn)
 {
-	switch (size) {
-		case 1:		return LLVMInt1Type();
+	if (insn->type)
+		return symbol_type(insn->type);
+
+	switch (insn->size) {
 		case 8:		return LLVMInt8Type();
 		case 16:	return LLVMInt16Type();
 		case 32:	return LLVMInt32Type();
@@ -252,20 +230,13 @@
 		case 64:	return LLVMInt64Type();
 
 		default:
-			die("invalid bit size %d", size);
+			die("invalid bit size %d", insn->size);
 			break;
 	}
+
 	return NULL;	/* not reached */
 }
 
-static LLVMTypeRef insn_symbol_type(LLVMModuleRef module, struct instruction *insn)
-{
-	if (insn->type)
-		return symbol_type(module, insn->type);
-
-	return int_type_by_size(insn->size);
-}
-
 static LLVMLinkage data_linkage(struct symbol *sym)
 {
 	if (sym->ctype.modifiers & MOD_STATIC)
@@ -284,88 +255,130 @@
 
 #define MAX_PSEUDO_NAME 64
 
-static void pseudo_name(pseudo_t pseudo, char *buf)
+static const char *pseudo_name(pseudo_t pseudo, char *buf)
 {
 	switch (pseudo->type) {
 	case PSEUDO_REG:
-		snprintf(buf, MAX_PSEUDO_NAME, "R%d", pseudo->nr);
+		snprintf(buf, MAX_PSEUDO_NAME, "R%d.", pseudo->nr);
 		break;
-	case PSEUDO_SYM:
-		assert(0);
+	case PSEUDO_PHI:
+		snprintf(buf, MAX_PSEUDO_NAME, "PHI%d.", pseudo->nr);
 		break;
+	case PSEUDO_SYM:
 	case PSEUDO_VAL:
-		assert(0);
+	case PSEUDO_ARG:
+	case PSEUDO_VOID:
+		buf[0] = '\0';
 		break;
-	case PSEUDO_ARG: {
+	case PSEUDO_UNDEF:
 		assert(0);
 		break;
-	}
-	case PSEUDO_PHI:
-		snprintf(buf, MAX_PSEUDO_NAME, "PHI%d", pseudo->nr);
-		break;
 	default:
 		assert(0);
 	}
+
+	return buf;
 }
 
-static LLVMValueRef pseudo_to_value(struct function *fn, struct instruction *insn, pseudo_t pseudo)
+static LLVMValueRef get_sym_value(LLVMModuleRef module, struct symbol *sym)
 {
+	const char *name = show_ident(sym->ident);
+	LLVMTypeRef type = symbol_type(sym);
 	LLVMValueRef result = NULL;
+	struct expression *expr;
 
-	switch (pseudo->type) {
-	case PSEUDO_REG:
-		result = pseudo->priv;
-		break;
-	case PSEUDO_SYM: {
-		struct symbol *sym = pseudo->sym;
-		struct expression *expr;
+	assert(sym->bb_target == NULL);
 
-		assert(sym->bb_target == NULL);
+	expr = sym->initializer;
+	if (expr && !sym->ident) {
+		switch (expr->type) {
+		case EXPR_STRING: {
+			const char *s = expr->string->data;
+			LLVMValueRef indices[] = { LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt64Type(), 0, 0) };
+			LLVMValueRef data;
 
-		expr = sym->initializer;
-		if (expr) {
-			switch (expr->type) {
-			case EXPR_STRING: {
-				const char *s = expr->string->data;
-				LLVMValueRef indices[] = { LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt64Type(), 0, 0) };
-				LLVMValueRef data;
+			data = LLVMAddGlobal(module, LLVMArrayType(LLVMInt8Type(), strlen(s) + 1), ".str");
+			LLVMSetLinkage(data, LLVMPrivateLinkage);
+			LLVMSetGlobalConstant(data, 1);
+			LLVMSetInitializer(data, LLVMConstString(strdup(s), strlen(s) + 1, true));
 
-				data = LLVMAddGlobal(fn->module, LLVMArrayType(LLVMInt8Type(), strlen(s) + 1), ".str");
-				LLVMSetLinkage(data, LLVMPrivateLinkage);
-				LLVMSetGlobalConstant(data, 1);
-				LLVMSetInitializer(data, LLVMConstString(strdup(s), strlen(s) + 1, true));
+			result = LLVMConstGEP(data, indices, ARRAY_SIZE(indices));
+			return result;
+		}
+		default:
+			break;
+		}
+	}
 
-				result = LLVMConstGEP(data, indices, ARRAY_SIZE(indices));
-				break;
-			}
-			case EXPR_SYMBOL: {
-				struct symbol *sym = expr->symbol;
+	if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) {
+		result = LLVMGetNamedFunction(module, name);
+		if (!result)
+			result = LLVMAddFunction(module, name, type);
+	} else {
+		result = LLVMGetNamedGlobal(module, name);
+		if (!result)
+			result = LLVMAddGlobal(module, type, name);
+	}
 
-				result = LLVMGetNamedGlobal(fn->module, show_ident(sym->ident));
-				assert(result != NULL);
-				break;
-			}
-			default:
-				assert(0);
-			}
-		} else {
-			const char *name = show_ident(sym->ident);
-			LLVMTypeRef type = symbol_type(fn->module, sym);
+	return result;
+}
 
-			if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) {
-				result = LLVMGetNamedFunction(fn->module, name);
-				if (!result)
-					result = LLVMAddFunction(fn->module, name, type);
-			} else {
-				result = LLVMGetNamedGlobal(fn->module, name);
-				if (!result)
-					result = LLVMAddGlobal(fn->module, type, name);
-			}
+static LLVMValueRef constant_value(unsigned long long val, LLVMTypeRef dtype)
+{
+	LLVMValueRef result;
+
+	switch (LLVMGetTypeKind(dtype)) {
+	case LLVMPointerTypeKind:
+		if (val != 0) {	 // for example: ... = (void*) 0x123;
+			LLVMTypeRef itype = LLVMIntType(bits_in_pointer);
+			result = LLVMConstInt(itype, val, 1);
+			result = LLVMConstIntToPtr(result, dtype);
+		} else {
+			result = LLVMConstPointerNull(dtype);
 		}
 		break;
+	case LLVMIntegerTypeKind:
+		result = LLVMConstInt(dtype, val, 1);
+		break;
+	case LLVMArrayTypeKind:
+	case LLVMStructTypeKind:
+		if (val != 0)
+			return NULL;
+		result = LLVMConstNull(dtype);
+		break;
+	default:
+		return NULL;
 	}
+	return result;
+}
+
+static LLVMValueRef val_to_value(unsigned long long val, struct symbol *ctype)
+{
+	LLVMValueRef result;
+	LLVMTypeRef dtype;
+
+	assert(ctype);
+	dtype = symbol_type(ctype);
+	result = constant_value(val, dtype);
+	if (result)
+		return result;
+	sparse_error(ctype->pos, "no value possible for %s", show_typename(ctype));
+	return LLVMGetUndef(symbol_type(ctype));
+}
+
+static LLVMValueRef pseudo_to_value(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+	LLVMValueRef result = NULL;
+
+	switch (pseudo->type) {
+	case PSEUDO_REG:
+		result = pseudo->priv;
+		break;
+	case PSEUDO_SYM:
+		result = get_sym_value(fn->module, pseudo->sym);
+		break;
 	case PSEUDO_VAL:
-		result = LLVMConstInt(int_type_by_size(pseudo->size), pseudo->value, 1);
+		result = val_to_value(pseudo->value, ctype);
 		break;
 	case PSEUDO_ARG: {
 		result = LLVMGetParam(fn->fn, pseudo->nr - 1);
@@ -377,6 +390,9 @@
 	case PSEUDO_VOID:
 		result = NULL;
 		break;
+	case PSEUDO_UNDEF:
+		result = LLVMGetUndef(symbol_type(ctype));
+		break;
 	default:
 		assert(0);
 	}
@@ -384,6 +400,80 @@
 	return result;
 }
 
+static LLVMValueRef pseudo_to_rvalue(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+	LLVMValueRef val = pseudo_to_value(fn, ctype, pseudo);
+	LLVMTypeRef dtype = symbol_type(ctype);
+	char name[MAX_PSEUDO_NAME];
+
+	pseudo_name(pseudo, name);
+	return LLVMBuildBitCast(fn->builder, val, dtype, name);
+}
+
+static LLVMValueRef value_to_ivalue(struct function *fn, struct symbol *ctype, LLVMValueRef val)
+{
+	const char *name = LLVMGetValueName(val);
+	LLVMTypeRef dtype = symbol_type(ctype);
+
+	if (LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMPointerTypeKind) {
+		LLVMTypeRef dtype = LLVMIntType(bits_in_pointer);
+		val = LLVMBuildPtrToInt(fn->builder, val, dtype, name);
+	}
+	if (ctype && is_int_type(ctype)) {
+		val = LLVMBuildIntCast(fn->builder, val, dtype, name);
+	}
+	return val;
+}
+
+static LLVMValueRef value_to_pvalue(struct function *fn, struct symbol *ctype, LLVMValueRef val)
+{
+	const char *name = LLVMGetValueName(val);
+	LLVMTypeRef dtype = symbol_type(ctype);
+
+	assert(is_ptr_type(ctype));
+	switch (LLVMGetTypeKind(LLVMTypeOf(val))) {
+	case LLVMIntegerTypeKind:
+		val = LLVMBuildIntToPtr(fn->builder, val, dtype, name);
+		break;
+	case LLVMPointerTypeKind:
+		val = LLVMBuildBitCast(fn->builder, val, dtype, name);
+		break;
+	default:
+		break;
+	}
+	return val;
+}
+
+static LLVMValueRef adjust_type(struct function *fn, struct symbol *ctype, LLVMValueRef val)
+{
+	if (is_int_type(ctype))
+		return value_to_ivalue(fn, ctype, val);
+	if (is_ptr_type(ctype))
+		return value_to_pvalue(fn, ctype, val);
+	return val;
+}
+
+/*
+ * Get the LLVMValue corresponding to the pseudo
+ * and force the type corresponding to ctype.
+ */
+static LLVMValueRef get_operand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+	LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
+	return adjust_type(fn, ctype, target);
+}
+
+/*
+ * Get the LLVMValue corresponding to the pseudo
+ * and force the type corresponding to ctype but
+ * map all pointers to intptr_t.
+ */
+static LLVMValueRef get_ioperand(struct function *fn, struct symbol *ctype, pseudo_t pseudo)
+{
+	LLVMValueRef target = pseudo_to_value(fn, ctype, pseudo);
+	return value_to_ivalue(fn, ctype, target);
+}
+
 static LLVMValueRef calc_gep(LLVMBuilderRef builder, LLVMValueRef base, LLVMValueRef off)
 {
 	LLVMTypeRef type = LLVMTypeOf(base);
@@ -390,13 +480,14 @@
 	unsigned int as = LLVMGetPointerAddressSpace(type);
 	LLVMTypeRef bytep = LLVMPointerType(LLVMInt8Type(), as);
 	LLVMValueRef addr;
+	const char *name = LLVMGetValueName(off);
 
 	/* convert base to char* type */
-	base = LLVMBuildPointerCast(builder, base, bytep, "");
+	base = LLVMBuildPointerCast(builder, base, bytep, name);
 	/* addr = base + off */
-	addr = LLVMBuildInBoundsGEP(builder, base, &off, 1, "");
+	addr = LLVMBuildInBoundsGEP(builder, base, &off, 1, name);
 	/* convert back to the actual pointer type */
-	addr = LLVMBuildPointerCast(builder, addr, type, "");
+	addr = LLVMBuildPointerCast(builder, addr, type, name);
 	return addr;
 }
 
@@ -403,17 +494,20 @@
 static LLVMRealPredicate translate_fop(int opcode)
 {
 	static const LLVMRealPredicate trans_tbl[] = {
-		[OP_SET_EQ]	= LLVMRealOEQ,
-		[OP_SET_NE]	= LLVMRealUNE,
-		[OP_SET_LE]	= LLVMRealOLE,
-		[OP_SET_GE]	= LLVMRealOGE,
-		[OP_SET_LT]	= LLVMRealOLT,
-		[OP_SET_GT]	= LLVMRealOGT,
-		/* Are these used with FP? */
-		[OP_SET_B]	= LLVMRealOLT,
-		[OP_SET_A]	= LLVMRealOGT,
-		[OP_SET_BE]	= LLVMRealOLE,
-		[OP_SET_AE]	= LLVMRealOGE,
+		[OP_FCMP_ORD]	= LLVMRealORD,
+		[OP_FCMP_OEQ]	= LLVMRealOEQ,
+		[OP_FCMP_ONE]	= LLVMRealONE,
+		[OP_FCMP_OLE]	= LLVMRealOLE,
+		[OP_FCMP_OGE]	= LLVMRealOGE,
+		[OP_FCMP_OLT]	= LLVMRealOLT,
+		[OP_FCMP_OGT]	= LLVMRealOGT,
+		[OP_FCMP_UEQ]	= LLVMRealUEQ,
+		[OP_FCMP_UNE]	= LLVMRealUNE,
+		[OP_FCMP_ULE]	= LLVMRealULE,
+		[OP_FCMP_UGE]	= LLVMRealUGE,
+		[OP_FCMP_ULT]	= LLVMRealULT,
+		[OP_FCMP_UGT]	= LLVMRealUGT,
+		[OP_FCMP_UNO]	= LLVMRealUNO,
 	};
 
 	return trans_tbl[opcode];
@@ -442,109 +536,83 @@
 	LLVMValueRef lhs, rhs, target;
 	char target_name[64];
 
-	lhs = pseudo_to_value(fn, insn, insn->src1);
+	lhs = get_ioperand(fn, insn->type, insn->src1);
+	rhs = get_ioperand(fn, insn->type, insn->src2);
 
-	rhs = pseudo_to_value(fn, insn, insn->src2);
-
 	pseudo_name(insn->target, target_name);
 
 	switch (insn->opcode) {
 	/* Binary */
 	case OP_ADD:
-		if (symbol_is_fp_type(insn->type))
-			target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildAdd(fn->builder, lhs, rhs, target_name);
+		target = LLVMBuildAdd(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_SUB:
-		if (symbol_is_fp_type(insn->type))
-			target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildSub(fn->builder, lhs, rhs, target_name);
+		target = LLVMBuildSub(fn->builder, lhs, rhs, target_name);
 		break;
-	case OP_MULU:
-		if (symbol_is_fp_type(insn->type))
-			target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
-		break;
-	case OP_MULS:
-		assert(!symbol_is_fp_type(insn->type));
+	case OP_MUL:
 		target = LLVMBuildMul(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_DIVU:
-		if (symbol_is_fp_type(insn->type))
-			target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name);
-		else
-			target = LLVMBuildUDiv(fn->builder, lhs, rhs, target_name);
+		target = LLVMBuildUDiv(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_DIVS:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildSDiv(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_MODU:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildURem(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_MODS:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildSRem(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_SHL:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildShl(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_LSR:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildLShr(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_ASR:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildAShr(fn->builder, lhs, rhs, target_name);
 		break;
+
+	/* floating-point */
+	case OP_FADD:
+		target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name);
+		break;
+	case OP_FSUB:
+		target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name);
+		break;
+	case OP_FMUL:
+		target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name);
+		break;
+	case OP_FDIV:
+		target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name);
+		break;
 	
 	/* Logical */
 	case OP_AND:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildAnd(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_OR:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildOr(fn->builder, lhs, rhs, target_name);
 		break;
 	case OP_XOR:
-		assert(!symbol_is_fp_type(insn->type));
+		assert(!is_float_type(insn->type));
 		target = LLVMBuildXor(fn->builder, lhs, rhs, target_name);
 		break;
-	case OP_AND_BOOL: {
-		LLVMValueRef lhs_nz, rhs_nz;
-		LLVMTypeRef dst_type;
-
-		lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, "");
-		rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, "");
-		target = LLVMBuildAnd(fn->builder, lhs_nz, rhs_nz, target_name);
-
-		dst_type = insn_symbol_type(fn->module, insn);
-		target = LLVMBuildZExt(fn->builder, target, dst_type, target_name);
-		break;
-	}
-	case OP_OR_BOOL: {
-		LLVMValueRef lhs_nz, rhs_nz;
-		LLVMTypeRef dst_type;
-
-		lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, "");
-		rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, "");
-		target = LLVMBuildOr(fn->builder, lhs_nz, rhs_nz, target_name);
-
-		dst_type = insn_symbol_type(fn->module, insn);
-		target = LLVMBuildZExt(fn->builder, target, dst_type, target_name);
-		break;
-	}
 	default:
 		assert(0);
 		break;
 	}
 
+	target = adjust_type(fn, insn->type, target);
 	insn->target->priv = target;
 }
 
@@ -553,26 +621,48 @@
 	LLVMValueRef lhs, rhs, target;
 	char target_name[64];
 
-	lhs = pseudo_to_value(fn, insn, insn->src1);
-
+	lhs = pseudo_to_value(fn, NULL, insn->src1);
 	if (insn->src2->type == PSEUDO_VAL)
-		rhs = LLVMConstInt(LLVMTypeOf(lhs), insn->src2->value, 1);
+		rhs = constant_value(insn->src2->value, LLVMTypeOf(lhs));
 	else
-		rhs = pseudo_to_value(fn, insn, insn->src2);
+		rhs = pseudo_to_value(fn, NULL, insn->src2);
+	if (!rhs)
+		rhs = LLVMGetUndef(symbol_type(insn->type));
 
 	pseudo_name(insn->target, target_name);
 
-	LLVMTypeRef dst_type = insn_symbol_type(fn->module, insn);
+	LLVMTypeRef dst_type = insn_symbol_type(insn);
 
-	if (LLVMGetTypeKind(LLVMTypeOf(lhs)) == LLVMIntegerTypeKind) {
+	switch  (LLVMGetTypeKind(LLVMTypeOf(lhs))) {
+	case LLVMPointerTypeKind:
+		lhs = value_to_pvalue(fn, &ptr_ctype, lhs);
+		rhs = value_to_pvalue(fn, &ptr_ctype, rhs);
+		/* fall through */
+
+	case LLVMIntegerTypeKind: {
 		LLVMIntPredicate op = translate_op(insn->opcode);
 
+		if (LLVMGetTypeKind(LLVMTypeOf(rhs)) == LLVMPointerTypeKind) {
+			LLVMTypeRef ltype = LLVMTypeOf(lhs);
+			rhs = LLVMBuildPtrToInt(fn->builder, rhs, ltype, "");
+		}
 		target = LLVMBuildICmp(fn->builder, op, lhs, rhs, target_name);
-	} else {
+		break;
+	}
+	case LLVMHalfTypeKind:
+	case LLVMFloatTypeKind:
+	case LLVMDoubleTypeKind:
+	case LLVMX86_FP80TypeKind:
+	case LLVMFP128TypeKind:
+	case LLVMPPC_FP128TypeKind: {
 		LLVMRealPredicate op = translate_fop(insn->opcode);
 
 		target = LLVMBuildFCmp(fn->builder, op, lhs, rhs, target_name);
+		break;
 	}
+	default:
+		assert(0);
+	}
 
 	target = LLVMBuildZExt(fn->builder, target, dst_type, target_name);
 
@@ -584,8 +674,7 @@
 	pseudo_t pseudo = insn->src;
 
 	if (pseudo && pseudo != VOID) {
-		LLVMValueRef result = pseudo_to_value(fn, insn, pseudo);
-
+		LLVMValueRef result = get_operand(fn, insn->type, pseudo);
 		LLVMBuildRet(fn->builder, result);
 	} else
 		LLVMBuildRetVoid(fn->builder);
@@ -602,10 +691,10 @@
 	off = LLVMConstInt(int_type, insn->offset, 0);
 
 	/* convert src to the effective pointer type */
-	src = pseudo_to_value(fn, insn, insn->src);
+	src = pseudo_to_value(fn, insn->type, insn->src);
 	as = LLVMGetPointerAddressSpace(LLVMTypeOf(src));
-	addr_type = LLVMPointerType(insn_symbol_type(fn->module, insn), as);
-	src = LLVMBuildPointerCast(fn->builder, src, addr_type, "");
+	addr_type = LLVMPointerType(insn_symbol_type(insn), as);
+	src = LLVMBuildPointerCast(fn->builder, src, addr_type, LLVMGetValueName(src));
 
 	/* addr = src + off */
 	addr = calc_gep(fn->builder, src, off);
@@ -616,11 +705,13 @@
 static void output_op_load(struct function *fn, struct instruction *insn)
 {
 	LLVMValueRef addr, target;
+	char name[MAX_PSEUDO_NAME];
 
 	addr = calc_memop_addr(fn, insn);
 
 	/* perform load */
-	target = LLVMBuildLoad(fn->builder, addr, "load_target");
+	pseudo_name(insn->target, name);
+	target = LLVMBuildLoad(fn->builder, addr, name);
 
 	insn->target->priv = target;
 }
@@ -627,22 +718,20 @@
 
 static void output_op_store(struct function *fn, struct instruction *insn)
 {
-	LLVMValueRef addr, target, target_in;
+	LLVMValueRef addr, target_in;
 
 	addr = calc_memop_addr(fn, insn);
 
-	target_in = pseudo_to_value(fn, insn, insn->target);
+	target_in = pseudo_to_rvalue(fn, insn->type, insn->target);
 
 	/* perform store */
-	target = LLVMBuildStore(fn->builder, target_in, addr);
-
-	insn->target->priv = target;
+	LLVMBuildStore(fn->builder, target_in, addr);
 }
 
 static LLVMValueRef bool_value(struct function *fn, LLVMValueRef value)
 {
 	if (LLVMTypeOf(value) != LLVMInt1Type())
-		value = LLVMBuildIsNotNull(fn->builder, value, "cond");
+		value = LLVMBuildIsNotNull(fn->builder, value, LLVMGetValueName(value));
 
 	return value;
 }
@@ -650,7 +739,7 @@
 static void output_op_cbr(struct function *fn, struct instruction *br)
 {
 	LLVMValueRef cond = bool_value(fn,
-			pseudo_to_value(fn, br, br->cond));
+			pseudo_to_value(fn, NULL, br->cond));
 
 	LLVMBuildCondBr(fn->builder, cond,
 			br->bb_true->priv,
@@ -665,14 +754,16 @@
 static void output_op_sel(struct function *fn, struct instruction *insn)
 {
 	LLVMValueRef target, src1, src2, src3;
+	char name[MAX_PSEUDO_NAME];
 
-	src1 = bool_value(fn, pseudo_to_value(fn, insn, insn->src1));
-	src2 = pseudo_to_value(fn, insn, insn->src2);
-	src3 = pseudo_to_value(fn, insn, insn->src3);
+	src1 = bool_value(fn, pseudo_to_value(fn, NULL, insn->src1));
+	src2 = get_operand(fn, insn->type, insn->src2);
+	src3 = get_operand(fn, insn->type, insn->src3);
 
-	target = LLVMBuildSelect(fn->builder, src1, src2, src3, "select");
+	pseudo_name(insn->target, name);
+	target = LLVMBuildSelect(fn->builder, src1, src2, src3, name);
 
-	insn->target->priv = target;
+	insn->target->priv = adjust_type(fn, insn->type, target);
 }
 
 static void output_op_switch(struct function *fn, struct instruction *insn)
@@ -683,51 +774,52 @@
 	int n_jmp = 0;
 
 	FOR_EACH_PTR(insn->multijmp_list, jmp) {
-		if (jmp->begin == jmp->end) {		/* case N */
-			n_jmp++;
-		} else if (jmp->begin < jmp->end) {	/* case M..N */
-			assert(0);
+		if (jmp->begin <= jmp->end) {
+			n_jmp += (jmp->end - jmp->begin) + 1;
 		} else					/* default case */
 			def = jmp->target;
 	} END_FOR_EACH_PTR(jmp);
 
-	sw_val = pseudo_to_value(fn, insn, insn->target);
+	sw_val = get_ioperand(fn, insn->type, insn->cond);
 	target = LLVMBuildSwitch(fn->builder, sw_val,
 				 def ? def->priv : NULL, n_jmp);
 
 	FOR_EACH_PTR(insn->multijmp_list, jmp) {
-		if (jmp->begin == jmp->end) {		/* case N */
-			LLVMAddCase(target,
-				LLVMConstInt(LLVMInt32Type(), jmp->begin, 0),
-				jmp->target->priv);
-		} else if (jmp->begin < jmp->end) {	/* case M..N */
-			assert(0);
+		long long val;
+
+		for (val = jmp->begin; val <= jmp->end; val++) {
+			LLVMValueRef Val = val_to_value(val, insn->type);
+			LLVMAddCase(target, Val, jmp->target->priv);
 		}
 	} END_FOR_EACH_PTR(jmp);
-
-	insn->target->priv = target;
 }
 
 static void output_op_call(struct function *fn, struct instruction *insn)
 {
 	LLVMValueRef target, func;
+	struct symbol *ctype;
 	int n_arg = 0, i;
 	struct pseudo *arg;
 	LLVMValueRef *args;
+	char name[64];
 
-	FOR_EACH_PTR(insn->arguments, arg) {
-		n_arg++;
-	} END_FOR_EACH_PTR(arg);
-
+	n_arg = pseudo_list_size(insn->arguments);
 	args = calloc(n_arg, sizeof(LLVMValueRef));
 
+	PREPARE_PTR_LIST(insn->fntypes, ctype);
+	if (insn->func->type == PSEUDO_REG || insn->func->type == PSEUDO_PHI)
+		func = get_operand(fn, ctype, insn->func);
+	else
+		func = pseudo_to_value(fn, ctype, insn->func);
 	i = 0;
 	FOR_EACH_PTR(insn->arguments, arg) {
-		args[i++] = pseudo_to_value(fn, insn, arg);
+		NEXT_PTR_LIST(ctype);
+		args[i++] = pseudo_to_rvalue(fn, ctype, arg);
 	} END_FOR_EACH_PTR(arg);
+	FINISH_PTR_LIST(ctype);
 
-	func = pseudo_to_value(fn, insn, insn->func);
-	target = LLVMBuildCall(fn->builder, func, args, n_arg, "");
+	pseudo_name(insn->target, name);
+	target = LLVMBuildCall(fn->builder, func, args, n_arg, name);
 
 	insn->target->priv = target;
 }
@@ -740,7 +832,7 @@
 	assert(insn->target->priv == NULL);
 
 	/* target = src */
-	v = pseudo_to_value(fn, insn, insn->phi_src);
+	v = get_operand(fn, insn->type, insn->phi_src);
 
 	FOR_EACH_PTR(insn->phi_users, phi) {
 		LLVMValueRef load, ptr;
@@ -770,18 +862,38 @@
 static void output_op_ptrcast(struct function *fn, struct instruction *insn)
 {
 	LLVMValueRef src, target;
+	LLVMTypeRef dtype;
+	struct symbol *otype = insn->orig_type;
+	LLVMOpcode op;
 	char target_name[64];
 
-	src = insn->src->priv;
-	if (!src)
-		src = pseudo_to_value(fn, insn, insn->src);
-
+	src = get_operand(fn, otype, insn->src);
 	pseudo_name(insn->target, target_name);
 
-	assert(!symbol_is_fp_type(insn->type));
+	dtype = symbol_type(insn->type);
+	switch (insn->opcode) {
+	case OP_UTPTR:
+	case OP_SEXT:			// FIXME
+		assert(is_int_type(otype));
+		assert(is_ptr_type(insn->type));
+		op = LLVMIntToPtr;
+		break;
+	case OP_PTRTU:
+		assert(is_ptr_type(otype));
+		assert(is_int_type(insn->type));
+		op = LLVMPtrToInt;
+		break;
+	case OP_PTRCAST:
+	case OP_ZEXT:			// FIXME
+		assert(is_ptr_type(otype));
+		assert(is_ptr_type(insn->type));
+		op = LLVMBitCast;
+		break;
+	default:
+		assert(0);
+	}
 
-	target = LLVMBuildBitCast(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
-
+	target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
 	insn->target->priv = target;
 }
 
@@ -788,24 +900,89 @@
 static void output_op_cast(struct function *fn, struct instruction *insn, LLVMOpcode op)
 {
 	LLVMValueRef src, target;
+	LLVMTypeRef dtype;
+	struct symbol *otype = insn->orig_type;
 	char target_name[64];
 
-	src = insn->src->priv;
-	if (!src)
-		src = pseudo_to_value(fn, insn, insn->src);
+	if (is_ptr_type(insn->type))	// cast to void* is OP_CAST ...
+		return output_op_ptrcast(fn, insn);
 
+	assert(is_int_type(insn->type));
+
+	src = get_operand(fn, otype, insn->src);
 	pseudo_name(insn->target, target_name);
 
-	assert(!symbol_is_fp_type(insn->type));
+	dtype = symbol_type(insn->type);
+	if (is_ptr_type(otype)) {
+		op = LLVMPtrToInt;
+	} else if (is_float_type(otype)) {
+		assert(op == LLVMFPToUI || op == LLVMFPToSI);
+	} else if (is_int_type(otype)) {
+		unsigned int width = otype->bit_size;
+		if (insn->size < width)
+			op = LLVMTrunc;
+		else if (insn->size == width)
+			op = LLVMBitCast;
+	} else {
+		assert(0);
+	}
 
-	if (insn->size < LLVMGetIntTypeWidth(LLVMTypeOf(src)))
-		target = LLVMBuildTrunc(fn->builder, src, insn_symbol_type(fn->module, insn), target_name);
-	else
-		target = LLVMBuildCast(fn->builder, op, src, insn_symbol_type(fn->module, insn), target_name);
+	target = LLVMBuildCast(fn->builder, op, src, dtype, target_name);
+	insn->target->priv = target;
+}
 
+static void output_op_fpcast(struct function *fn, struct instruction *insn)
+{
+	LLVMTypeRef dtype = symbol_type(insn->type);
+	LLVMValueRef src, target;
+	struct symbol *otype = insn->orig_type;
+	char name[64];
+
+	assert(is_float_type(insn->type));
+
+	pseudo_name(insn->target, name);
+	src = get_operand(fn, otype, insn->src);
+	switch (insn->opcode) {
+	case OP_FCVTF:
+		target = LLVMBuildFPCast(fn->builder, src, dtype, name);
+		break;
+	case OP_SCVTF:
+		target = LLVMBuildSIToFP(fn->builder, src, dtype, name);
+		break;
+	case OP_UCVTF:
+		target = LLVMBuildUIToFP(fn->builder, src, dtype, name);
+		break;
+	default:
+		assert(0);
+	}
 	insn->target->priv = target;
 }
 
+static void output_op_setval(struct function *fn, struct instruction *insn)
+{
+	struct expression *val = insn->val;
+	LLVMValueRef target;
+
+	switch (val->type) {
+	case EXPR_LABEL:
+		target = LLVMBlockAddress(fn->fn, val->symbol->bb_target->priv);
+		break;
+	default:
+		assert(0);
+	}
+
+	insn->target->priv = target;
+}
+
+static void output_op_setfval(struct function *fn, struct instruction *insn)
+{
+	LLVMTypeRef dtype = symbol_type(insn->type);
+	LLVMValueRef target;
+
+	target = LLVMConstReal(dtype, insn->fvalue);
+	insn->target->priv = target;
+}
+
 static void output_insn(struct function *fn, struct instruction *insn)
 {
 	switch (insn->opcode) {
@@ -822,8 +999,11 @@
 		assert(0);
 		break;
 	case OP_SETVAL:
-		assert(0);
+		output_op_setval(fn, insn);
 		break;
+	case OP_SETFVAL:
+		output_op_setfval(fn, insn);
+		break;
 	case OP_SWITCH:
 		output_op_switch(fn, insn);
 		break;
@@ -839,30 +1019,35 @@
 	case OP_LOAD:
 		output_op_load(fn, insn);
 		break;
-	case OP_LNOP:
-		assert(0);
-		break;
 	case OP_STORE:
 		output_op_store(fn, insn);
 		break;
-	case OP_SNOP:
-		assert(0);
-		break;
 	case OP_INLINED_CALL:
-		assert(0);
 		break;
 	case OP_CALL:
 		output_op_call(fn, insn);
 		break;
-	case OP_CAST:
+	case OP_ZEXT:
 		output_op_cast(fn, insn, LLVMZExt);
 		break;
-	case OP_SCAST:
+	case OP_SEXT:
 		output_op_cast(fn, insn, LLVMSExt);
 		break;
-	case OP_FPCAST:
-		assert(0);
+	case OP_TRUNC:
+		output_op_cast(fn, insn, LLVMTrunc);
 		break;
+	case OP_FCVTU:
+		output_op_cast(fn, insn, LLVMFPToUI);
+		break;
+	case OP_FCVTS:
+		output_op_cast(fn, insn, LLVMFPToSI);
+		break;
+	case OP_UCVTF: case OP_SCVTF:
+	case OP_FCVTF:
+		output_op_fpcast(fn, insn);
+		break;
+	case OP_UTPTR:
+	case OP_PTRTU:
 	case OP_PTRCAST:
 		output_op_ptrcast(fn, insn);
 		break;
@@ -869,7 +1054,7 @@
 	case OP_BINARY ... OP_BINARY_END:
 		output_op_binary(fn, insn);
 		break;
-	case OP_BINCMP ... OP_BINCMP_END:
+	case OP_FPCMP ... OP_BINCMP_END:
 		output_op_compare(fn, insn);
 		break;
 	case OP_SEL:
@@ -882,7 +1067,7 @@
 		LLVMValueRef src, target;
 		char target_name[64];
 
-		src = pseudo_to_value(fn, insn, insn->src);
+		src = pseudo_to_value(fn, insn->type, insn->src);
 
 		pseudo_name(insn->target, target_name);
 
@@ -891,9 +1076,23 @@
 		insn->target->priv = target;
 		break;
 	}
-	case OP_NEG:
-		assert(0);
+	case OP_FNEG:
+	case OP_NEG: {
+		LLVMValueRef src, target;
+		char target_name[64];
+
+		src = pseudo_to_value(fn, insn->type, insn->src);
+
+		pseudo_name(insn->target, target_name);
+
+		if (insn->opcode == OP_FNEG)
+			target = LLVMBuildFNeg(fn->builder, src, target_name);
+		else
+			target = LLVMBuildNeg(fn->builder, src, target_name);
+
+		insn->target->priv = target;
 		break;
+	}
 	case OP_CONTEXT:
 		assert(0);
 		break;
@@ -916,12 +1115,10 @@
 	}
 }
 
-static void output_bb(struct function *fn, struct basic_block *bb, unsigned long generation)
+static void output_bb(struct function *fn, struct basic_block *bb)
 {
 	struct instruction *insn;
 
-	bb->generation = generation;
-
 	FOR_EACH_PTR(bb->insns, insn) {
 		if (!insn->bb)
 			continue;
@@ -935,43 +1132,33 @@
 
 static void output_fn(LLVMModuleRef module, struct entrypoint *ep)
 {
-	unsigned long generation = ++bb_generation;
 	struct symbol *sym = ep->name;
 	struct symbol *base_type = sym->ctype.base_type;
-	struct symbol *ret_type = sym->ctype.base_type->ctype.base_type;
-	LLVMTypeRef arg_types[MAX_ARGS];
-	LLVMTypeRef return_type;
 	struct function function = { .module = module };
 	struct basic_block *bb;
-	struct symbol *arg;
-	const char *name;
 	int nr_args = 0;
+	int i;
 
-	FOR_EACH_PTR(base_type->arguments, arg) {
-		struct symbol *arg_base_type = arg->ctype.base_type;
-
-		arg_types[nr_args++] = symbol_type(module, arg_base_type);
-	} END_FOR_EACH_PTR(arg);
-
-	name = show_ident(sym->ident);
-
-	return_type = symbol_type(module, ret_type);
-
-	function.type = LLVMFunctionType(return_type, arg_types, nr_args, 0);
-
-	function.fn = LLVMAddFunction(module, name, function.type);
+	function.fn = get_sym_value(module, sym);
 	LLVMSetFunctionCallConv(function.fn, LLVMCCallConv);
-
 	LLVMSetLinkage(function.fn, function_linkage(sym));
 
 	function.builder = LLVMCreateBuilder();
 
-	static int nr_bb;
+	/* give a name to each argument */
+	nr_args = symbol_list_size(base_type->arguments);
+	for (i = 0; i < nr_args; i++) {
+		char name[MAX_PSEUDO_NAME];
+		LLVMValueRef arg;
 
-	FOR_EACH_PTR(ep->bbs, bb) {
-		if (bb->generation == generation)
-			continue;
+		arg = LLVMGetParam(function.fn, i);
+		snprintf(name, sizeof(name), "ARG%d.", i+1);
+		LLVMSetValueName(arg, name);
+	}
 
+	/* create the BBs */
+	FOR_EACH_PTR(ep->bbs, bb) {
+		static int nr_bb;
 		LLVMBasicBlockRef bbr;
 		char bbname[32];
 		struct instruction *insn;
@@ -992,7 +1179,7 @@
 			/* insert alloca into entry block */
 			entrybbr = LLVMGetEntryBasicBlock(function.fn);
 			LLVMPositionBuilderAtEnd(function.builder, entrybbr);
-			phi_type = insn_symbol_type(module, insn);
+			phi_type = insn_symbol_type(insn);
 			ptr = LLVMBuildAlloca(function.builder, phi_type, "");
 			/* emit forward load for phi */
 			LLVMClearInsertionPosition(function.builder);
@@ -1002,12 +1189,9 @@
 	END_FOR_EACH_PTR(bb);
 
 	FOR_EACH_PTR(ep->bbs, bb) {
-		if (bb->generation == generation)
-			continue;
-
 		LLVMPositionBuilderAtEnd(function.builder, bb->priv);
 
-		output_bb(&function, bb, generation);
+		output_bb(&function, bb);
 	}
 	END_FOR_EACH_PTR(bb);
 }
@@ -1022,8 +1206,11 @@
 	if (initializer) {
 		switch (initializer->type) {
 		case EXPR_VALUE:
-			initial_value = LLVMConstInt(symbol_type(module, sym), initializer->value, 1);
+			initial_value = LLVMConstInt(symbol_type(sym), initializer->value, 1);
 			break;
+		case EXPR_FVALUE:
+			initial_value = LLVMConstReal(symbol_type(sym), initializer->fvalue);
+			break;
 		case EXPR_SYMBOL: {
 			struct symbol *sym = initializer->symbol;
 
@@ -1039,16 +1226,21 @@
 			break;
 		}
 		default:
-			assert(0);
+			warning(initializer->pos, "can't initialize type: %s", show_typename(sym));
+			initial_value = NULL;
+			break;
 		}
 	} else {
-		LLVMTypeRef type = symbol_type(module, sym);
+		LLVMTypeRef type = symbol_type(sym);
 
 		initial_value = LLVMConstNull(type);
 	}
 
-	name = show_ident(sym->ident);
+	if (!initial_value)
+		return NULL;
 
+	name = sym->ident ? show_ident(sym->ident) : "" ;
+
 	data = LLVMAddGlobal(module, LLVMTypeOf(initial_value), name);
 
 	LLVMSetLinkage(data, data_linkage(sym));
@@ -1080,8 +1272,11 @@
 		struct entrypoint *ep;
 		expand_symbol(sym);
 
-		if (is_prototype(sym))
+		if (is_prototype(sym)) {
+			// this will do the LLVMAddFunction() we want
+			get_sym_value(module, sym);
 			continue;
+		}
 
 		ep = linearize_symbol(sym);
 		if (ep)
@@ -1158,12 +1353,12 @@
 
 	/* need ->phi_users */
 	dbg_dead = 1;
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		symlist = sparse(file);
 		if (die_if_error)
 			return 1;
 		compile(module, symlist);
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 	LLVMVerifyModule(module, LLVMPrintMessageAction, NULL);
 
--- old/usr/src/tools/smatch/src/sparse.1	Mon Nov 18 13:19:31 2019
+++ new/usr/src/tools/smatch/src/sparse.1	Mon Nov 18 13:19:31 2019
@@ -20,6 +20,12 @@
 .
 .SH WARNING OPTIONS
 .TP
+.B \-fmax-warnings=COUNT
+Set the maximum number of displayed warnings to COUNT, which should be
+a numerical value or 'unlimited'.
+The default limit is 100.
+.
+.TP
 .B \-Wsparse\-all
 Turn on all sparse warnings, except for those explicitly disabled via
 \fB\-Wno\-something\fR.
@@ -31,13 +37,21 @@
 Warn about code which mixes pointers to different address spaces.
 
 Sparse allows an extended attribute
-.BI __attribute__((address_space( num )))
-on pointers, which designates a pointer target in address space \fInum\fR (a
-constant integer).  With \fB\-Waddress\-space\fR, Sparse treats pointers with
-identical target types but different address spaces as distinct types.  To
-override this warning, such as for functions which convert pointers between
-address spaces, use a type that includes \fB__attribute__((force))\fR.
+.BI __attribute__((address_space( id )))
+on pointers, which designates a pointer target in address space \fIid\fR (an
+identifier or a constant integer).
+With \fB\-Waddress\-space\fR, Sparse treats pointers with
+identical target types but different address spaces as distinct types and
+will warn accordingly.
 
+Sparse will also warn on casts which remove the address space (casts to an
+integer type or to a plain pointer type). An exception to this is when the
+destination type is \fBuintptr_t\fR (or \fBunsigned long\fR) since such casts
+are often used to "get a pointer value representation in an integer type" and
+such values are independent of the address space.
+
+To override these warnings, use a type that includes \fB__attribute__((force))\fR.
+
 Sparse issues these warnings by default.  To turn them off, use
 \fB\-Wno\-address\-space\fR.
 .
@@ -71,10 +85,27 @@
 \fB\-Wno\-bitwise\fR.
 .
 .TP
+.B \-Wbitwise\-pointer
+Same as \fB\-Wbitwise\fR but for casts to or from pointers to bitwise types.
+
+Sparse does not issue these warnings by default.
+.
+.TP
+.B \-Wcast\-from\-as
+Warn about casts which remove an address space from a pointer type.
+
+This is similar to \fB\-Waddress\-space\fR but will also warn
+on casts to \fBunsigned long\fR.
+
+Sparse does not issues these warnings by default.
+.
+.TP
 .B \-Wcast\-to\-as
 Warn about casts which add an address space to a pointer type.
 
 A cast that includes \fB__attribute__((force))\fR will suppress this warning.
+No warning is generated if the original type is \fBuintptr_t\fR
+(or \fBunsigned long\fR).
 
 Sparse does not issue these warnings by default.
 .
@@ -213,13 +244,6 @@
 \fB\-Wno\-enum\-mismatch\fR.
 .
 .TP
-.B \-Wempty\-character\-constant
-Warn about a constant such as ''.
-
-Sparse issues these warnings by default.  To turn them off, use
-\fB\-Wno\-empty\-character\-constant\fR.
-.
-.TP
 .B \-Wexternal\-function\-has\-definition
 Warn about function definitions that are declared with external linkage.
 
@@ -256,13 +280,6 @@
 the default being \fB100000\fR.
 .
 .TP
-.B \-Wnon\-ansi\-function\-declaration
-Warn about non-ANSI function declarations.
-
-Sparse issues these warnings by default.  To turn them off, use
-\fB\-Wno\-non\-ansi\-function\-declaration\fR.
-.
-.TP
 .B \-Wnon\-pointer\-null
 Warn about the use of 0 as a NULL pointer.
 
@@ -366,10 +383,22 @@
 Sparse does not issue these warnings by default.
 .
 .TP
+.B \-Wshift-count-negative
+Warn if a shift count is negative.
+
+Sparse issues these warnings by default.
+.
+.TP
+.B \-Wshift-count-overflow
+Warn if a shift count is bigger than the operand's width.
+
+Sparse issues these warnings by default.
+.
+.TP
 .B \-Wsizeof-bool
 Warn when checking the sizeof a _Bool.
 
-C99 does not specify the sizeof a _Bool.  gcc uses 1.
+C99 does not specify the size of a _Bool. GCC, by default, uses \fI1\fR.
 
 Sparse does not issue these warnings by default.
 .
@@ -412,19 +441,20 @@
 .
 .SH DEBUG OPTIONS
 .TP
-.B \-fdump-linearize[=only]
-Dump the IR code of a function directly after its linearization,
-before any simplifications are made. If the argument \fB=only\fR is
-also given no further processing is done on the function.
-.
 .B \-fmem-report
 Report some statistics about memory allocation used by the tool.
 .
 .SH OTHER OPTIONS
 .TP
+.B \-fdiagnostic-prefix[=PREFIX]
+Prefix all diagnostics by the given PREFIX, followed by ": ".
+If no one is given "sparse" is used.
+The default is to not use a prefix at all.
+.
+.TP
 .B \-fmemcpy-max-count=COUNT
 Set the limit for the warnings given by \fB-Wmemcpy-max-count\fR.
-A COUNT of 0, useless in itself, will effectively disable the warning.
+A COUNT of 'unlimited' or '0' will effectively disable the warning.
 The default limit is 100000.
 .
 .TP
@@ -433,6 +463,11 @@
 column numbers in warnings or errors.  If the value is less than 1 or
 greater than 100, the option is ignored.  The default is 8.
 .
+.TP
+.B \-f[no-]unsigned-char, \-f[no-]signed-char
+Let plain 'char' be unsigned or signed.
+By default chars are signed.
+.
 .SH SEE ALSO
 .BR cgcc (1)
 .
@@ -442,5 +477,18 @@
 .SH MAILING LIST
 linux-sparse@vger.kernel.org
 .
-.SH MAINTAINER
-Christopher Li <sparse@chrisli.org>
+.SH CONTRIBUTINGS AND REPORTING BUGS
+Submission of patches and reporting of bugs, as well as discussions
+related to Sparse, should be done via the mailing list (linux-sparse@vger.kernel.org)
+where the development and maintenance is primarily done.
+You do not have to be subscribed to the list to send a message there.
+
+Bugs can also be reported and tracked via the Linux kernel's bugzilla:
+http://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools .
+.
+.SH AUTHORS
+Sparse was started by Linus Torvalds.
+The complete list of contributors can be find at
+https://www.openhub.net/p/sparse/contributors .
+
+Luc Van Oostenryck is Sparse's current maintainer.
--- old/usr/src/tools/smatch/src/sparse.c	Mon Nov 18 13:19:32 2019
+++ new/usr/src/tools/smatch/src/sparse.c	Mon Nov 18 13:19:32 2019
@@ -47,6 +47,8 @@
 
 	FOR_EACH_PTR(bb->insns, insn) {
 		int val;
+		if (!insn->bb)
+			continue;
 		if (insn->opcode != OP_CONTEXT)
 			continue;
 		val = insn->increment;
@@ -120,7 +122,7 @@
 		int old = orig_type->bit_size;
 		int new = insn->size;
 		int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0;
-		int newsigned = insn->opcode == OP_SCAST;
+		int newsigned = insn->opcode == OP_SEXT;
 
 		if (new > old) {
 			if (oldsigned == newsigned)
@@ -214,7 +216,8 @@
 static void check_one_instruction(struct instruction *insn)
 {
 	switch (insn->opcode) {
-	case OP_CAST: case OP_SCAST:
+	case OP_SEXT: case OP_ZEXT:
+	case OP_TRUNC:
 		if (verbose)
 			check_cast_instruction(insn);
 		break;
@@ -243,6 +246,7 @@
 {
 	struct basic_block *bb;
 	FOR_EACH_PTR(ep->bbs, bb) {
+		bb->context = -1;
 		check_bb_instructions(bb);
 	} END_FOR_EACH_PTR(bb);
 }
@@ -271,6 +275,37 @@
 	check_bb_context(ep, ep->entry->bb, in_context, out_context);
 }
 
+/* list_compound_symbol - symbol info for arrays, structures, unions */
+static void list_compound_symbol(struct symbol *sym)
+{
+	struct symbol *base;
+
+	/* Only show symbols that have a positive size */
+	if (sym->bit_size <= 0)
+		return;
+	if (!sym->ctype.base_type)
+		return;
+	/* Don't show unnamed types */
+	if (!sym->ident)
+		return;
+
+	if (sym->type == SYM_NODE)
+		base = sym->ctype.base_type;
+	else
+		base = sym;
+	switch (base->type) {
+	case SYM_STRUCT: case SYM_UNION: case SYM_ARRAY:
+		break;
+	default:
+		return;
+	}
+
+	info(sym->pos, "%s: compound size %u, alignment %lu",
+		show_typename(sym),
+		bits_to_bytes(sym->bit_size),
+		sym->ctype.alignment);
+}
+
 static void check_symbols(struct symbol_list *list)
 {
 	struct symbol *sym;
@@ -280,12 +315,14 @@
 
 		expand_symbol(sym);
 		ep = linearize_symbol(sym);
-		if (ep) {
+		if (ep && ep->entry) {
 			if (dbg_entry)
 				show_entry(ep);
 
 			check_context(ep);
 		}
+		if (dbg_compound)
+			list_compound_symbol(sym);
 	} END_FOR_EACH_PTR(sym);
 
 	if (Wsparse_error && die_if_error)
@@ -297,11 +334,14 @@
 	struct string_list *filelist = NULL;
 	char *file;
 
+	// by default ignore -o <file>
+	do_output = 0;
+
 	// Expand, linearize and show it.
 	check_symbols(sparse_initialize(argc, argv, &filelist));
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		check_symbols(sparse(file));
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 	report_stats();
 	return 0;
--- old/usr/src/tools/smatch/src/sparse.pc.in	Mon Nov 18 13:19:33 2019
+++ /dev/null	Mon Nov 18 13:19:33 2019
@@ -1,9 +0,0 @@
-prefix=@prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Sparse
-Description: Semantic parser for C
-Version: @version@
-Libs: -L${libdir} -lsparse
-Cflags: -I${includedir}
--- old/usr/src/tools/smatch/src/sparsec	Mon Nov 18 13:19:33 2019
+++ new/usr/src/tools/smatch/src/sparsec	Mon Nov 18 13:19:33 2019
@@ -29,20 +29,29 @@
 	shift
 done
 
-TMPLLVM=`mktemp -t tmp.XXXXXX`".llvm"
-TMPFILE=`mktemp -t tmp.XXXXXX`".o"
+TMPFILE=`mktemp -t tmp.XXXXXX`
 
-$DIRNAME/sparse-llvm $SPARSEOPTS > $TMPLLVM
 
 LLC=`"${LLVM_CONFIG:-llvm-config}" --bindir`/llc
 
-$LLC -o - $TMPLLVM | as -o $TMPFILE
+LLC_ARCH_OPTS=
+case "$(uname -s)" in
+*CYGWIN*)
+	# cygwin uses the sjlj (setjmp-longjmp) exception model
+	LLC_ARCH_OPTS="-exception-model=sjlj"
+	;;
+*)
+	;;
+esac
 
+$DIRNAME/sparse-llvm $SPARSEOPTS | $LLC ${LLC_ARCH_OPTS} | as -o $TMPFILE
+
 if [ $NEED_LINK -eq 1 ]; then
 	if [ -z $OUTFILE ]; then
 		OUTFILE=a.out
 	fi
 	gcc $TMPFILE -o $OUTFILE
+	rm -f $TMPFILE
 else
 	if [ -z $OUTFILE ]; then
 		echo "`basename $0`: no output file"
@@ -50,5 +59,3 @@
 	fi
 	mv $TMPFILE $OUTFILE
 fi
-
-rm -f $TMPLLVM
--- old/usr/src/tools/smatch/src/sparsei	Mon Nov 18 13:19:33 2019
+++ new/usr/src/tools/smatch/src/sparsei	Mon Nov 18 13:19:33 2019
@@ -2,6 +2,9 @@
 
 set +e
 
+SPARSEOPTS=
+JIT_OPT=
+
 DIRNAME=`dirname $0`
 LLI=`"${LLVM_CONFIG:-llvm-config}" --bindir`/lli
 
@@ -10,4 +13,19 @@
   exit 1
 fi
 
-$DIRNAME/sparse-llvm $@ | $LLI
+while [ $# -gt 0 ]; do
+	case $1 in
+	--jit)
+		JIT_OPT=
+		;;
+	--no-jit)
+		JIT_OPT="-force-interpreter"
+		;;
+	*)
+		SPARSEOPTS="$SPARSEOPTS $1 "
+		;;
+	esac
+	shift
+done
+
+$DIRNAME/sparse-llvm ${SPARSEOPTS} | $LLI ${JIT_OPT}
--- /dev/null	Mon Nov 18 13:19:34 2019
+++ new/usr/src/tools/smatch/src/ssa.c	Mon Nov 18 13:19:34 2019
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: MIT
+//
+// SSA conversion
+// Copyright (C) 2005 Luc Van Oostenryck
+//
+
+#include <assert.h>
+#include "ssa.h"
+#include "lib.h"
+#include "sset.h"
+#include "dominate.h"
+#include "flowgraph.h"
+#include "linearize.h"
+#include "flow.h"			// for convert_load_instruction()
+
+
+// Is it possible and desirable for this to be promoted to a pseudo?
+static inline bool is_promotable(struct symbol *type)
+{
+	struct symbol *member;
+	int bf_seen;
+	int nbr;
+
+	if (type->type == SYM_NODE)
+		type = type->ctype.base_type;
+	switch (type->type) {
+	case SYM_ENUM:
+	case SYM_BITFIELD:
+	case SYM_PTR:
+	case SYM_RESTRICT:	// OK, always integer types
+		return 1;
+	case SYM_STRUCT:
+		// we allow a single scalar field
+		// but a run of bitfields count for 1
+		nbr = 0;
+		bf_seen = 0;
+		FOR_EACH_PTR(type->symbol_list, member) {
+			if (is_bitfield_type(member)) {
+				if (bf_seen)
+					continue;
+				bf_seen = 1;
+			} else {
+				bf_seen = 0;
+			}
+			if (!is_scalar_type(member))
+				return 0;
+			if (nbr++)
+				return 0;
+		} END_FOR_EACH_PTR(member);
+		if (bf_seen && (type->bit_size > long_ctype.bit_size))
+			return 0;
+		return 1;
+	case SYM_UNION:
+		// FIXME: should be like struct but has problem
+		//        when used with/for type cohercion
+		// -----> OK if only same sized integral types
+		FOR_EACH_PTR(type->symbol_list, member) {
+			if (member->bit_size != type->bit_size)
+				return 0;
+			if (!is_integral_type(member))
+				return 0;
+		} END_FOR_EACH_PTR(member);
+		return 1;
+	default:
+		break;
+	}
+	if (type->ctype.base_type == &int_type)
+		return 1;
+	if (type->ctype.base_type == &fp_type)
+		return 1;
+	return 0;
+}
+
+static bool insn_before(struct instruction *a, struct instruction *b)
+{
+	struct basic_block *bb = a->bb;
+	struct instruction *insn;
+
+	assert(b->bb == bb);
+	FOR_EACH_PTR(bb->insns, insn) {
+		if (insn == a)
+			return true;
+		if (insn == b)
+			return false;
+	} END_FOR_EACH_PTR(insn);
+	assert(0);
+}
+
+static void kill_store(struct instruction *insn)
+{
+	remove_use(&insn->src);
+	remove_use(&insn->target);
+	insn->bb = NULL;
+}
+
+static void rewrite_local_var(struct basic_block *bb, pseudo_t addr, int nbr_stores, int nbr_uses)
+{
+	struct instruction *insn;
+	pseudo_t val = NULL;
+
+	if (!bb)
+		return;
+
+	FOR_EACH_PTR(bb->insns, insn) {
+
+		if (!insn->bb || insn->src != addr)
+			continue;
+		switch (insn->opcode) {
+		case OP_LOAD:
+			if (!val)
+				val = undef_pseudo();
+			convert_load_instruction(insn, val);
+			break;
+		case OP_STORE:
+			val = insn->target;
+			// can't use kill_instruction() unless
+			// we add a fake user to val
+			kill_store(insn);
+			break;
+		}
+	} END_FOR_EACH_PTR(insn);
+}
+
+static bool rewrite_single_store(struct instruction *store)
+{
+	pseudo_t addr = store->src;
+	struct pseudo_user *pu;
+
+	FOR_EACH_PTR(addr->users, pu) {
+		struct instruction *insn = pu->insn;
+
+		if (insn->opcode != OP_LOAD)
+			continue;
+
+		// Let's try to replace the value of the load
+		// by the value from the store. This is only valid
+		// if the store dominate the load.
+
+		if (insn->bb == store->bb) {
+			// the load and the store are in the same BB
+			// we can convert if the load is after the store.
+			if (!insn_before(store, insn))
+				continue;
+		} else if (!domtree_dominates(store->bb, insn->bb)) {
+			// we can't convert this load
+			continue;
+		}
+
+		// OK, we can rewrite this load
+
+		// undefs ?
+
+		convert_load_instruction(insn, store->target);
+	} END_FOR_EACH_PTR(pu);
+
+	// is there some unconverted loads?
+	if (pseudo_user_list_size(addr->users) > 1)
+		return false;
+
+	kill_store(store);
+	return true;
+}
+
+static struct sset *processed;
+
+// we would like to know:
+// is there one or more stores?
+// are all loads & stores local/done in a single block?
+static void ssa_convert_one_var(struct entrypoint *ep, struct symbol *var)
+{
+	struct basic_block_list *alpha = NULL;
+	struct basic_block_list *idf = NULL;
+	struct basic_block *samebb = NULL;
+	struct instruction *store = NULL;
+	struct basic_block *bb;
+	struct pseudo_user *pu;
+	unsigned long mod = var->ctype.modifiers;
+	bool local = true;
+	int nbr_stores = 0;
+	int nbr_uses   = 0;
+	pseudo_t addr;
+
+	/* Never used as a symbol? */
+	addr = var->pseudo;
+	if (!addr)
+		return;
+
+	/* We don't do coverage analysis of volatiles.. */
+	if (mod & MOD_VOLATILE)
+		return;
+
+	/* ..and symbols with external visibility need more care */
+	mod &= (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE);
+	if (mod)
+		goto external_visibility;
+
+	if (!is_promotable(var))
+		return;
+
+	// 1) insert in the worklist all BBs that may modify var
+	sset_reset(processed);
+	FOR_EACH_PTR(addr->users, pu) {
+		struct instruction *insn = pu->insn;
+		struct basic_block *bb = insn->bb;
+
+		switch (insn->opcode) {
+		case OP_STORE:
+			nbr_stores++;
+			store = insn;
+			if (!sset_testset(processed, bb->nr))
+				add_bb(&alpha, bb);
+			/* fall through */
+		case OP_LOAD:
+			if (local) {
+				if (!samebb)
+					samebb = bb;
+				else if (samebb != bb)
+					local = false;
+			}
+			nbr_uses++;
+			break;
+		case OP_SYMADDR:
+			mod |= MOD_ADDRESSABLE;
+			goto external_visibility;
+		default:
+			warning(var->pos, "symbol '%s' pseudo used in unexpected way",
+				show_ident(var->ident));
+		}
+	} END_FOR_EACH_PTR(pu);
+
+	if (nbr_stores == 1) {
+		if (rewrite_single_store(store))
+			return;
+	}
+
+	// if all uses are local to a single block
+	// they can easily be rewritten and doesn't need phi-nodes
+	// FIXME: could be done for extended BB too
+	if (local) {
+		rewrite_local_var(samebb, addr, nbr_stores, nbr_uses);
+		return;
+	}
+
+	idf_compute(ep, &idf, alpha);
+	FOR_EACH_PTR(idf, bb) {
+		struct instruction *node = insert_phi_node(bb, var);
+		node->phi_var = var->pseudo;
+	} END_FOR_EACH_PTR(bb);
+	var->torename = 1;
+
+external_visibility:
+	if (mod & (MOD_NONLOCAL | MOD_STATIC))
+		return;
+	kill_dead_stores(ep, addr, !mod);
+}
+
+static pseudo_t lookup_var(struct basic_block *bb, struct symbol *var)
+{
+	do {
+		pseudo_t val = phi_map_lookup(bb->phi_map, var);
+		if (val)
+			return val;
+	} while ((bb = bb->idom));
+	return undef_pseudo();
+}
+
+static struct instruction_list *phis_all;
+static struct instruction_list *phis_used;
+
+static void ssa_rename_insn(struct basic_block *bb, struct instruction *insn)
+{
+	struct symbol *var;
+	pseudo_t addr;
+	pseudo_t val;
+
+	switch (insn->opcode) {
+	case OP_STORE:
+		addr = insn->src;
+		if (addr->type != PSEUDO_SYM)
+			break;
+		var = addr->sym;
+		if (!var || !var->torename)
+			break;
+		phi_map_update(&bb->phi_map, var, insn->target);
+		kill_store(insn);
+		break;
+	case OP_LOAD:
+		addr = insn->src;
+		if (addr->type != PSEUDO_SYM)
+			break;
+		var = addr->sym;
+		if (!var || !var->torename)
+			break;
+		val = lookup_var(bb, var);
+		convert_load_instruction(insn, val);
+		break;
+	case OP_PHI:
+		var = insn->type;
+		if (!var || !var->torename)
+			break;
+		phi_map_update(&bb->phi_map, var, insn->target);
+		add_instruction(&phis_all, insn);
+		break;
+	}
+}
+
+static void ssa_rename_insns(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+
+	FOR_EACH_PTR(ep->bbs, bb) {
+		struct instruction *insn;
+		FOR_EACH_PTR(bb->insns, insn) {
+			if (!insn->bb)
+				continue;
+			ssa_rename_insn(bb, insn);
+		} END_FOR_EACH_PTR(insn);
+	} END_FOR_EACH_PTR(bb);
+}
+
+static void mark_phi_used(pseudo_t val)
+{
+	struct instruction *node;
+
+	if (val->type != PSEUDO_REG)
+		return;
+	node = val->def;
+	if (node->opcode != OP_PHI)
+		return;
+	if (node->used)
+		return;
+	node->used = 1;
+	add_instruction(&phis_used, node);
+}
+
+static void ssa_rename_phi(struct instruction *insn)
+{
+	struct basic_block *par;
+	struct symbol *var;
+
+	if (!insn->phi_var)
+		return;
+	var = insn->phi_var->sym;
+	if (!var->torename)
+		return;
+	FOR_EACH_PTR(insn->bb->parents, par) {
+		struct instruction *term = delete_last_instruction(&par->insns);
+		pseudo_t val = lookup_var(par, var);
+		pseudo_t phi = alloc_phi(par, val, var);
+		phi->ident = var->ident;
+		add_instruction(&par->insns, term);
+		use_pseudo(insn, phi, add_pseudo(&insn->phi_list, phi));
+		mark_phi_used(val);
+	} END_FOR_EACH_PTR(par);
+}
+
+static void ssa_rename_phis(struct entrypoint *ep)
+{
+	struct instruction *phi;
+
+	phis_used = NULL;
+	FOR_EACH_PTR(phis_all, phi) {
+		if (has_users(phi->target)) {
+			phi->used = 1;
+			add_instruction(&phis_used, phi);
+		}
+	} END_FOR_EACH_PTR(phi);
+
+	FOR_EACH_PTR(phis_used, phi) {
+		if (!phi->bb)
+			continue;
+		ssa_rename_phi(phi);
+	} END_FOR_EACH_PTR(phi);
+}
+
+void ssa_convert(struct entrypoint *ep)
+{
+	struct basic_block *bb;
+	pseudo_t pseudo;
+	int first, last;
+
+	// calculate the number of BBs
+	first = ep->entry->bb->nr;
+	last = first;
+	FOR_EACH_PTR(ep->bbs, bb) {
+		int nr = bb->nr;
+		if (nr > last)
+			last = nr;
+	} END_FOR_EACH_PTR(bb);
+
+	processed = sset_init(first, last);
+
+	// try to promote memory accesses to pseudos
+	FOR_EACH_PTR(ep->accesses, pseudo) {
+		ssa_convert_one_var(ep, pseudo->sym);
+	} END_FOR_EACH_PTR(pseudo);
+
+	// rename the converted accesses
+	phis_all = phis_used = NULL;
+	ssa_rename_insns(ep);
+	ssa_rename_phis(ep);
+}
--- /dev/null	Mon Nov 18 13:19:34 2019
+++ new/usr/src/tools/smatch/src/ssa.h	Mon Nov 18 13:19:34 2019
@@ -0,0 +1,8 @@
+#ifndef SSA_H
+#define SSA_H
+
+struct entrypoint;
+
+void ssa_convert(struct entrypoint *ep);
+
+#endif
--- /dev/null	Mon Nov 18 13:19:34 2019
+++ new/usr/src/tools/smatch/src/sset.c	Mon Nov 18 13:19:34 2019
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: MIT
+//
+// sset.c - an all O(1) implementation of sparse sets as presented in:
+//	"An Efficient Representation for Sparse Sets"
+//	by Preston Briggs and Linda Torczon
+//
+// Copyright (C) 2017 - Luc Van Oostenryck
+
+#include "sset.h"
+#include "lib.h"
+#include <stdlib.h>
+
+
+struct sset *sset_init(unsigned int first, unsigned int last)
+{
+	unsigned int size = last - first + 1;
+	struct sset *s = malloc(sizeof(*s) + size * 2 * sizeof(s->sets[0]));
+
+	s->size = size;
+	s->off = first;
+	s->nbr = 0;
+	return s;
+}
+
+void sset_free(struct sset *s)
+{
+	free(s);
+}
--- /dev/null	Mon Nov 18 13:19:34 2019
+++ new/usr/src/tools/smatch/src/sset.h	Mon Nov 18 13:19:34 2019
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: MIT
+
+#ifndef SSET_H
+#define SSET_H
+
+/*
+ * sset.h - an all O(1) implementation of sparse sets as presented in:
+ *	"An Efficient Representation for Sparse Sets"
+ *	by Preston Briggs and Linda Torczon
+ *
+ * Copyright (C) 2017 - Luc Van Oostenryck
+ */
+
+#include <stdbool.h>
+
+struct sset {
+	unsigned int nbr;
+	unsigned int off;
+	unsigned int size;
+	unsigned int sets[0];
+};
+
+extern struct sset *sset_init(unsigned int size, unsigned int off);
+extern void sset_free(struct sset *s);
+
+
+static inline void sset_reset(struct sset *s)
+{
+	s->nbr = 0;
+}
+
+static inline void sset_add(struct sset *s, unsigned int idx)
+{
+	unsigned int __idx = idx - s->off;
+	unsigned int n = s->nbr++;
+	s->sets[__idx] = n;
+	s->sets[s->size + n] = __idx;
+}
+
+static inline bool sset_test(struct sset *s, unsigned int idx)
+{
+	unsigned int __idx = idx - s->off;
+	unsigned int n = s->sets[__idx];
+
+	return (n < s->nbr) && (s->sets[s->size + n] == __idx);
+}
+
+static inline bool sset_testset(struct sset *s, unsigned int idx)
+{
+	if (sset_test(s, idx))
+		return true;
+	sset_add(s, idx);
+	return false;
+}
+
+#endif
--- old/usr/src/tools/smatch/src/symbol.c	Mon Nov 18 13:19:34 2019
+++ new/usr/src/tools/smatch/src/symbol.c	Mon Nov 18 13:19:34 2019
@@ -33,6 +33,7 @@
 #include "symbol.h"
 #include "scope.h"
 #include "expression.h"
+#include "evaluate.h"
 
 #include "target.h"
 
@@ -48,9 +49,9 @@
 void access_symbol(struct symbol *sym)
 {
 	if (sym->ctype.modifiers & MOD_INLINE) {
-		if (!(sym->ctype.modifiers & MOD_ACCESSED)) {
+		if (!sym->accessed) {
 			add_symbol(&translation_unit_used_list, sym);
-			sym->ctype.modifiers |= MOD_ACCESSED;
+			sym->accessed = 1;
 		}
 	}
 }
@@ -213,7 +214,7 @@
 	base_type = examine_symbol_type(sym->ctype.base_type);
 	if (!base_type || base_type->type == SYM_PTR)
 		return base_type;
-	sym->ctype.as |= base_type->ctype.as;
+	combine_address_space(sym->pos, &sym->ctype.as, base_type->ctype.as);
 	sym->ctype.modifiers |= base_type->ctype.modifiers & MOD_PTRINHERIT;
 	concat_ptr_list((struct ptr_list *)base_type->ctype.contexts,
 			(struct ptr_list **)&sym->ctype.contexts);
@@ -277,7 +278,7 @@
  */
 void merge_type(struct symbol *sym, struct symbol *base_type)
 {
-	sym->ctype.as |= base_type->ctype.as;
+	combine_address_space(sym->pos, &sym->ctype.as, base_type->ctype.as);
 	sym->ctype.modifiers |= (base_type->ctype.modifiers & ~MOD_STORAGE);
 	concat_ptr_list((struct ptr_list *)base_type->ctype.contexts,
 	                (struct ptr_list **)&sym->ctype.contexts);
@@ -364,6 +365,23 @@
 	return NULL;
 }
 
+static unsigned int implicit_array_size(struct symbol *node, unsigned int count)
+{
+	struct symbol *arr_ori = node->ctype.base_type;
+	struct symbol *arr_new = alloc_symbol(node->pos, SYM_ARRAY);
+	struct symbol *elem_type = arr_ori->ctype.base_type;
+	struct expression *size = alloc_const_expression(node->pos, count);
+	unsigned int bit_size = array_element_offset(elem_type->bit_size, count);
+
+	*arr_new = *arr_ori;
+	arr_new->bit_size = bit_size;
+	arr_new->array_size = size;
+	node->array_size = size;
+	node->ctype.base_type = arr_new;
+
+	return bit_size;
+}
+
 static struct symbol * examine_node_type(struct symbol *sym)
 {
 	struct symbol *base_type = examine_base_type(sym);
@@ -393,7 +411,7 @@
 			int count = count_array_initializer(node_type, initializer);
 
 			if (node_type && node_type->bit_size >= 0)
-				bit_size = array_element_offset(node_type->bit_size, count);
+				bit_size = implicit_array_size(sym, count);
 		}
 	}
 	
@@ -479,13 +497,15 @@
 			sym->ctype.base_type = base;
 			return examine_node_type(sym);
 		}
-		break;
+		sym->type = SYM_NODE;
+		sym->ctype.base_type = &bad_ctype;
+		return sym;
 	}
 	case SYM_PREPROCESSOR:
 		sparse_error(sym->pos, "ctype on preprocessor command? (%s)", show_ident(sym->ident));
 		return NULL;
 	case SYM_UNINITIALIZED:
-//		sparse_error(sym->pos, "ctype on uninitialized symbol %p", sym);
+//		sparse_error(sym->pos, "ctype on uninitialized symbol '%s'", show_typename(sym));
 		return NULL;
 	case SYM_RESTRICT:
 		examine_base_type(sym);
@@ -677,6 +697,14 @@
 		string_ctype, ptr_ctype, lazy_ptr_ctype,
 		incomplete_ctype, label_ctype, bad_ctype,
 		null_ctype;
+struct symbol	int_ptr_ctype, uint_ptr_ctype;
+struct symbol	long_ptr_ctype, ulong_ptr_ctype;
+struct symbol	llong_ptr_ctype, ullong_ptr_ctype;
+struct symbol	float32_ctype, float32x_ctype;
+struct symbol	float64_ctype, float64x_ctype;
+struct symbol	float128_ctype;
+struct symbol	const_void_ctype, const_char_ctype;
+struct symbol	const_ptr_ctype, const_string_ctype;
 
 struct symbol	zero_int;
 
@@ -703,6 +731,10 @@
 #else
 #define CHAR_SIGNEDNESS MOD_SIGNED
 #endif
+// For fix-sized types
+static int bits_in_type32 = 32;
+static int bits_in_type64 = 64;
+static int bits_in_type128 = 128;
 
 #define MOD_ESIGNED (MOD_SIGNED | MOD_EXPLICITLY_SIGNED)
 #define MOD_LL (MOD_LONG | MOD_LONGLONG)
@@ -744,11 +776,28 @@
 	{ &double_ctype,    SYM_BASETYPE, MOD_LONG,		    &bits_in_double,         &max_fp_alignment,  &fp_type },
 	{ &ldouble_ctype,   SYM_BASETYPE, MOD_LONG | MOD_LONGLONG,  &bits_in_longdouble,     &max_fp_alignment,  &fp_type },
 
+	{ &float32_ctype,   SYM_BASETYPE,  0,			    &bits_in_type32,          &max_fp_alignment, &fp_type },
+	{ &float32x_ctype,  SYM_BASETYPE, MOD_LONG,		    &bits_in_double,         &max_fp_alignment,  &fp_type },
+	{ &float64_ctype,   SYM_BASETYPE,  0,			    &bits_in_type64,          &max_fp_alignment, &fp_type },
+	{ &float64x_ctype,  SYM_BASETYPE, MOD_LONG | MOD_LONGLONG,  &bits_in_longdouble,     &max_fp_alignment,  &fp_type },
+	{ &float128_ctype,  SYM_BASETYPE,  0,			    &bits_in_type128,         &max_alignment,    &fp_type },
+
 	{ &string_ctype,    SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &char_ctype },
 	{ &ptr_ctype,	    SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &void_ctype },
 	{ &null_ctype,	    SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &void_ctype },
 	{ &label_ctype,	    SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &void_ctype },
 	{ &lazy_ptr_ctype,  SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &void_ctype },
+	{ &int_ptr_ctype,   SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &int_ctype },
+	{ &uint_ptr_ctype,  SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &uint_ctype },
+	{ &long_ptr_ctype,  SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &long_ctype },
+	{ &ulong_ptr_ctype, SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &ulong_ctype },
+	{ &llong_ptr_ctype, SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &llong_ctype },
+	{ &ullong_ptr_ctype,SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &ullong_ctype },
+
+	{ &const_void_ctype, SYM_NODE,	  MOD_CONST,		    NULL, NULL, &void_ctype },
+	{ &const_char_ctype, SYM_NODE,	  MOD_CONST,		    &bits_in_char, &max_int_alignment, &char_ctype },
+	{ &const_ptr_ctype, SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &const_void_ctype },
+	{ &const_string_ctype,SYM_PTR,	  0,			    &bits_in_pointer,        &pointer_alignment, &const_char_ctype },
 	{ NULL, }
 };
 #undef MOD_LLL
@@ -773,4 +822,10 @@
 		sym->ctype.base_type = ctype->base_type;
 		sym->ctype.modifiers = ctype->modifiers;
 	}
+
+	// and now some adjustments
+	if (funsigned_char) {
+		char_ctype.ctype.modifiers |= MOD_UNSIGNED;
+		char_ctype.ctype.modifiers &= ~MOD_SIGNED;
+	}
 }
--- old/usr/src/tools/smatch/src/symbol.h	Mon Nov 18 13:19:35 2019
+++ new/usr/src/tools/smatch/src/symbol.h	Mon Nov 18 13:19:35 2019
@@ -101,7 +101,7 @@
 	unsigned long modifiers;
 	unsigned long alignment;
 	struct context_list *contexts;
-	unsigned int as;
+	struct ident *as;
 	struct symbol *base_type;
 };
 
@@ -110,6 +110,7 @@
 	struct ident **ident;
 	struct symbol_op *mode;
 	unsigned char prefer_abstract, is_inline, storage_class, is_tls;
+	unsigned char is_ext_visible;
 };
 
 struct symbol_op {
@@ -124,6 +125,7 @@
 	struct token *(*toplevel)(struct token *token, struct symbol_list **list);
 	struct token *(*attribute)(struct token *token, struct symbol *attr, struct decl_state *ctx);
 	struct symbol *(*to_mode)(struct symbol *);
+	void          (*asm_modifier)(struct token *token, unsigned long *mods);
 
 	int test, set, class;
 };
@@ -155,6 +157,7 @@
 			struct token *expansion;
 			struct token *arglist;
 			struct scope *used_in;
+			void (*expander)(struct token *);
 		};
 		struct /* NS_PREPROCESSOR */ {
 			int (*handler)(struct stream *, struct token **, struct token *);
@@ -164,7 +167,6 @@
 			unsigned long	offset;
 			int		bit_size;
 			unsigned int	bit_offset:8,
-					arg_count:10,
 					variadic:1,
 					initialized:1,
 					examined:1,
@@ -173,6 +175,9 @@
 					string:1,
 					designated_init:1,
 					forced_arg:1,
+					accessed:1,
+					builtin:1,
+					torename:1,
 					transparent_union:1;
 			struct expression *array_size;
 			struct ctype ctype;
@@ -183,7 +188,6 @@
 			struct symbol_list *inline_symbol_list;
 			struct expression *initializer;
 			struct entrypoint *ep;
-			long long value;		/* Initial value */
 			struct symbol *definition;
 		};
 	};
@@ -199,44 +203,45 @@
 };
 
 /* Modifiers */
-#define MOD_AUTO	0x0001
-#define MOD_REGISTER	0x0002
-#define MOD_STATIC	0x0004
-#define MOD_EXTERN	0x0008
+#define MOD_AUTO		0x00000001
+#define MOD_REGISTER		0x00000002
+#define MOD_STATIC		0x00000004
+#define MOD_EXTERN		0x00000008
+#define MOD_TOPLEVEL		0x00000010	// scoping..
+#define MOD_TLS			0x00000020
+#define MOD_ASM_GOTO		MOD_TLS		// never used together
+#define MOD_INLINE		0x00000040
 
-#define MOD_CONST	0x0010
-#define MOD_VOLATILE	0x0020
-#define MOD_SIGNED	0x0040
-#define MOD_UNSIGNED	0x0080
+#define MOD_ASSIGNED		0x00000080
+#define MOD_ADDRESSABLE		0x00000100
 
-#define MOD_CHAR	0x0100
-#define MOD_SHORT	0x0200
-#define MOD_LONG	0x0400
-#define MOD_LONGLONG	0x0800
-#define MOD_LONGLONGLONG	0x1000
-#define MOD_PURE	0x2000
+#define MOD_CONST		0x00000200
+#define MOD_VOLATILE		0x00000400
+#define MOD_RESTRICT		0x00000800
+#define MOD_ATOMIC		0x00001000
 
-#define MOD_TYPEDEF	0x10000
+#define MOD_SIGNED		0x00002000
+#define MOD_UNSIGNED		0x00004000
+#define MOD_EXPLICITLY_SIGNED	0x00008000
 
-#define MOD_TLS		0x20000
-#define MOD_INLINE	0x40000
-#define MOD_ADDRESSABLE	0x80000
+#define MOD_TYPE		0x00010000
+#define MOD_USERTYPE		0x00020000
+#define MOD_CHAR		0x00040000
+#define MOD_SHORT		0x00080000
+#define MOD_LONG		0x00100000
+#define MOD_LONGLONG		0x00200000
+#define MOD_LONGLONGLONG	0x00400000
 
-#define MOD_NOCAST	0x100000
-#define MOD_NODEREF	0x200000
-#define MOD_ACCESSED	0x400000
-#define MOD_TOPLEVEL	0x800000	// scoping..
+#define MOD_SAFE		0x00800000	// non-null/non-trapping pointer
+#define MOD_PURE		0x01000000
+#define MOD_BITWISE		0x02000000
+#define MOD_NOCAST		0x04000000
+#define MOD_NODEREF		0x08000000
+#define MOD_NORETURN		0x10000000
+#define MOD_EXT_VISIBLE		0x20000000
 
-#define MOD_ASSIGNED	0x2000000
-#define MOD_TYPE	0x4000000
-#define MOD_SAFE	0x8000000	// non-null/non-trapping pointer
 
-#define MOD_USERTYPE	0x10000000
-#define MOD_NORETURN	0x20000000
-#define MOD_EXPLICITLY_SIGNED	0x40000000
-#define MOD_BITWISE	0x80000000
-
-
+#define MOD_ACCESS	(MOD_ASSIGNED | MOD_ADDRESSABLE)
 #define MOD_NONLOCAL	(MOD_EXTERN | MOD_TOPLEVEL)
 #define MOD_STORAGE	(MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL)
 #define MOD_SIGNEDNESS	(MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED)
@@ -243,11 +248,11 @@
 #define MOD_LONG_ALL	(MOD_LONG | MOD_LONGLONG | MOD_LONGLONGLONG)
 #define MOD_SPECIFIER	(MOD_CHAR | MOD_SHORT | MOD_LONG_ALL | MOD_SIGNEDNESS)
 #define MOD_SIZE	(MOD_CHAR | MOD_SHORT | MOD_LONG_ALL)
-#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE |	\
-	MOD_ASSIGNED | MOD_USERTYPE | MOD_ACCESSED | MOD_EXPLICITLY_SIGNED)
-#define MOD_PTRINHERIT (MOD_VOLATILE | MOD_CONST | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
+#define MOD_IGNORE	(MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED | MOD_EXT_VISIBLE)
+#define	MOD_QUALIFIER	(MOD_CONST | MOD_VOLATILE | MOD_RESTRICT | MOD_ATOMIC)
+#define MOD_PTRINHERIT	(MOD_QUALIFIER | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
 /* modifiers preserved by typeof() operator */
-#define MOD_TYPEOF	(MOD_VOLATILE | MOD_CONST | MOD_NOCAST | MOD_SPECIFIER)
+#define MOD_TYPEOF	(MOD_QUALIFIER | MOD_NOCAST | MOD_SPECIFIER)
 
 
 /* Current parsing/evaluation function */
@@ -269,7 +274,18 @@
 			string_ctype, ptr_ctype, lazy_ptr_ctype,
 			incomplete_ctype, label_ctype, bad_ctype,
 			null_ctype;
+extern struct symbol	int_ptr_ctype, uint_ptr_ctype;
+extern struct symbol	long_ptr_ctype, ulong_ptr_ctype;
+extern struct symbol	llong_ptr_ctype, ullong_ptr_ctype;
+extern struct symbol	float32_ctype, float32x_ctype;
+extern struct symbol	float64_ctype, float64x_ctype;
+extern struct symbol	float128_ctype;
+extern struct symbol	const_void_ctype, const_char_ctype;
+extern struct symbol	const_ptr_ctype, const_string_ctype;
 
+#define	uintptr_ctype	 size_t_ctype
+#define	 intptr_ctype	ssize_t_ctype
+
 /* Special internal symbols */
 extern struct symbol	zero_int;
 
@@ -277,7 +293,6 @@
 	extern struct ident n
 #include "ident-list.h"
 
-#define symbol_is_typename(sym) ((sym)->type == SYM_TYPE)
 
 extern struct symbol_list *translation_unit_used_list;
 
@@ -290,7 +305,9 @@
 extern struct symbol *create_symbol(int stream, const char *name, int type, int namespace);
 extern void init_symbols(void);
 extern void init_builtins(int stream);
+extern void declare_builtins(void);
 extern void init_ctype(void);
+extern void init_target(void);
 extern struct symbol *alloc_symbol(struct position, int type);
 extern void show_type(struct symbol *);
 extern const char *modifier_string(unsigned long mod);
@@ -303,9 +320,10 @@
 
 extern struct symbol *examine_symbol_type(struct symbol *);
 extern struct symbol *examine_pointer_target(struct symbol *);
-extern void examine_simple_symbol_type(struct symbol *);
+extern const char *show_as(struct ident *as);
 extern const char *show_typename(struct symbol *sym);
 extern const char *builtin_typename(struct symbol *sym);
+extern const char *builtin_type_suffix(struct symbol *sym);
 extern const char *builtin_ctypename(struct ctype *ctype);
 extern const char* get_type_name(enum type type);
 
@@ -312,12 +330,23 @@
 extern void debug_symbol(struct symbol *);
 extern void merge_type(struct symbol *sym, struct symbol *base_type);
 extern void check_declaration(struct symbol *sym);
+extern void check_duplicates(struct symbol *sym);
 
+static inline int valid_type(const struct symbol *ctype)
+{
+	return ctype && ctype != &bad_ctype;
+}
+
 static inline struct symbol *get_base_type(const struct symbol *sym)
 {
 	return examine_symbol_type(sym->ctype.base_type);
 }
 
+///
+// test if type is an integer type
+//
+// @return: ``1`` for plain integer type, enums & bitfields
+//	but ``0`` for bitwise types!
 static inline int is_int_type(const struct symbol *type)
 {
 	if (type->type == SYM_NODE)
@@ -335,6 +364,15 @@
 	return (type->type == SYM_ENUM);
 }
 
+static inline int is_signed_type(struct symbol *sym)
+{
+	if (sym->type == SYM_NODE)
+		sym = sym->ctype.base_type;
+	if (sym->type == SYM_PTR)
+		return 0;
+	return !(sym->ctype.modifiers & MOD_UNSIGNED);
+}
+
 static inline int is_type_type(struct symbol *type)
 {
 	return (type->ctype.modifiers & MOD_TYPE) != 0;
@@ -409,6 +447,24 @@
 	return 0;
 }
 
+/// return true for integer & pointer types
+static inline bool is_integral_type(struct symbol *type)
+{
+	if (type->type == SYM_NODE)
+		type = type->ctype.base_type;
+	switch (type->type) {
+	case SYM_ENUM:
+	case SYM_PTR:
+	case SYM_RESTRICT:	// OK, always integer types
+		return 1;
+	default:
+		break;
+	}
+	if (type->ctype.base_type == &int_type)
+		return 1;
+	return 0;
+}
+
 static inline int is_function(struct symbol *type)
 {
 	return type && type->type == SYM_FN;
@@ -430,6 +486,14 @@
 	return type->type;
 }
 
+static inline long long extend_value(long long val, struct symbol *ctype)
+{
+	int is_signed = !(ctype->ctype.modifiers & MOD_UNSIGNED);
+	unsigned size = ctype->bit_size;
+
+	return bits_extend(val, size, is_signed);
+}
+
 static inline struct symbol *lookup_keyword(struct ident *ident, enum namespace ns)
 {
 	if (!ident->keyword)
@@ -440,9 +504,31 @@
 #define is_restricted_type(type) (get_sym_type(type) == SYM_RESTRICT)
 #define is_fouled_type(type) (get_sym_type(type) == SYM_FOULED)
 #define is_bitfield_type(type)   (get_sym_type(type) == SYM_BITFIELD)
-extern int is_ptr_type(struct symbol *);
 
 void create_fouled(struct symbol *type);
 struct symbol *befoul(struct symbol *type);
 
+
+extern struct ident bad_address_space;
+
+static inline bool valid_as(struct ident *as)
+{
+	return as && as != &bad_address_space;
+}
+
+static inline void combine_address_space(struct position pos,
+	struct ident **tas, struct ident *sas)
+{
+	struct ident *as;
+	if (!sas)
+		return;
+	as = *tas;
+	if (!as)
+		*tas = sas;
+	else if (as != sas) {
+		*tas = &bad_address_space;
+		sparse_error(pos, "multiple address spaces given");
+	}
+}
+
 #endif /* SYMBOL_H */
--- old/usr/src/tools/smatch/src/target.c	Mon Nov 18 13:19:35 2019
+++ new/usr/src/tools/smatch/src/target.c	Mon Nov 18 13:19:35 2019
@@ -2,9 +2,18 @@
 
 #include "symbol.h"
 #include "target.h"
+#include "machine.h"
 
 struct symbol *size_t_ctype = &ulong_ctype;
 struct symbol *ssize_t_ctype = &long_ctype;
+struct symbol *intmax_ctype = &llong_ctype;
+struct symbol *uintmax_ctype = &ullong_ctype;
+struct symbol *int64_ctype = &long_ctype;
+struct symbol *uint64_ctype = &ulong_ctype;
+struct symbol *int32_ctype = &int_ctype;
+struct symbol *uint32_ctype = &uint_ctype;
+struct symbol *wchar_ctype = &int_ctype;
+struct symbol *wint_ctype = &uint_ctype;
 
 /*
  * For "__attribute__((aligned))"
@@ -22,8 +31,6 @@
 int bits_in_longlong = 64;
 int bits_in_longlonglong = 128;
 
-int bits_in_wchar = 32;
-
 int max_int_alignment = 4;
 
 /*
@@ -31,9 +38,9 @@
  */
 int bits_in_float = 32;
 int bits_in_double = 64;
-int bits_in_longdouble = 80;
+int bits_in_longdouble = 128;
 
-int max_fp_alignment = 8;
+int max_fp_alignment = 16;
 
 /*
  * Pointer data type
@@ -46,3 +53,111 @@
  */
 int bits_in_enum = 32;
 int enum_alignment = 4;
+
+
+void init_target(void)
+{
+	switch (arch_mach) {
+	case MACH_X86_64:
+		if (arch_m64 == ARCH_LP64)
+			break;
+		/* fall through */
+	case MACH_I386:
+	case MACH_M68K:
+	case MACH_SPARC32:
+	case MACH_PPC32:
+		wchar_ctype = &long_ctype;
+		break;
+	case MACH_ARM:
+	case MACH_ARM64:
+		wchar_ctype = &uint_ctype;
+		break;
+	default:
+		break;
+	}
+
+	switch (arch_mach) {
+	case MACH_MIPS64:
+		if (arch_m64 == ARCH_LP64)
+			break;
+		/* fall through */
+	case MACH_M68K:
+	case MACH_SPARC32:
+	case MACH_PPC32:
+	case MACH_MIPS32:
+	case MACH_RISCV32:
+		arch_m64 = ARCH_LP32;
+		int32_ctype = &long_ctype;
+		uint32_ctype = &ulong_ctype;
+		break;
+	default:
+		break;
+	}
+
+	switch (arch_mach) {
+	case MACH_ARM:
+	case MACH_MIPS32:
+	case MACH_S390X:
+	case MACH_SPARC32:
+		bits_in_longdouble = 64;
+		max_fp_alignment = 8;
+		break;
+	case MACH_X86_64:
+		if (arch_m64 == ARCH_LP64 || arch_m64 == ARCH_X32)
+			break;
+		/* fall through */
+	case MACH_I386:
+	case MACH_M68K:
+		bits_in_longdouble = 96;
+		max_fp_alignment = 4;
+		break;
+	default:
+		break;
+	}
+
+	switch (arch_m64) {
+	case ARCH_X32:
+		max_int_alignment = 8;
+		int64_ctype = &llong_ctype;
+		uint64_ctype = &ullong_ctype;
+		break;
+	case ARCH_LP32:
+		/* default values */
+		int64_ctype = &llong_ctype;
+		uint64_ctype = &ullong_ctype;
+		intmax_ctype = &llong_ctype;
+		uintmax_ctype = &ullong_ctype;
+		break;
+	case ARCH_LP64:
+		bits_in_long = 64;
+		max_int_alignment = 8;
+		size_t_ctype = &ulong_ctype;
+		ssize_t_ctype = &long_ctype;
+		intmax_ctype = &long_ctype;
+		uintmax_ctype = &ulong_ctype;
+		goto case_64bit_common;
+	case ARCH_LLP64:
+		bits_in_long = 32;
+		max_int_alignment = 8;
+		size_t_ctype = &ullong_ctype;
+		ssize_t_ctype = &llong_ctype;
+		int64_ctype = &llong_ctype;
+		uint64_ctype = &ullong_ctype;
+		goto case_64bit_common;
+	case_64bit_common:
+		bits_in_pointer = 64;
+		pointer_alignment = 8;
+		break;
+	}
+
+#if defined(__CYGWIN__)
+	wchar_ctype = &ushort_ctype;
+#endif
+#if defined(__FreeBSD__) || defined(__APPLE__)
+	wint_ctype = &int_ctype;
+#endif
+#if defined(__APPLE__)
+	int64_ctype = &llong_ctype;
+	uint64_ctype = &ullong_ctype;
+#endif
+}
--- old/usr/src/tools/smatch/src/target.h	Mon Nov 18 13:19:36 2019
+++ new/usr/src/tools/smatch/src/target.h	Mon Nov 18 13:19:36 2019
@@ -3,6 +3,14 @@
 
 extern struct symbol *size_t_ctype;
 extern struct symbol *ssize_t_ctype;
+extern struct symbol *intmax_ctype;
+extern struct symbol *uintmax_ctype;
+extern struct symbol *int64_ctype;
+extern struct symbol *uint64_ctype;
+extern struct symbol *int32_ctype;
+extern struct symbol *uint32_ctype;
+extern struct symbol *wchar_ctype;
+extern struct symbol *wint_ctype;
 
 /*
  * For "__attribute__((aligned))"
@@ -20,8 +28,6 @@
 extern int bits_in_longlong;
 extern int bits_in_longlonglong;
 
-extern int bits_in_wchar;
-
 extern int max_int_alignment;
 
 /*
--- old/usr/src/tools/smatch/src/test-dissect.c	Mon Nov 18 13:19:36 2019
+++ new/usr/src/tools/smatch/src/test-dissect.c	Mon Nov 18 13:19:36 2019
@@ -88,10 +88,10 @@
 
 	sparse_initialize(argc, argv, &filelist);
 
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		dotc_stream = input_stream_nr;
 		dissect(__sparse(file), &reporter);
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 	return 0;
 }
--- old/usr/src/tools/smatch/src/test-inspect.c	Mon Nov 18 13:19:36 2019
+++ new/usr/src/tools/smatch/src/test-inspect.c	Mon Nov 18 13:19:36 2019
@@ -32,11 +32,11 @@
 
 	gtk_init(&argc,&argv);
 	expand_symbols(sparse_initialize(argc, argv, &filelist));
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		struct symbol_list *syms = sparse(file);
 		expand_symbols(syms);
 		concat_symbol_list(syms, &view_syms);
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 	treeview_main(view_syms);
 	return 0;
 }
--- old/usr/src/tools/smatch/src/test-lexing.c	Mon Nov 18 13:19:37 2019
+++ new/usr/src/tools/smatch/src/test-lexing.c	Mon Nov 18 13:19:37 2019
@@ -41,9 +41,9 @@
 
 	preprocess_only = 1;
 	sparse_initialize(argc, argv, &filelist);
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		sparse(file);
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 	show_identifier_stats();
 	return 0;
 }
--- old/usr/src/tools/smatch/src/test-linearize.c	Mon Nov 18 13:19:38 2019
+++ new/usr/src/tools/smatch/src/test-linearize.c	Mon Nov 18 13:19:38 2019
@@ -47,6 +47,8 @@
 
 		expand_symbol(sym);
 		ep = linearize_symbol(sym);
+		if (!(fdump_ir & PASS_FINAL))
+			continue;
 		if (ep)
 			show_entry(ep);
 	} END_FOR_EACH_PTR(sym);
@@ -58,9 +60,9 @@
 	char *file;
 
 	clean_up_symbols(sparse_initialize(argc, argv, &filelist));
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		clean_up_symbols(sparse(file));
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 	report_stats();
 	return 0;
--- old/usr/src/tools/smatch/src/test-parsing.c	Mon Nov 18 13:19:38 2019
+++ new/usr/src/tools/smatch/src/test-parsing.c	Mon Nov 18 13:19:39 2019
@@ -64,7 +64,7 @@
 	printf("\n\n");
 #endif
 
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		list = sparse(file);
 
 		// Simplification
@@ -75,7 +75,7 @@
 		show_symbol_list(list, "\n\n");
 		printf("\n\n");
 #endif
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 #if 0
 	// And show the allocation statistics
--- old/usr/src/tools/smatch/src/test-unssa.c	Mon Nov 18 13:19:39 2019
+++ new/usr/src/tools/smatch/src/test-unssa.c	Mon Nov 18 13:19:39 2019
@@ -12,7 +12,7 @@
 	struct instruction *insn;
 
 	bb->generation = generation;
-	printf(".L%u\n", bb->nr);
+	printf("%s\n", show_label(bb));
 
 	FOR_EACH_PTR(bb->insns, insn) {
 		if (!insn->bb)
@@ -62,6 +62,8 @@
 		struct entrypoint *ep;
 		expand_symbol(sym);
 		ep = linearize_symbol(sym);
+		if (!(fdump_ir & PASS_FINAL))
+			continue;
 		if (ep)
 			output_fn(ep);
 		else
@@ -78,9 +80,9 @@
 	char *file;
 
 	compile(sparse_initialize(argc, argv, &filelist));
-	FOR_EACH_PTR_NOTAG(filelist, file) {
+	FOR_EACH_PTR(filelist, file) {
 		compile(sparse(file));
-	} END_FOR_EACH_PTR_NOTAG(file);
+	} END_FOR_EACH_PTR(file);
 
 	report_stats();
 	return 0;
--- old/usr/src/tools/smatch/src/token.h	Mon Nov 18 13:19:40 2019
+++ new/usr/src/tools/smatch/src/token.h	Mon Nov 18 13:19:40 2019
@@ -80,6 +80,7 @@
 
 enum token_type {
 	TOKEN_EOF,
+	TOKEN_BAD,
 	TOKEN_ERROR,
 	TOKEN_IDENT,
 	TOKEN_ZERO_IDENT,
@@ -238,6 +239,8 @@
 
 extern void store_macro_pos(struct token *);
 extern char *get_macro_name(struct position pos);
+extern char *get_inner_macro(struct position pos);
+extern struct string_list *get_all_macros(struct position pos);
 
 static inline int match_op(struct token *token, unsigned int op)
 {
--- old/usr/src/tools/smatch/src/tokenize.c	Mon Nov 18 13:19:40 2019
+++ new/usr/src/tools/smatch/src/tokenize.c	Mon Nov 18 13:19:40 2019
@@ -93,9 +93,13 @@
 
 const char *show_ident(const struct ident *ident)
 {
-	static char buffer[256];
+	static char buff[4][256];
+	static int n;
+	char *buffer;
+
 	if (!ident)
 		return "<noident>";
+	buffer = buff[3 & ++n];
 	sprintf(buffer, "%.*s", ident->len, ident->name);
 	return buffer;
 }
@@ -129,7 +133,7 @@
 	char *ptr;
 	int i;
 
-	if (!string->length)
+	if (!string || !string->length)
 		return "<bad_string>";
 	ptr = buffer;
 	*ptr++ = '"';
@@ -449,6 +453,7 @@
 	struct token *end;
 
 	end = alloc_token(stream);
+	eof_token_entry.pos = end->pos;
 	token_type(end) = TOKEN_STREAMEND;
 	end->pos.newline = 1;
 
@@ -488,9 +493,8 @@
 	Quote = 64,
 };
 
-static const long cclass[257] = {
-	['0' + 1 ... '7' + 1] = Digit | Hex,	/* \<octal> */
-	['8' + 1 ... '9' + 1] = Digit | Hex,
+static const char cclass[257] = {
+	['0' + 1 ... '9' + 1] = Digit | Hex,
 	['A' + 1 ... 'D' + 1] = Letter | Hex,
 	['E' + 1] = Letter | Hex | Exp,	/* E<exp> */
 	['F' + 1] = Letter | Hex,
@@ -497,23 +501,12 @@
 	['G' + 1 ... 'O' + 1] = Letter,
 	['P' + 1] = Letter | Exp,	/* P<exp> */
 	['Q' + 1 ... 'Z' + 1] = Letter,
-	['a' + 1 ... 'b' + 1] = Letter | Hex, /* \a, \b */
-	['c' + 1 ... 'd' + 1] = Letter | Hex,
-	['e' + 1] = Letter | Hex | Exp,/* \e, e<exp> */
-	['f' + 1] = Letter | Hex,	/* \f */
-	['g' + 1 ... 'm' + 1] = Letter,
-	['n' + 1] = Letter,	/* \n */
-	['o' + 1] = Letter,
+	['a' + 1 ... 'd' + 1] = Letter | Hex,
+	['e' + 1] = Letter | Hex | Exp,	/* e<exp> */
+	['f' + 1] = Letter | Hex,
+	['g' + 1 ... 'o' + 1] = Letter,
 	['p' + 1] = Letter | Exp,	/* p<exp> */
-	['q' + 1] = Letter,
-	['r' + 1] = Letter,	/* \r */
-	['s' + 1] = Letter,
-	['t' + 1] = Letter,	/* \t */
-	['u' + 1] = Letter,
-	['v' + 1] = Letter,	/* \v */
-	['w' + 1] = Letter,
-	['x' + 1] = Letter,	/* \x<hex> */
-	['y' + 1 ... 'z' + 1] = Letter,
+	['q' + 1 ... 'z' + 1] = Letter,
 	['_' + 1] = Letter,
 	['.' + 1] = Dot | ValidSecond,
 	['=' + 1] = ValidSecond,
@@ -544,8 +537,7 @@
 {
 	struct token *token;
 	static char buffer[4095];
-	char *p = buffer, *buf, *buffer_end = buffer + sizeof (buffer);
-	int len;
+	char *p = buffer, *buffer_end = buffer + sizeof (buffer);
 
 	*p++ = c;
 	for (;;) {
@@ -573,13 +565,9 @@
 	}
 
 	*p++ = 0;
-	len = p - buffer;
-	buf = __alloc_bytes(len);
-	memcpy(buf, buffer, len);
-
 	token = stream->token;
 	token_type(token) = TOKEN_NUMBER;
-	token->number = buf;
+	token->number = xmemdup(buffer, p - buffer);
 	add_token(stream);
 
 	return next;
@@ -601,9 +589,9 @@
 		len++;
 		if (next == '\n') {
 			warning(stream_pos(stream),
-				"Newline in string or character constant");
-			if (delim == '\'') /* assume it's lost ' */
-				break;
+				"missing terminating %c character", delim);
+			/* assume delimiter is lost */
+			break;
 		}
 		if (next == EOF) {
 			warning(stream_pos(stream),
--- old/usr/src/tools/smatch/src/unssa.c	Mon Nov 18 13:19:41 2019
+++ new/usr/src/tools/smatch/src/unssa.c	Mon Nov 18 13:19:41 2019
@@ -34,11 +34,6 @@
 #include <assert.h>
 
 
-static inline int nbr_pseudo_users(pseudo_t p)
-{
-	return ptr_list_size((struct ptr_list *)p->users);
-}
-
 static int simplify_phi_node(struct instruction *phi, pseudo_t tmp)
 {
 	pseudo_t target = phi->target;
@@ -95,7 +90,7 @@
 		src = def->phi_src;
 		if (src->type != PSEUDO_REG)
 			continue;
-		switch (nbr_pseudo_users(src)) {
+		switch (nbr_users(src)) {
 			struct instruction *insn;
 		case 1:
 			insn = src->def;
--- /dev/null	Mon Nov 18 13:19:41 2019
+++ new/usr/src/tools/smatch/src/utils.c	Mon Nov 18 13:19:41 2019
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT
+// Copyright (C) 2018 Luc Van Oostenryck
+
+#include "utils.h"
+#include "allocate.h"
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+
+void *xmemdup(const void *src, size_t len)
+{
+	return memcpy(__alloc_bytes(len), src, len);
+}
+
+char *xstrdup(const char *src)
+{
+	return xmemdup(src, strlen(src) + 1);
+}
+
+char *xvasprintf(const char *fmt, va_list ap)
+{
+	va_list ap2;
+	char *str;
+	int n;
+
+	va_copy(ap2, ap);
+	n = vsnprintf(NULL, 0, fmt, ap2) + 1;
+	va_end(ap2);
+
+	str = __alloc_bytes(n);
+	vsnprintf(str, n, fmt, ap);
+
+	return str;
+}
+
+char *xasprintf(const char *fmt, ...)
+{
+	va_list ap;
+	char *str;
+
+	va_start(ap, fmt);
+	str = xvasprintf(fmt, ap);
+	va_end(ap);
+
+	return str;
+}
--- /dev/null	Mon Nov 18 13:19:41 2019
+++ new/usr/src/tools/smatch/src/utils.h	Mon Nov 18 13:19:41 2019
@@ -0,0 +1,43 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+///
+// Miscellaneous utilities
+// -----------------------
+
+#include <stddef.h>
+#include <stdarg.h>
+
+///
+// duplicate a memory buffer in a newly allocated buffer.
+// @src: a pointer to the memory buffer to be duplicated
+// @len: the size of the memory buffer to be duplicated
+// @return: a pointer to a copy of @src allocated via
+//	:func:`__alloc_bytes()`.
+void *xmemdup(const void *src, size_t len);
+
+///
+// duplicate a null-terminated string in a newly allocated buffer.
+// @src: a pointer to string to be duplicated
+// @return: a pointer to a copy of @str allocated via
+//	:func:`__alloc_bytes()`.
+char *xstrdup(const char *src);
+
+///
+// printf to allocated string
+// @fmt: the format followed by its arguments.
+// @return: the allocated & formatted string.
+// This function is similar to asprintf() but the resulting string
+// is allocated with __alloc_bytes().
+char *xasprintf(const char *fmt, ...);
+
+///
+// vprintf to allocated string
+// @fmt: the format
+// @ap: the variadic arguments
+// @return: the allocated & formatted string.
+// This function is similar to asprintf() but the resulting string
+// is allocated with __alloc_bytes().
+char *xvasprintf(const char *fmt, va_list ap);
+
+#endif
--- /dev/null	Mon Nov 18 13:19:41 2019
+++ new/usr/src/tools/smatch/src/validation/Waddress-array.c	Mon Nov 18 13:19:41 2019
@@ -0,0 +1,25 @@
+int foo(void) {
+	extern int a[];
+
+	if (a)
+		return 1;
+	return 0;
+}
+
+int bar(void) {
+	int a[2];
+
+	if (a)
+		return 1;
+	return 0;
+}
+
+/*
+ * check-name: Waddress-array
+ * check-command: sparse -Wno-decl -Waddress $file
+ *
+ * check-error-start
+Waddress-array.c:4:13: warning: the address of an array will always evaluate as true
+Waddress-array.c:12:13: warning: the address of an array will always evaluate as true
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:42 2019
+++ new/usr/src/tools/smatch/src/validation/Waddress-function.c	Mon Nov 18 13:19:42 2019
@@ -0,0 +1,17 @@
+extern void func(void);
+
+int global_function(void)
+{
+	if (func)
+		return 1;
+	return 0;
+}
+
+/*
+ * check-name: Waddress-function
+ * check-command: sparse -Wno-decl -Waddress $file
+ *
+ * check-error-start
+Waddress-function.c:5:13: warning: the address of a function will always evaluate as true
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:42 2019
+++ new/usr/src/tools/smatch/src/validation/Waddress-space-all-attr.c	Mon Nov 18 13:19:42 2019
@@ -0,0 +1,64 @@
+/* Resembles include/linux/compiler_types.h */
+#define __kernel __attribute__((address_space(0)))
+#define __user __attribute__((address_space(1)))
+#define __iomem __attribute__((address_space(2)))
+#define __percpu __attribute__((address_space(3)))
+#define __rcu __attribute__((address_space(4)))
+
+
+typedef unsigned long ulong;
+typedef struct s obj_t;
+
+static void expl(obj_t __kernel *k, obj_t __iomem *o,
+		 obj_t __user *p, obj_t __percpu *pc,
+		 obj_t __rcu *r)
+{
+	(ulong)(k); (__UINTPTR_TYPE__)(k);
+	(void *)(k);
+	(obj_t*)(k);
+	(obj_t __kernel*)(k);
+
+	(ulong)(o); (__UINTPTR_TYPE__)(o);
+	(void *)(o);
+	(obj_t*)(o);
+	(obj_t __iomem*)(o);
+
+	(ulong)(p); (__UINTPTR_TYPE__)(p);
+	(void *)(p);
+	(obj_t*)(p);
+	(obj_t __user*)(p);
+
+	(ulong)(pc); (__UINTPTR_TYPE__)(pc);
+	(void *)(pc);
+	(obj_t*)(pc);
+	(obj_t __percpu*)(pc);
+
+	(ulong)(r); (__UINTPTR_TYPE__)(r);
+	(void *)(r);
+	(obj_t*)(r);
+	(obj_t __rcu*)(r);
+}
+
+/*
+ * check-name: Waddress-space-all-attr
+ * check-command: sparse -Wcast-from-as -Wcast-to-as $file
+ *
+ * check-error-start
+Waddress-space-all-attr.c:21:10: warning: cast removes address space '<asn:2>' of expression
+Waddress-space-all-attr.c:21:22: warning: cast removes address space '<asn:2>' of expression
+Waddress-space-all-attr.c:22:10: warning: cast removes address space '<asn:2>' of expression
+Waddress-space-all-attr.c:23:10: warning: cast removes address space '<asn:2>' of expression
+Waddress-space-all-attr.c:26:10: warning: cast removes address space '<asn:1>' of expression
+Waddress-space-all-attr.c:26:22: warning: cast removes address space '<asn:1>' of expression
+Waddress-space-all-attr.c:27:10: warning: cast removes address space '<asn:1>' of expression
+Waddress-space-all-attr.c:28:10: warning: cast removes address space '<asn:1>' of expression
+Waddress-space-all-attr.c:31:10: warning: cast removes address space '<asn:3>' of expression
+Waddress-space-all-attr.c:31:23: warning: cast removes address space '<asn:3>' of expression
+Waddress-space-all-attr.c:32:10: warning: cast removes address space '<asn:3>' of expression
+Waddress-space-all-attr.c:33:10: warning: cast removes address space '<asn:3>' of expression
+Waddress-space-all-attr.c:36:10: warning: cast removes address space '<asn:4>' of expression
+Waddress-space-all-attr.c:36:22: warning: cast removes address space '<asn:4>' of expression
+Waddress-space-all-attr.c:37:10: warning: cast removes address space '<asn:4>' of expression
+Waddress-space-all-attr.c:38:10: warning: cast removes address space '<asn:4>' of expression
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:42 2019
+++ new/usr/src/tools/smatch/src/validation/Waddress-space-from.c	Mon Nov 18 13:19:42 2019
@@ -0,0 +1,63 @@
+
+#define __kernel __attribute__((address_space(0)))
+#define __user   __attribute__((address_space(__user)))
+#define __iomem  __attribute__((address_space(__iomem)))
+#define __percpu __attribute__((address_space(__percpu)))
+#define __rcu    __attribute__((address_space(__rcu)))
+
+
+typedef struct s obj_t;
+
+static void expl(obj_t __kernel *k, obj_t __iomem *o,
+		 obj_t __user *p, obj_t __percpu *pc,
+		 obj_t __rcu *r)
+{
+	(__UINTPTR_TYPE__)(k);	// OK
+	(unsigned long)(k);	// OK
+	(void *)(k);		// OK
+	(obj_t*)(k);		// OK
+	(obj_t __kernel*)(k);	// OK
+
+	(__UINTPTR_TYPE__)(o);	// OK
+	(unsigned long)(o);	// OK
+	(void *)(o);
+	(obj_t*)(o);
+	(obj_t __iomem*)(o);	// OK
+
+	(__UINTPTR_TYPE__)(p);	// OK
+	(unsigned long)(p);	// OK
+	(void *)(p);
+	(obj_t*)(p);
+	(obj_t __user*)(p);	// OK
+
+	(__UINTPTR_TYPE__)(pc);	// OK
+	(unsigned long)(pc);	// OK
+	(void *)(pc);
+	(obj_t*)(pc);
+	(obj_t __percpu*)(pc);	// OK
+
+	(__UINTPTR_TYPE__)(r);	// OK
+	(unsigned long)(r);	// OK
+	(void *)(r);
+	(obj_t*)(r);
+	(obj_t __rcu*)(r);	// OK
+}
+
+/*
+ * check-name: Waddress-space-from
+ * check-command: sparse -Wno-cast-from-as $file
+ * check-description: Test the removal of AS from a pointer but only
+ *	in the non-strict variant where casts to ulong (or uintptr_t)
+ *	are allowed.
+ *
+ * check-error-start
+Waddress-space-from.c:23:10: warning: cast removes address space '__iomem' of expression
+Waddress-space-from.c:24:10: warning: cast removes address space '__iomem' of expression
+Waddress-space-from.c:29:10: warning: cast removes address space '__user' of expression
+Waddress-space-from.c:30:10: warning: cast removes address space '__user' of expression
+Waddress-space-from.c:35:10: warning: cast removes address space '__percpu' of expression
+Waddress-space-from.c:36:10: warning: cast removes address space '__percpu' of expression
+Waddress-space-from.c:41:10: warning: cast removes address space '__rcu' of expression
+Waddress-space-from.c:42:10: warning: cast removes address space '__rcu' of expression
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:42 2019
+++ new/usr/src/tools/smatch/src/validation/Waddress-space-strict.c	Mon Nov 18 13:19:42 2019
@@ -0,0 +1,36 @@
+#define __user __attribute__((address_space(1)))
+
+typedef unsigned long ulong;
+typedef struct s obj_t;
+
+static void expl(ulong u, void *v, obj_t *o, obj_t __user *p)
+{
+	(obj_t*)(u);
+	(obj_t __user*)(u);
+
+	(obj_t*)(v);
+	(obj_t __user*)(v);
+
+	(ulong)(o);
+	(void *)(o);
+	(obj_t*)(o);
+	(obj_t __user*)(o);
+
+	(ulong)(p);		// w!
+	(void *)(p);		// w
+	(obj_t*)(p);		// w
+	(obj_t __user*)(p);	// ok
+}
+
+/*
+ * check-name: Waddress-space-strict
+ * check-command: sparse -Wcast-from-as -Wcast-to-as $file
+ *
+ * check-error-start
+Waddress-space-strict.c:12:10: warning: cast adds address space '<asn:1>' to expression
+Waddress-space-strict.c:17:10: warning: cast adds address space '<asn:1>' to expression
+Waddress-space-strict.c:19:10: warning: cast removes address space '<asn:1>' of expression
+Waddress-space-strict.c:20:10: warning: cast removes address space '<asn:1>' of expression
+Waddress-space-strict.c:21:10: warning: cast removes address space '<asn:1>' of expression
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:42 2019
+++ new/usr/src/tools/smatch/src/validation/Waddress-weak.c	Mon Nov 18 13:19:42 2019
@@ -0,0 +1,27 @@
+extern int var       __attribute__((weak));
+extern int arr[]     __attribute__((weak));
+extern int fun(void) __attribute__((weak));
+
+int test_addr_weak_fun(void)
+{
+	if ( &var) return 1;
+	if (  arr) return 1;
+	if ( &arr) return 1;
+	if (  fun) return 1;
+	if ( &fun) return 1;
+	if ( *fun) return 1;
+	if (!&var) return 0;
+	if (! arr) return 0;
+	if (!&arr) return 0;
+	if (! fun) return 0;
+	if (!&fun) return 0;
+	if (!*fun) return 0;
+	return -1;
+}
+
+/*
+ * check-name: Waddress-weak
+ * check-note: Undefined weak symbols (can) have a null address.
+ * check-command: sparse -Wno-decl -Waddress $file
+ * check-known-to-fail
+ */
--- /dev/null	Mon Nov 18 13:19:42 2019
+++ new/usr/src/tools/smatch/src/validation/Waddress.c	Mon Nov 18 13:19:43 2019
@@ -0,0 +1,114 @@
+extern int fun(void);
+extern int arr[];
+extern int var;
+
+int test_address(int arg, int ptr[])
+{
+
+	if (fun())	return -1;
+	if (var)	return -1;
+	if (arg)	return -1;
+	if (ptr)	return -1;
+
+lab:
+	if (arr)	return 1;
+	if (&arr)	return 1;
+	if (fun)	return 1;
+	if (&fun)	return 1;
+	if (*fun)	return 1;
+	if (&var)	return 1;
+	if (&arg)	return 1;
+	if (&&lab)	return 1;
+
+	return -1;
+}
+
+int test_address_not(int arg, int ptr[])
+{
+
+	if (!fun())	return -1;
+	if (!var)	return -1;
+	if (!arg)	return -1;
+	if (!ptr)	return -1;
+
+lab:
+	if (!arr)	return 0;
+	if (!&arr)	return 0;
+	if (!fun)	return 0;
+	if (!&fun)	return 0;
+	if (!*fun)	return 0;
+	if (!&var)	return 0;
+	if (!&arg)	return 0;
+	if (!&&lab)	return 0;
+
+	return -1;
+}
+
+int test_address_cmp(int arg, int ptr[])
+{
+	if (fun() == 0)	return -1;
+	if (0 == fun())	return -1;
+	if (var == 0)	return -1;
+	if (0 == var)	return -1;
+	if (arg == 0)	return -1;
+	if (0 == arg)	return -1;
+	if (ptr == 0)	return -1;
+	if (0 == ptr)	return -1;
+
+lab:
+	if (arr == 0)	return 0;
+	if (0 == arr)	return 0;
+	if (&arr == 0)	return 0;
+	if (0 == &arr)	return 0;
+	if (fun == 0)	return 0;
+	if (0 == fun)	return 0;
+	if (&fun == 0)	return 0;
+	if (0 == &fun)	return 0;
+	if (*fun == 0)	return 0;
+	if (0 == *fun)	return 0;
+	if (&var == 0)	return 0;
+	if (0 == &var)	return 0;
+	if (&arg == 0)	return 0;
+	if (0 == &arg)	return 0;
+	if (&&lab == 0)	return 0;
+	if (0 == &&lab)	return 0;
+
+	return -1;
+}
+
+/*
+ * check-name: Waddress
+ * check-command: sparse -Wno-decl -Wno-non-pointer-null -Waddress $file
+ * check-known-to-fail
+ *
+ * check-error-start
+Waddress.c:14:13: warning: the address of an array will always evaluate as true
+Waddress.c:15:14: warning: the address of an array will always evaluate as true
+Waddress.c:16:13: warning: the address of a function will always evaluate as true
+Waddress.c:17:14: warning: the address of a function will always evaluate as true
+Waddress.c:18:13: warning: the address of a variable will always evaluate as true
+Waddress.c:19:13: warning: the address of a variable will always evaluate as true
+Waddress.c:20:13: warning: the address of a label will always evaluate as true
+Waddress.c:34:13: warning: the address of an array will always evaluate as true
+Waddress.c:35:13: warning: the address of an array will always evaluate as true
+Waddress.c:36:13: warning: the address of a function will always evaluate as true
+Waddress.c:37:13: warning: the address of a function will always evaluate as true
+Waddress.c:38:13: warning: the address of a variable will always evaluate as true
+Waddress.c:39:13: warning: the address of a variable will always evaluate as true
+Waddress.c:40:13: warning: the address of a label will always evaluate as true
+Waddress.c:57:13: warning: the address of an array will always evaluate as true
+Waddress.c:58:13: warning: the address of an array will always evaluate as true
+Waddress.c:59:13: warning: the address of an array will always evaluate as true
+Waddress.c:60:13: warning: the address of an array will always evaluate as true
+Waddress.c:61:13: warning: the address of a function will always evaluate as true
+Waddress.c:62:13: warning: the address of a function will always evaluate as true
+Waddress.c:63:13: warning: the address of a function will always evaluate as true
+Waddress.c:64:13: warning: the address of a function will always evaluate as true
+Waddress.c:65:13: warning: the address of a variable will always evaluate as true
+Waddress.c:66:13: warning: the address of a variable will always evaluate as true
+Waddress.c:67:13: warning: the address of a variable will always evaluate as true
+Waddress.c:68:13: warning: the address of a variable will always evaluate as true
+Waddress.c:69:13: warning: the address of a label will always evaluate as true
+Waddress.c:70:13: warning: the address of a label will always evaluate as true
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:43 2019
+++ new/usr/src/tools/smatch/src/validation/Wcast-to-as.c	Mon Nov 18 13:19:43 2019
@@ -0,0 +1,36 @@
+#define __user __attribute__((address_space(1)))
+
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef unsigned long ulong;
+typedef struct s obj_t;
+
+static void expl(ulong u, uintptr_t uip, void *v, obj_t *o, obj_t __user *p)
+{
+	(obj_t*)(u);
+	(obj_t __user*)(u);
+
+	(obj_t*)(uip);
+	(obj_t __user*)(uip);
+
+	(obj_t*)(v);
+	(obj_t __user*)(v);
+
+	(ulong)(o);
+	(void *)(o);
+	(obj_t*)(o);
+	(obj_t __user*)(o);
+
+	(ulong)(p);
+	(obj_t __user*)(p);
+
+}
+
+/*
+ * check-name: cast-to-as
+ * check-command: sparse -Wcast-to-as $file
+ *
+ * check-error-start
+Wcast-to-as.c:16:10: warning: cast adds address space '<asn:1>' to expression
+Wcast-to-as.c:21:10: warning: cast adds address space '<asn:1>' to expression
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:43 2019
+++ new/usr/src/tools/smatch/src/validation/Wexternal-function-has-definition.c	Mon Nov 18 13:19:43 2019
@@ -0,0 +1,12 @@
+
+extern int myfunction(void);
+
+extern int myfunction(void) { return 0; }
+
+/*
+ * check-name: external-function-has-definition
+ * check-command: sparse -Wno-external-function-has-definition $file
+ *
+ * check-error-start
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/Wunknown-attribute-def.c	Mon Nov 18 13:19:43 2019
+++ new/usr/src/tools/smatch/src/validation/Wunknown-attribute-def.c	Mon Nov 18 13:19:43 2019
@@ -2,8 +2,4 @@
 
 /*
  * check-name: warn-unknown-attribute
- *
- * check-error-start
-Wunknown-attribute-def.c:1:37: warning: attribute 'unknown_attribute': unknown attribute
- * check-error-end
  */
--- old/usr/src/tools/smatch/src/validation/Wunknown-attribute-yes.c	Mon Nov 18 13:19:44 2019
+++ new/usr/src/tools/smatch/src/validation/Wunknown-attribute-yes.c	Mon Nov 18 13:19:44 2019
@@ -5,6 +5,6 @@
  * check-command: sparse -Wunknown-attribute $file
  *
  * check-error-start
-Wunknown-attribute-yes.c:1:37: warning: attribute 'unknown_attribute': unknown attribute
+Wunknown-attribute-yes.c:1:37: warning: unknown attribute 'unknown_attribute'
  * check-error-end
  */
--- /dev/null	Mon Nov 18 13:19:44 2019
+++ new/usr/src/tools/smatch/src/validation/abi-integer.c	Mon Nov 18 13:19:44 2019
@@ -0,0 +1,31 @@
+#define TEST(T, S, A)	\
+	_Static_assert(sizeof(T) == S && _Alignof(T) == A, #T)
+
+int main(void)
+{
+	TEST(int,    4, 4);
+
+#if defined(__LP64__)
+	TEST(long,      8, 8);
+	TEST(void *,    8, 8);
+	TEST(long long, 8, 8);
+#elif defined(__LLP64__)
+	TEST(long,      4, 4);
+	TEST(void *,    8, 8);
+	TEST(long long, 8, 8);
+#elif defined(__x86_64__)
+	TEST(long,      4, 4);
+	TEST(void *,    4, 4);
+	TEST(long long, 8, 8);
+#else
+	TEST(long,      4, 4);
+	TEST(void *,    4, 4);
+	TEST(long long, 8, 4);
+#endif
+
+	return 0;
+}
+
+/*
+ * check-name: abi-integer
+ */
--- old/usr/src/tools/smatch/src/validation/address_space.c	Mon Nov 18 13:19:44 2019
+++ new/usr/src/tools/smatch/src/validation/address_space.c	Mon Nov 18 13:19:44 2019
@@ -12,6 +12,6 @@
  * check-error-start
 address_space.c:7:28: warning: incorrect type in argument 1 (different address spaces)
 address_space.c:7:28:    expected void *addr
-address_space.c:7:28:    got void <asn:1>*user_addr
+address_space.c:7:28:    got void <asn:1> *user_addr
  * check-error-end
  */
--- /dev/null	Mon Nov 18 13:19:45 2019
+++ new/usr/src/tools/smatch/src/validation/array-implicit-size.c	Mon Nov 18 13:19:45 2019
@@ -0,0 +1,26 @@
+static int array[] = { 0, 1, 2, 3, };
+_Static_assert(sizeof(array) == 4 * sizeof(int), "size of array");
+
+
+typedef int table_t[];
+static table_t tbl2 = {
+	0,
+	1,
+};
+_Static_assert(sizeof(tbl2) == 2 * sizeof(int), "size of tbl2");
+
+static table_t tbl1 = {
+	0,
+};
+_Static_assert(sizeof(tbl1) == 1 * sizeof(int), "size of tbl1");
+
+static table_t tbl3 = {
+	0,
+	1,
+	2,
+};
+_Static_assert(sizeof(tbl3) == 3 * sizeof(int), "size of tbl3");
+
+/*
+ * check-name: array-implicit-size
+ */
--- /dev/null	Mon Nov 18 13:19:45 2019
+++ new/usr/src/tools/smatch/src/validation/as-name.c	Mon Nov 18 13:19:45 2019
@@ -0,0 +1,17 @@
+#define __user __attribute__((address_space(__user)))
+
+extern void fun(void *addr);
+
+static void foo(void __user *ptr)
+{
+	return fun(ptr);
+}
+/*
+ * check-name: as-name attribute
+ *
+ * check-error-start
+as-name.c:7:20: warning: incorrect type in argument 1 (different address spaces)
+as-name.c:7:20:    expected void *addr
+as-name.c:7:20:    got void __user *ptr
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:45 2019
+++ new/usr/src/tools/smatch/src/validation/asm-inline.c	Mon Nov 18 13:19:45 2019
@@ -0,0 +1,52 @@
+static void foo(void)
+{
+	asm("");
+	asm volatile ("v");
+	asm inline ("i");
+	asm volatile inline ("vi");
+	asm inline volatile ("iv");
+
+	asm goto ("g" :::: label);
+	asm volatile goto ("vg" :::: label);
+	asm inline goto ("ig" :::: label);
+	asm volatile inline goto ("vig" :::: label);
+	asm inline volatile goto ("ivg" :::: label);
+
+	asm goto volatile ("gv" :::: label);
+	asm goto inline ("gi" :::: label);
+	asm goto volatile inline ("gvi" :::: label);
+	asm goto inline volatile ("giv" :::: label);
+	asm volatile goto inline ("vgi" :::: label);
+	asm inline goto volatile ("giv" :::: label);
+
+	// warn on duplicates
+	asm volatile volatile ("vv");
+	asm inline inline ("ii");
+	asm goto goto ("gg" :::: label);
+
+	asm inline volatile inline ("ivi");
+	asm inline goto inline ("igi" :::: label);
+	asm goto inline goto ("gig" :::: label);
+	asm goto volatile goto ("gvg" :::: label);
+	asm volatile inline volatile ("viv");
+	asm volatile goto volatile ("vgv" :::: label);
+
+label:
+	;
+}
+
+/*
+ * check-name: asm-inline
+ *
+ * check-error-start
+asm-inline.c:23:22: warning: duplicated asm modifier
+asm-inline.c:24:20: warning: duplicated asm modifier
+asm-inline.c:25:18: warning: duplicated asm modifier
+asm-inline.c:27:29: warning: duplicated asm modifier
+asm-inline.c:28:25: warning: duplicated asm modifier
+asm-inline.c:29:25: warning: duplicated asm modifier
+asm-inline.c:30:27: warning: duplicated asm modifier
+asm-inline.c:31:29: warning: duplicated asm modifier
+asm-inline.c:32:27: warning: duplicated asm modifier
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:45 2019
+++ new/usr/src/tools/smatch/src/validation/attr-context.c	Mon Nov 18 13:19:45 2019
@@ -0,0 +1,40 @@
+static void a(void) __attribute__((context));		// KO
+static void b(void) __attribute__((context()));		// KO
+static void c(void) __attribute__((context 1));		// KO
+static void d(void) __attribute__((context 1,2));	// KO
+static void e(void) __attribute__((context (1)));	// !!!!
+static void f(void) __attribute__((context(0)));	// !!!!
+static void g(void) __attribute__((context(0,1,2,3)));	// KO
+
+static void h(void) __attribute__((context (1,2)));	// OK
+static void i(void) __attribute__((context(0,1)));	// OK
+static void j(void) __attribute__((context(0,1,2)));	// OK
+
+extern int u, v;
+static void x(void) __attribute__((context(0,1,v)));
+static void y(void) __attribute__((context(0,u,1)));
+static void z(void) __attribute__((context(0,u)));
+
+/*
+ * check-name: attr-context
+ *
+ * check-error-start
+attr-context.c:1:43: error: Expected ( after context attribute
+attr-context.c:1:43: error: got )
+attr-context.c:2:44: error: Expected , after context 1st argument
+attr-context.c:2:44: error: got )
+attr-context.c:3:44: error: Expected ( after context attribute
+attr-context.c:3:44: error: got 1
+attr-context.c:4:44: error: Expected ( after context attribute
+attr-context.c:4:44: error: got 1
+attr-context.c:5:46: error: Expected , after context 1st argument
+attr-context.c:5:46: error: got )
+attr-context.c:6:45: error: Expected , after context 1st argument
+attr-context.c:6:45: error: got )
+attr-context.c:7:49: error: Expected ) after context 3rd argument
+attr-context.c:7:49: error: got ,
+attr-context.c:14:48: error: bad constant expression
+attr-context.c:15:46: error: bad constant expression
+attr-context.c:16:46: error: bad constant expression
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/backend/arithmetic-ops.c	Mon Nov 18 13:19:45 2019
+++ new/usr/src/tools/smatch/src/validation/backend/arithmetic-ops.c	Mon Nov 18 13:19:45 2019
@@ -88,6 +88,26 @@
 	return x % y;
 }
 
+static int neg(int x)
+{
+	return -x;
+}
+
+static unsigned int uneg(unsigned int x)
+{
+	return -x;
+}
+
+static float fneg(float x)
+{
+	return -x;
+}
+
+static double dneg(double x)
+{
+	return -x;
+}
+
 /*
  * check-name: Arithmetic operator code generation
  * check-command: sparsec -c $file -o tmp.o
--- /dev/null	Mon Nov 18 13:19:46 2019
+++ new/usr/src/tools/smatch/src/validation/backend/call-variadic.c	Mon Nov 18 13:19:46 2019
@@ -0,0 +1,27 @@
+#define NULL	((void*)0)
+
+extern int print(const char *msg, ...);
+
+int foo(const char *fmt, int a, long l, int *p);
+int foo(const char *fmt, int a, long l, int *p)
+{
+	return print(fmt, 'x', a, __LINE__, l, 0L, p, NULL);
+}
+
+/*
+ * check-name: call-variadic
+ * check-command: sparse-llvm-dis -m64 $file
+ *
+ * check-output-start
+; ModuleID = '<stdin>'
+source_filename = "sparse"
+
+define i32 @foo(i8* %ARG1., i32 %ARG2., i64 %ARG3., i32* %ARG4.) {
+L0:
+  %R5. = call i32 (i8*, ...) @print(i8* %ARG1., i32 120, i32 %ARG2., i32 8, i64 %ARG3., i64 0, i32* %ARG4., i8* null)
+  ret i32 %R5.
+}
+
+declare i32 @print(i8*, ...)
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/backend/cast.c	Mon Nov 18 13:19:46 2019
+++ new/usr/src/tools/smatch/src/validation/backend/cast.c	Mon Nov 18 13:19:46 2019
@@ -1,4 +1,5 @@
 typedef _Bool bool;
+typedef   signed char schar;
 typedef unsigned char uchar;
 typedef unsigned short ushort;
 typedef unsigned int uint;
@@ -14,6 +15,7 @@
 #define DEFINE_CASTS(from)			\
 	DEFINE_CAST(from, bool)			\
 	DEFINE_CAST(from, char)			\
+	DEFINE_CAST(from, schar)		\
 	DEFINE_CAST(from, uchar)		\
 	DEFINE_CAST(from, short)		\
 	DEFINE_CAST(from, ushort)		\
@@ -23,13 +25,12 @@
 	DEFINE_CAST(from, ulong)		\
 	DEFINE_CAST(from, longlong)		\
 	DEFINE_CAST(from, ulonglong)		\
-/*
 	DEFINE_CAST(from, float)		\
 	DEFINE_CAST(from, double)
-*/
 
 DEFINE_CASTS(bool)
 DEFINE_CASTS(char)
+DEFINE_CASTS(schar)
 DEFINE_CASTS(uchar)
 DEFINE_CASTS(short)
 DEFINE_CASTS(ushort)
@@ -39,10 +40,8 @@
 DEFINE_CASTS(ulong)
 DEFINE_CASTS(longlong)
 DEFINE_CASTS(ulonglong)
-/*
 DEFINE_CASTS(float)
 DEFINE_CASTS(double)
-*/
 
 /*
  * check-name: Cast code generation
--- /dev/null	Mon Nov 18 13:19:46 2019
+++ new/usr/src/tools/smatch/src/validation/backend/compare-with-null.c	Mon Nov 18 13:19:46 2019
@@ -0,0 +1,12 @@
+int  tstv(void *p) { return !p; }
+int  cmpv(void *p) { return p == ((void*)0); }
+
+int  tsti(int  *p) { return !p; }
+int  cmpi(int  *p) { return p == ((int *)0); }
+int  cmpx(int  *p) { return p == ((void*)0); }
+
+/*
+ * check-name: compare-with-null
+ * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ * check-output-ignore
+ */
--- /dev/null	Mon Nov 18 13:19:47 2019
+++ new/usr/src/tools/smatch/src/validation/backend/constant-pointer.c	Mon Nov 18 13:19:47 2019
@@ -0,0 +1,24 @@
+extern int *ip[];
+
+void foo(void);
+void foo(void)
+{
+	ip[0] = (void *)0L;
+	ip[1] = (int *)0L;
+	ip[2] = (void *)0;
+	ip[3] = (int *)0;
+	ip[4] = (void *)(long)0;
+	ip[5] = (int *)(long)0;
+	ip[6] = (void *)123;
+	ip[7] = (int *)123;
+	ip[8] = (void *)123L;
+	ip[9] = (int *)123L;
+	ip[10] = (void *)(long)123;
+	ip[11] = (int *)(long)123;
+}
+
+/*
+ * check-name: constant pointers
+ * check-command: sparse-llvm $file
+ * check-output-ignore
+ */
--- /dev/null	Mon Nov 18 13:19:47 2019
+++ new/usr/src/tools/smatch/src/validation/backend/degenerate-ptr.c	Mon Nov 18 13:19:47 2019
@@ -0,0 +1,72 @@
+extern int array[3];
+extern int matrix[3][3];
+extern int fun(int);
+
+extern int fia(int []);
+extern int fip(int *);
+extern int fim(int (*)[3]);
+extern int fvp(void *);
+extern int ffp(int (*)(int));
+
+void call(void);
+void call(void)
+{
+	fia(array);
+
+	fip(array);
+	fim(matrix);
+
+	fvp(array);
+	fvp(matrix);
+
+	fvp(fun);
+	fvp(&fun);
+	ffp(fun);
+	ffp(&fun);
+}
+
+void local(void);
+void local(void)
+{
+	int *ip;
+	int (*im)[3];
+	void *vp;
+	int (*fp)(int);
+
+	ip = array;
+	im = matrix;
+
+	vp = array;
+	vp = matrix;
+
+	vp = fun;
+	vp = &fun;
+	fp = fun;
+	fp = &fun;
+}
+
+
+extern int *ip;
+extern int (*im)[3];
+extern void *vp;
+extern int (*fp)(int);
+
+void global(void);
+void global(void)
+{
+	ip = array;
+	im = matrix;
+
+	vp = array;
+	vp = matrix;
+
+	vp = fun;
+	vp = &fun;
+	fp = fun;
+	fp = &fun;
+}
+
+/*
+ * check-name: degenerated pointer handling
+ * check-command: sparsec -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:47 2019
+++ new/usr/src/tools/smatch/src/validation/backend/fn-ref.c	Mon Nov 18 13:19:47 2019
@@ -0,0 +1,32 @@
+extern int fun0(int a);
+extern int fun1(int a);
+
+int foo(int a);
+int foo(int a)
+{
+	int v = fun0(a);
+	return v;
+}
+
+void *bar(int a)
+{
+	return fun1;
+}
+
+int fun0(int a)
+{
+	return a + 0;
+}
+
+int fun1(int a)
+{
+	return a + 1;
+}
+
+/*
+ * check-name: llvm function reference
+ * check-command: sparse-llvm-dis -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: fun[0-9]\.[1-9]
+ */
--- /dev/null	Mon Nov 18 13:19:47 2019
+++ new/usr/src/tools/smatch/src/validation/backend/function-ptr-xtype.c	Mon Nov 18 13:19:47 2019
@@ -0,0 +1,37 @@
+typedef int  (*binop_t)(int, int);
+typedef int  (*unop_t)(int);
+typedef int  (*idef_t)(void);
+typedef long (*ldef_t)(void);
+typedef void (*use_t)(int);
+
+// We want to 'fn' have several different types.
+// The goal is for the ->priv member to be used
+// with a type different from what it was first stored.
+
+int foo(void *fn, int arg1, int arg2);
+int foo(void *fn, int arg1, int arg2)
+{
+	int res = 0;
+
+	res += ((binop_t)fn)(arg1, arg2);
+	res += ((unop_t)fn)(arg1);
+	res += ((ldef_t)fn)();
+	res += ((idef_t)fn)();
+	((use_t)fn)(res);
+	return res;
+}
+
+int bar(int (*fn)(int), int arg1, int arg2);
+int bar(int (*fn)(int), int arg1, int arg2)
+{
+	int res = 0;
+
+	res += ((binop_t)fn)(arg1, arg2);
+	res += fn(arg1);
+	return res;
+}
+
+/*
+ * check-name: mutate function pointer's type
+ * check-command: sparsec -c $file -o tmp.o
+ */
--- old/usr/src/tools/smatch/src/validation/backend/function-ptr.c	Mon Nov 18 13:19:47 2019
+++ new/usr/src/tools/smatch/src/validation/backend/function-ptr.c	Mon Nov 18 13:19:47 2019
@@ -1,10 +1,152 @@
-typedef int (*fn_t)(int x, int y);
+extern int ival;
+extern int *ipval;
+extern int array[3];
+extern int matrix[3][3];
+extern int fun(int);
 
-static int run(fn_t fn, int x, int y)
+// via an argument
+void arg(int a, int *p, int (*fb)(unsigned char), int (*fi)(int), int (*fl)(long), int (*fv)(void), int (*fip)(int *), int (*fim)(int (*)[3]), int (*fvp)(void *), int (*ffp)(int (*)(int)));
+void arg(int a, int *p, int (*fb)(unsigned char), int (*fi)(int), int (*fl)(long), int (*fv)(void), int (*fip)(int *), int (*fim)(int (*)[3]), int (*fvp)(void *), int (*ffp)(int (*)(int)))
 {
-	return fn(x, y);
+	fv();
+
+	fb(a);
+	fi(a);
+	fl(a);
+	fb(123);
+	fi(123);
+	fl(123);
+	fb(123L);
+	fi(123L);
+	fl(123L);
+	fb(ival);
+	fi(ival);
+	fl(ival);
+
+	fip(p);
+	fip((void*)0);
+	fip(ipval);
+	fip(&ival);
+	fip(array);
+	fim(matrix);
+
+	fvp(p);
+	fvp((void*)0);
+	fvp(ipval);
+	fvp(&ival);
+	fvp(array);
+	fvp(matrix);
+
+	fvp(fun);
+	fvp(&fun);
+	ffp(fun);
+	ffp(&fun);
 }
 
+// a global
+extern int (*fb)(unsigned char);
+extern int (*fi)(int);
+extern int (*fl)(long);
+extern int (*fv)(void);
+extern int (*fip)(int *);
+extern int (*fim)(int (*)[3]);
+extern int (*fvp)(void *);
+extern int (*ffp)(int (*)(int));
+
+void glb(int a, int *p);
+void glb(int a, int *p)
+{
+	fv();
+
+	fb(a);
+	fi(a);
+	fl(a);
+	fb(123);
+	fi(123);
+	fl(123);
+	fb(123L);
+	fi(123L);
+	fl(123L);
+	fb(ival);
+	fi(ival);
+	fl(ival);
+
+	fip(p);
+	fip((void*)0);
+	fip(ipval);
+	fip(&ival);
+	fip(array);
+	fim(matrix);
+
+	fvp(p);
+	fvp((void*)0);
+	fvp(ipval);
+	fvp(&ival);
+	fvp(array);
+	fvp(matrix);
+
+	fvp(fun);
+	fvp(&fun);
+	ffp(fun);
+	ffp(&fun);
+}
+
+// via a struct member:
+// -> force to create a register containing the function pointer
+struct ops {
+	int (*fb)(unsigned char);
+	int (*fi)(int);
+	int (*fl)(long);
+	int (*fv)(void);
+	int (*fip)(int *);
+	int (*fim)(int (*)[3]);
+	int (*fvp)(void *);
+	int (*ffp)(int (*)(int));
+
+	int (*const cfi)(int);		// for the fun of it
+};
+
+void ops(int a, int *p, struct ops *ops);
+void ops(int a, int *p, struct ops *ops)
+{
+	ops->fv();
+
+	ops->fb(a);
+	ops->fi(a);
+	ops->fl(a);
+	ops->fb(123);
+	ops->fi(123);
+	ops->fl(123);
+	ops->fb(123L);
+	ops->fi(123L);
+	ops->fl(123L);
+	ops->fb(ival);
+	ops->fi(ival);
+	ops->fl(ival);
+
+	ops->fip(p);
+	ops->fip((void*)0);
+	ops->fip(ipval);
+	ops->fip(&ival);
+	ops->fip(array);
+	ops->fim(matrix);
+
+	ops->fvp(p);
+	ops->fvp((void*)0);
+	ops->fvp(ipval);
+	ops->fvp(&ival);
+	ops->fvp(array);
+	ops->fvp(matrix);
+
+	ops->fvp(fun);
+	ops->fvp(&fun);
+	ops->ffp(fun);
+	ops->ffp(&fun);
+	ops->fvp(fi);
+
+	ops->cfi(42);
+}
+
 /*
  * check-name: Function pointer code generation
  * check-command: sparsec -c $file -o tmp.o
--- /dev/null	Mon Nov 18 13:19:48 2019
+++ new/usr/src/tools/smatch/src/validation/backend/label-as-value.c	Mon Nov 18 13:19:48 2019
@@ -0,0 +1,13 @@
+void *foo(void *def);
+void *foo(void *def)
+{
+	if (!def)
+yes:		return &&yes;
+
+	return def;
+}
+
+/*
+ * check-name: label-as-value
+ * check-command: sparsec -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:48 2019
+++ new/usr/src/tools/smatch/src/validation/backend/load-global.c	Mon Nov 18 13:19:48 2019
@@ -0,0 +1,21 @@
+const char *s = "abc";
+int x = 4;
+int y;
+
+int *p = &x;
+int *q;
+
+int loadn(void) { return y; }
+int loadi(void) { return x; }
+
+const char *loads(void) { return s; }
+
+int *retpn(void) { return  q; }
+int loadpn(void) { return *q; }
+int *retpi(void) { return  p; }
+int loadpi(void) { return *p; }
+
+/*
+ * check-name: use simple value from global vars
+ * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:48 2019
+++ new/usr/src/tools/smatch/src/validation/backend/pointer-add.c	Mon Nov 18 13:19:48 2019
@@ -0,0 +1,54 @@
+char *caddv(char *p, int o) { char *r = p; r = r + o; return r; }
+void *vaddv(void *p, int o) { void *r = p; r = r + o; return r; }
+int  *iaddv(int  *p, int o) { int  *r = p; r = r + o; return r; }
+
+char *caddc(char *p, int o) { char *r = p; r = r + 3; return r; }
+void *vaddc(void *p, int o) { void *r = p; r = r + 3; return r; }
+int  *iaddc(int  *p, int o) { int  *r = p; r = r + 3; return r; }
+
+char *cincv(char *p, int o) { char *r = p; r += o; return r; }
+void *vincv(void *p, int o) { void *r = p; r += o; return r; }
+int  *iincv(int  *p, int o) { int  *r = p; r += o; return r; }
+
+char *cincc(char *p, int o) { char *r = p; r += 3; return r; }
+void *vincc(void *p, int o) { void *r = p; r += 3; return r; }
+int  *iincc(int  *p, int o) { int  *r = p; r += 3; return r; }
+
+
+char *ciniaddv(char *p, int o) { char *r = p + o; return r; }
+void *viniaddv(void *p, int o) { void *r = p + o; return r; }
+int  *iiniaddv(int  *p, int o) { int  *r = p + o; return r; }
+
+char *ciniaddc(char *p, int o) { char *r = p + 3; return r; }
+void *viniaddc(void *p, int o) { void *r = p + 3; return r; }
+int  *iiniaddc(int  *p, int o) { int  *r = p + 3; return r; }
+
+char *ciniincv(char *p, int o) { char *r = p += o; return r; }
+void *viniincv(void *p, int o) { void *r = p += o; return r; }
+int  *iiniincv(int  *p, int o) { int  *r = p += o; return r; }
+
+char *ciniincc(char *p, int o) { char *r = p += 3; return r; }
+void *viniincc(void *p, int o) { void *r = p += 3; return r; }
+int  *iiniincc(int  *p, int o) { int  *r = p += 3; return r; }
+
+
+char *cretaddv(char *p, int o) { return p + o; }
+void *vretaddv(void *p, int o) { return p + o; }
+int  *iretaddv(int  *p, int o) { return p + o; }
+
+char *cretaddc(char *p, int o) { return p + 3; }
+void *vretaddc(void *p, int o) { return p + 3; }
+int  *iretaddc(int  *p, int o) { return p + 3; }
+
+char *cretincv(char *p, int o) { return p += o; }
+void *vretincv(void *p, int o) { return p += o; }
+int  *iretincv(int  *p, int o) { return p += o; }
+
+char *cretincc(char *p, int o) { return p += 3; }
+void *vretincc(void *p, int o) { return p += 3; }
+int  *iretincc(int  *p, int o) { return p += 3; }
+
+/*
+ * check-name: pointer-add
+ * check-command: sparsec -Wno-decl -c $file -o r.o
+ */
--- /dev/null	Mon Nov 18 13:19:48 2019
+++ new/usr/src/tools/smatch/src/validation/backend/pointer-cmp.c	Mon Nov 18 13:19:48 2019
@@ -0,0 +1,12 @@
+int cmpint(   int x,   int y)	{ return x == y; }
+int cmpflt( float x, float y)	{ return x == y; }
+int cmpvptr(void *x, void *y)	{ return x == y; }
+int cmpiptr(int  *x, int  *y)	{ return x == y; }
+
+int cmpmptr(long  x, int  *y)	{ return (int*)x == y; }
+int cmpnptr(int  *x, long  y)	{ return x == (int*)y; }
+
+/*
+ * check-name: pointer comparison
+ * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:48 2019
+++ new/usr/src/tools/smatch/src/validation/backend/pointer-param.c	Mon Nov 18 13:19:48 2019
@@ -0,0 +1,42 @@
+extern int gfun(int);
+static int sfun(int a) { return a; }
+
+void usei(int *);
+void usef(int (*)(int));
+void usev(void *);
+
+void foo(int *p, int a[5], int (*pfun)(int));
+void foo(int *p, int a[5], int (*pfun)(int))
+{
+	extern int valg[5], valh[5], vali[5];
+	static int vals[5], valt[5], valr[5];
+	       int vala[5], valb[5], valc[5];
+
+	usei(p);
+	usei(valg);
+	usei(&valh[0]);
+	usei(&vali[1]);
+	usei(vals);
+	usei(&valt[0]);
+	usei(&valr[1]);
+	usei(vala);
+	usei(&valb[0]);
+	usei(&valc[1]);
+
+	usef(pfun);
+	usef(gfun);
+	usef(&gfun);
+	usef(sfun);
+	usef(&sfun);
+
+	usev(pfun);
+	usev(gfun);
+	usev(&gfun);
+	usev(sfun);
+	usev(&sfun);
+}
+
+/*
+ * check-name: pointer-param
+ * check-command: sparsec -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:48 2019
+++ new/usr/src/tools/smatch/src/validation/backend/pointer-sub.c	Mon Nov 18 13:19:49 2019
@@ -0,0 +1,17 @@
+long subv0(void *p, int   a) { return p - ((void*)0); }
+long subvc(void *p, int   a) { return p - ((void*)8); }
+long subva(void *p, int   a) { return p - ((void*)a); }
+long subvq(void *p, void *q) { return p - q; }
+
+long subi0(int  *p, int   a) { return p - ((int *)0); }
+long subic(int  *p, int   a) { return p - ((int *)8); }
+long subia(int  *p, int   a) { return p - ((int *)a); }
+long subiq(int  *p, int  *q) { return p - q; }
+
+long subvm3(void *p, int   a) { return (p - ((void*)0)) * 3; }
+long subvx3(void *p, int   a) { return (p - ((void*)0)) ^ 3; }
+
+/*
+ * check-name: pointer-sub
+ * check-command: sparsec -Wno-int-to-pointer-cast -Wno-decl -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:49 2019
+++ new/usr/src/tools/smatch/src/validation/backend/setval.c	Mon Nov 18 13:19:49 2019
@@ -0,0 +1,7 @@
+double setfval64(void) { return 1.23; }
+float  setfval32(void) { return 1.23F; }
+
+/*
+ * check-name: setval-float
+ * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:49 2019
+++ new/usr/src/tools/smatch/src/validation/backend/shift-special.c	Mon Nov 18 13:19:49 2019
@@ -0,0 +1,13 @@
+long shift(long a, short b);
+long shift(long a, short b)
+{
+	long r1 = a << b;
+	long r2 = b << a;
+
+	return r1 + r2;
+}
+
+/*
+ * check-name: shift-special
+ * check-command: sparsec -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:49 2019
+++ new/usr/src/tools/smatch/src/validation/backend/store-x2.c	Mon Nov 18 13:19:49 2019
@@ -0,0 +1,16 @@
+void foo(int *p, int a, int b);
+void foo(int *p, int a, int b)
+{
+	int c = a + b;
+
+	p[0] = c;
+	p[1] = c;
+}
+
+/*
+ * check-name: store-x2
+ * check-command: sparsec -c $file -o tmp.o
+ * check-description: Verify in output_op_store() that
+ *	the first store doesn't mess anymore with the
+ *	'target' and thus making the second store unusable.
+ */
--- /dev/null	Mon Nov 18 13:19:49 2019
+++ new/usr/src/tools/smatch/src/validation/backend/string-value.c	Mon Nov 18 13:19:49 2019
@@ -0,0 +1,21 @@
+extern void use(const char *);
+
+const char *ret(void)
+{
+	return "abc";
+}
+
+const char *add(void)
+{
+	return "def" + 1;
+}
+
+void call(void)
+{
+	use("ijk");
+}
+
+/*
+ * check-name: string-value
+ * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ */
--- old/usr/src/tools/smatch/src/validation/backend/sum.c	Mon Nov 18 13:19:49 2019
+++ new/usr/src/tools/smatch/src/validation/backend/sum.c	Mon Nov 18 13:19:49 2019
@@ -19,7 +19,7 @@
 
 /*
  * check-name: sum from 1 to n
- * check-command: sparsei $file
+ * check-command: sparsei --no-jit $file
  *
  * check-output-start
 15
--- /dev/null	Mon Nov 18 13:19:50 2019
+++ new/usr/src/tools/smatch/src/validation/backend/switch.c	Mon Nov 18 13:19:50 2019
@@ -0,0 +1,248 @@
+int def(void);
+int r0(void);
+int r1(void);
+int r2(void);
+int r3(void);
+int r4(void);
+int r5(void);
+int r6(void);
+int r7(void);
+int r8(void);
+int r9(void);
+
+int small(int a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 1: return r1();
+	case 2: return r2();
+	}
+
+	return def();
+}
+
+int densefull(int a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 1: return r1();
+	case 2: return r2();
+	case 3: return r3();
+	case 4: return r4();
+	case 5: return r5();
+	case 6: return r6();
+	case 7: return r7();
+	case 8: return r8();
+	case 9: return r9();
+	}
+
+	return def();
+}
+
+int densepart(int a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 1: return r1();
+	case 2: return r2();
+	case 3: return r3();
+	case 4: return r4();
+
+	case 6: return r6();
+	case 7: return r7();
+	case 8: return r8();
+	case 9: return r9();
+	}
+
+	return def();
+}
+
+int dense_dense_20(int a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 1: return r1();
+	case 2: return r2();
+	case 3: return r3();
+	case 4: return r4();
+	case 5: return r5();
+	case 6: return r6();
+	case 7: return r7();
+	case 8: return r8();
+	case 9: return r9();
+
+	case 20: return r0();
+	case 21: return r1();
+	case 22: return r2();
+	case 23: return r3();
+	case 24: return r4();
+	case 25: return r5();
+	case 26: return r6();
+	case 27: return r7();
+	case 28: return r8();
+	case 29: return r9();
+	}
+
+	return def();
+}
+
+int dense_dense_100(int a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 1: return r1();
+	case 2: return r2();
+	case 3: return r3();
+	case 4: return r4();
+	case 5: return r5();
+	case 6: return r6();
+	case 7: return r7();
+	case 8: return r8();
+	case 9: return r9();
+
+	case 100: return r0();
+	case 101: return r1();
+	case 102: return r2();
+	case 103: return r3();
+	case 104: return r4();
+	case 105: return r5();
+	case 106: return r6();
+	case 107: return r7();
+	case 108: return r8();
+	case 109: return r9();
+	}
+
+	return def();
+}
+
+int dense_dense_1000(int a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 1: return r1();
+	case 2: return r2();
+	case 3: return r3();
+	case 4: return r4();
+	case 5: return r5();
+	case 6: return r6();
+	case 7: return r7();
+	case 8: return r8();
+	case 9: return r9();
+
+	case 1000: return r0();
+	case 1001: return r1();
+	case 1002: return r2();
+	case 1003: return r3();
+	case 1004: return r4();
+	case 1005: return r5();
+	case 1006: return r6();
+	case 1007: return r7();
+	case 1008: return r8();
+	case 1009: return r9();
+	}
+
+	return def();
+}
+
+int sparse(int a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 3: return r1();
+	case 12: return r2();
+	case 31: return r3();
+	case 54: return r4();
+	case 75: return r5();
+	case 96: return r6();
+	case 107: return r7();
+	case 189: return r8();
+	case 999: return r9();
+	}
+
+	return def();
+}
+
+int range_simple(int a)
+{
+	switch (a) {
+	case 1 ... 9: return r0();
+	}
+
+	return def();
+}
+
+int range_complex(int a)
+{
+	switch (a) {
+	case -1: return r0();
+	case 1 ... 9: return r0();
+	case 10 ... 19: return r1();
+	case 200 ... 202: return r2();
+	case 300 ... 303: return r3();
+	}
+
+	return def();
+}
+
+void switch_call(int a)
+{
+	int r;
+
+	switch (a) {
+	case 0: r0(); break;
+	case 1: r1(); break;
+	case 2: r2(); break;
+	case 3: r3(); break;
+	case 4: r4(); break;
+	case 5: r5(); break;
+	case 6: r6(); break;
+	case 7: r7(); break;
+	case 8: r8(); break;
+	case 9: r9(); break;
+	}
+}
+
+int switch_retcall(int a)
+{
+	int r = 0;
+
+	switch (a) {
+	case 0: r = r0(); break;
+	case 1: r = r1(); break;
+	case 2: r = r2(); break;
+	case 3: r = r3(); break;
+	case 4: r = r4(); break;
+	case 5: r = r5(); break;
+	case 6: r = r6(); break;
+	case 7: r = r7(); break;
+	case 8: r = r8(); break;
+	case 9: r = r9(); break;
+	}
+
+	return r;
+}
+
+int switch_cmov(int a)
+{
+	int r;
+
+	switch (a) {
+	case 0: r = 3; break;
+	case 1: r = 1; break;
+	case 2: r = 7; break;
+	case 3: r = 2; break;
+	case 4: r = 9; break;
+
+	case 6: r = 5; break;
+	case 7: r = 8; break;
+	case 8: r = 6; break;
+	case 9: r = 4; break;
+	}
+
+	return r;
+}
+
+/*
+ * check-name: llvm-switch
+ * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:50 2019
+++ new/usr/src/tools/smatch/src/validation/backend/symaddr.c	Mon Nov 18 13:19:50 2019
@@ -0,0 +1,70 @@
+extern void useip(int *);
+extern void useia(int (*)[3]);
+extern void usevp(void *);
+static int  sfun(void) { return 0; }
+static int  spun(void) { return 0; }
+
+void lfoo(int *p, int a)
+{
+	int larra[3], larrb[3], larrc[3], larrd[3], larre[3], larrf[3];
+	useip(p);
+	useip(larra);
+	useip(larrb + 1);
+	useip(larrc + a);
+	useip(&larrd[1]);
+	useip(&larre[a]);
+	useia(&larrf);
+}
+
+static int sarra[3], sarrb[3], sarrc[3], sarrd[3], sarre[3], sarrf[3];
+static int s, sfun(void), spun(void);
+void sfoo(int *p, int a)
+{
+	useip(p);
+	useip(&s);
+	useip(sarra);
+	useip(sarrb + 1);
+	useip(sarrc + a);
+	useip(&sarrd[1]);
+	useip(&sarre[a]);
+	useia(&sarrf);
+	usevp(sfun);
+	usevp(&spun);
+}
+
+extern int xarra[3], xarrb[3], xarrc[3], xarrd[3], xarre[3], xarrf[3];
+extern int x, xfun(void), xpun(void);
+void xfoo(int *p, int a)
+{
+	useip(p);
+	useip(&x);
+	useip(xarra);
+	useip(xarrb + 1);
+	useip(xarrc + a);
+	useip(&xarrd[1]);
+	useip(&xarre[a]);
+	useia(&xarrf);
+	usevp(xfun);
+	usevp(&xpun);
+}
+
+int garra[3], garrb[3], garrc[3], garrd[3], garre[3], garrf[3];
+int g, gfun(void), gpun(void);
+void gfoo(int *p, int a)
+{
+	useip(p);
+	useip(&g);
+	useip(garra);
+	useip(garrb + 1);
+	useip(garrc + a);
+	useip(&garrd[1]);
+	useip(&garre[a]);
+	useia(&garrf);
+	usevp(gfun);
+	usevp(&gpun);
+}
+
+/*
+ * check-name: symbol address
+ * check-command: sparsec -Wno-decl -c $file -o tmp.o
+ */
--- /dev/null	Mon Nov 18 13:19:50 2019
+++ new/usr/src/tools/smatch/src/validation/backend/type-constant.c	Mon Nov 18 13:19:50 2019
@@ -0,0 +1,23 @@
+char creti(void) { return 3; }
+int  ireti(void) { return 3; }
+long lreti(void) { return 3; }
+
+char cinii(void) { char r = 3; return r; }
+int  iinii(void) { int  r = 3; return r; }
+long linii(void) { long r = 3; return r; }
+
+
+void *vretn(void) { return (void*)0; }
+char *cretn(void) { return (void*)0; }
+int  *iretn(void) { return (void*)0; }
+long *lretn(void) { return (void*)0; }
+
+void *vinin(void) { void *r = (void*)0; return r; }
+char *cinin(void) { char *r = (void*)0; return r; }
+int  *iinin(void) { int  *r = (void*)0; return r; }
+long *linin(void) { long *r = (void*)0; return r; }
+
+/*
+ * check-name: type-constant
+ * check-command: sparsec -Wno-decl -c $file -o r.o
+ */
--- /dev/null	Mon Nov 18 13:19:50 2019
+++ new/usr/src/tools/smatch/src/validation/bad-return-type.c	Mon Nov 18 13:19:50 2019
@@ -0,0 +1,19 @@
+void foo(int a)
+{
+	return a;
+}
+
+int bar(void)
+{
+	return;
+}
+
+/*
+ * check-name: bad return type
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+bad-return-type.c:3:16: error: return expression in void function
+bad-return-type.c:8:9: error: return with no return value
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:50 2019
+++ new/usr/src/tools/smatch/src/validation/bad-type-twice0.c	Mon Nov 18 13:19:50 2019
@@ -0,0 +1,13 @@
+static int foo(a)
+{
+	return a ? : 1;
+}
+
+/*
+ * check-name: bad-type-twice0
+ *
+ * check-error-start
+bad-type-twice0.c:3:16: error: incorrect type in conditional (non-scalar type)
+bad-type-twice0.c:3:16:    got incomplete type a
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:50 2019
+++ new/usr/src/tools/smatch/src/validation/bad-type-twice1.c	Mon Nov 18 13:19:50 2019
@@ -0,0 +1,16 @@
+static unsigned long foo(unsigned long val, void *ref)
+{
+	if (val >= ref)
+		val = 0;
+	return val;
+}
+
+/*
+ * check-name: bad-type-twice1
+ *
+ * check-error-start
+bad-type-twice1.c:3:17: error: incompatible types for operation (>=)
+bad-type-twice1.c:3:17:    left side has type unsigned long val
+bad-type-twice1.c:3:17:    right side has type void *ref
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:50 2019
+++ new/usr/src/tools/smatch/src/validation/bad-type-twice2.c	Mon Nov 18 13:19:50 2019
@@ -0,0 +1,18 @@
+extern type_t fun(int);
+
+int foo(int x, int y)
+{
+	return ((int)fun(y)) + x;
+}
+
+/*
+ * check-name: bad-type-twice2
+ *
+ * check-error-start
+bad-type-twice2.c:1:8: warning: 'type_t' has implicit type
+bad-type-twice2.c:1:15: error: Expected ; at end of declaration
+bad-type-twice2.c:1:15: error: got fun
+bad-type-twice2.c:5:22: error: undefined identifier 'fun'
+bad-type-twice2.c:5:18: error: cast from unknown type
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:51 2019
+++ new/usr/src/tools/smatch/src/validation/bitfield-bool-layout.c	Mon Nov 18 13:19:51 2019
@@ -0,0 +1,26 @@
+struct bfb {
+	_Bool a:1;
+	_Bool f:1;
+	_Bool z:1;
+};
+
+
+struct bfb foo(struct bfb s)
+{
+	return s;
+}
+
+/*
+ * check-name: bitfield-bool-layout
+ * check-description: given that bool is here 1-bit wide
+ *	each field here above completely 'fill' a bool.
+ *	Thus 3 bools need to be allocated, but since the
+ *	alignment is 1-byte the result has a size of 3
+ *	bytes, 24 bits thus instead of 8.
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-known-to-fail
+ * check-output-ignore
+ * check-output-excludes: ret\\.24
+ * check-output-contains: ret\\.8
+ */
--- /dev/null	Mon Nov 18 13:19:51 2019
+++ new/usr/src/tools/smatch/src/validation/bitfield-kr.c	Mon Nov 18 13:19:51 2019
@@ -0,0 +1,14 @@
+static int foo(b)
+	int b: 4;
+{
+      return 0;
+}
+
+/*
+ * check-name: bitfield in K&R
+ *
+ * check-known-to-fail
+ * check-error-start
+bitfield-kr.c:2:9: error: bitfield in K&R declaration of 'foo'
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:51 2019
+++ new/usr/src/tools/smatch/src/validation/bitwise-cast-ptr.c	Mon Nov 18 13:19:51 2019
@@ -0,0 +1,33 @@
+#define __bitwise	__attribute__((bitwise))
+#define __force		__attribute__((force))
+
+typedef unsigned int u32;
+typedef unsigned int __bitwise __be32;
+
+static __be32* tobi(u32 *x)
+{
+	return x;			// should warn, implicit cast
+}
+
+static __be32* tobe(u32 *x)
+{
+	return (__be32 *) x;		// should warn, explicit cast
+}
+
+static __be32* tobf(u32 *x)
+{
+	return (__force __be32 *) x;	// should not warn, forced cast
+	return (__be32 __force *) x;	// should not warn, forced cast
+}
+
+/*
+ * check-name: cast of bitwise pointers
+ * check-command: sparse -Wbitwise -Wbitwise-pointer $file
+ *
+ * check-error-start
+bitwise-cast-ptr.c:9:16: warning: incorrect type in return expression (different base types)
+bitwise-cast-ptr.c:9:16:    expected restricted __be32 [usertype] *
+bitwise-cast-ptr.c:9:16:    got unsigned int [usertype] *x
+bitwise-cast-ptr.c:14:17: warning: cast to restricted __be32 [usertype] *
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/bitwise-cast.c	Mon Nov 18 13:19:51 2019
+++ new/usr/src/tools/smatch/src/validation/bitwise-cast.c	Mon Nov 18 13:19:51 2019
@@ -29,6 +29,12 @@
 	return (__be32)1729;
 }
 
+/* Explicit case of nonzero forced, legal */
+static __be32 quuy(void)
+{
+	return (__attribute__((force)) __be32) 1730;
+}
+
 /*
  * check-name: conversions to bitwise types
  * check-command: sparse -Wbitwise $file
--- old/usr/src/tools/smatch/src/validation/bool-cast-explicit.c	Mon Nov 18 13:19:51 2019
+++ /dev/null	Mon Nov 18 13:19:51 2019
@@ -1,22 +0,0 @@
-typedef unsigned int	u32;
-typedef          int	s32;
-typedef void *vdp;
-typedef int  *sip;
-typedef double dbl;
-typedef unsigned short __attribute__((bitwise)) le16;
-
-static _Bool fs32(s32 a) { return (_Bool)a; }
-static _Bool fu32(u32 a) { return (_Bool)a; }
-static _Bool fvdp(vdp a) { return (_Bool)a; }
-static _Bool fsip(sip a) { return (_Bool)a; }
-static _Bool fdbl(dbl a) { return (_Bool)a; }
-static _Bool ffun(void)  { return (_Bool)ffun; }
-
-static _Bool fres(le16 a) { return (_Bool)a; }
-
-/*
- * check-name: bool-cast-explicit
- * check-command: test-linearize -m64 $file
- * check-output-ignore
- * check-output-excludes: cast\\.
- */
--- old/usr/src/tools/smatch/src/validation/bool-cast-implicit.c	Mon Nov 18 13:19:51 2019
+++ /dev/null	Mon Nov 18 13:19:51 2019
@@ -1,25 +0,0 @@
-typedef unsigned int	u32;
-typedef          int	s32;
-typedef void *vdp;
-typedef int  *sip;
-typedef double dbl;
-typedef unsigned short __attribute__((bitwise)) le16;
-
-static _Bool fs32(s32 a) { return a; }
-static _Bool fu32(u32 a) { return a; }
-static _Bool fvdp(vdp a) { return a; }
-static _Bool fsip(sip a) { return a; }
-static _Bool fdbl(dbl a) { return a; }
-static _Bool ffun(void)  { return ffun; }
-
-static _Bool fres(le16 a) { return a; }
-
-/*
- * check-name: bool-cast-implicit
- * check-command: test-linearize -m64 $file
- * check-output-ignore
- * check-output-excludes: cast\\.
- *
- * check-error-start
- * check-error-end
- */
--- /dev/null	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/bool-float.c	Mon Nov 18 13:19:52 2019
@@ -0,0 +1,9 @@
+int ftst(double a)  { return !a; }
+
+/*
+ * check-name: not-operator on float
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: \\$0
+ */
--- /dev/null	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/bug-bad-type.c	Mon Nov 18 13:19:52 2019
@@ -0,0 +1,18 @@
+struct s {
+	int   i;
+};
+
+long a;
+void foo(void)
+{
+	(struct s) { .i = (foo - a), };
+}
+
+/*
+ * check-name: bug-bad-type
+ *
+ * check-error-start
+bug-bad-type.c:5:6: warning: symbol 'a' was not declared. Should it be static?
+bug-bad-type.c:8:32: error: arithmetics on pointers to functions
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/bug-crash16.c	Mon Nov 18 13:19:52 2019
@@ -0,0 +1,11 @@
+static void foo(void)
+{
+	int b[] = { 8 };
+	int c;
+	for (;;)
+		b[c] = b[0];
+}
+
+/*
+ * check-name: bug-crash16
+ */
--- /dev/null	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/bug-expand-union0.c	Mon Nov 18 13:19:52 2019
@@ -0,0 +1,21 @@
+union u {
+	char c;
+	float f;
+};
+
+static int foo(void)
+{
+	union u u = { .f = 0.123 };
+	return u.c;
+}
+
+/*
+ * check-name: bug-expand-union
+ * check description: must not infer the value from the float
+ * check-command: test-linearize $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ * check-output-excludes: ret\\..*\\$
+ */
--- /dev/null	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/bug-expand-union1.c	Mon Nov 18 13:19:52 2019
@@ -0,0 +1,20 @@
+union u {
+	int i;
+	float f;
+};
+
+static int foo(void)
+{
+	union u u = { .f = 0.123 };
+	return u.i;
+}
+
+/*
+ * check-name: bug-expand-union
+ * check description: must not infer the value from the float
+ * check-command: test-linearize $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ */
--- /dev/null	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/bug-rshift-ub.c	Mon Nov 18 13:19:52 2019
@@ -0,0 +1,16 @@
+enum a {
+	A = ~0ULL,
+};
+
+static enum a a = A;
+
+/*
+ * check-name: bug-rshift-ub
+ * check-description:
+ *	This test trigger(ed) a bug on x86 caused by a
+ *	full width shift (which is UB), expecting to get
+ *	0 but giving the unshifted value and as result
+ *	the type is invalid:
+ *		warning: incorrect type in initializer (invalid types)
+ *			 expected bad type enum a static [toplevel] a
+ */
--- /dev/null	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/builtin-arith.c	Mon Nov 18 13:19:52 2019
@@ -0,0 +1,52 @@
+
+
+void test(void (*fun)(void));
+void test(void (*fun)(void))
+{
+	typedef typeof(__builtin_trap) t;	// OK
+	void (*f)(void);
+	int i;
+
+	f =  __builtin_trap;
+	f = &__builtin_trap;
+	f = *__builtin_trap;			// OK for GCC
+	f =  __builtin_trap + 0;
+	f =  __builtin_trap + 1;
+	f =  __builtin_trap - 1;
+
+	// (void) __builtin_trap;
+	f = (void*) __builtin_trap;
+	f = (unsigned long) __builtin_trap;
+
+	i = !__builtin_trap;
+	i = (__builtin_trap > fun);
+	i = (__builtin_trap == fun);
+	i = (fun <  __builtin_trap);
+	i = (fun == __builtin_trap);
+
+	__builtin_trap - fun;
+	fun - __builtin_trap;
+}
+
+/*
+ * check-name: builtin arithmetic
+ * check-command: sparse -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-error-start
+builtin-arith.c:10:xx: error: ...
+builtin-arith.c:11:xx: error: ...
+builtin-arith.c:13:xx: error: arithmetics on pointers to functions
+builtin-arith.c:14:xx: error: arithmetics on pointers to functions
+builtin-arith.c:15:xx: error: arithmetics on pointers to functions
+builtin-arith.c:18:xx: error: ...
+builtin-arith.c:19:xx: error: ...
+builtin-arith.c:21:xx: error: ...
+builtin-arith.c:22:xx: error: ...
+builtin-arith.c:23:xx: error: ...
+builtin-arith.c:24:xx: error: ...
+builtin-arith.c:25:xx: error: ...
+builtin-arith.c:27:24: error: subtraction of functions? Share your drugs
+builtin-arith.c:28:13: error: subtraction of functions? Share your drugs
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/builtin-bswap-variable.c	Mon Nov 18 13:19:52 2019
+++ new/usr/src/tools/smatch/src/validation/builtin-bswap-variable.c	Mon Nov 18 13:19:53 2019
@@ -25,8 +25,8 @@
  *
  * check-output-ignore
  * check-output-contains:call.16 .* __builtin_bswap16
- * check-output-contains:cast.32 .* (64) %arg1
+ * check-output-contains:trunc.32 .* (64) %arg1
  * check-output-contains:call.32 .* __builtin_bswap32
- * check-output-contains:cast.64 .* (32) %arg1
+ * check-output-contains:zext.64 .* (32) %arg1
  * check-output-contains:call.64 .* __builtin_bswap64
  */
--- /dev/null	Mon Nov 18 13:19:53 2019
+++ new/usr/src/tools/smatch/src/validation/builtin-fp-unop.c	Mon Nov 18 13:19:53 2019
@@ -0,0 +1,95 @@
+static void test_not_enough_args(void)
+{
+	__builtin_isfinite();
+	__builtin_isinf();
+	__builtin_isinf_sign();
+	__builtin_isnan();
+	__builtin_isnormal();
+	__builtin_signbit();
+}
+
+static void test_too_many_args(double v)
+{
+	__builtin_isfinite(v, v);
+	__builtin_isinf(v, v);
+	__builtin_isinf_sign(v, v);
+	__builtin_isnan(v, v);
+	__builtin_isnormal(v, v);
+	__builtin_signbit(v, v);
+}
+
+static void test_non_float(int v)
+{
+	__builtin_isfinite(v);
+	__builtin_isinf(v);
+	__builtin_isinf_sign(v);
+	__builtin_isnan(v);
+	__builtin_isnormal(v);
+	__builtin_signbit(v);
+}
+
+static void test_float(float v)
+{
+	__builtin_isfinite(v);
+	__builtin_isinf(v);
+	__builtin_isinf_sign(v);
+	__builtin_isnan(v);
+	__builtin_isnormal(v);
+	__builtin_signbit(v);
+}
+
+static void test_double(double v)
+{
+	__builtin_isfinite(v);
+	__builtin_isinf(v);
+	__builtin_isinf_sign(v);
+	__builtin_isnan(v);
+	__builtin_isnormal(v);
+	__builtin_signbit(v);
+}
+
+static void test_ldouble(long double v)
+{
+	__builtin_isfinite(v);
+	__builtin_isinf(v);
+	__builtin_isinf_sign(v);
+	__builtin_isnan(v);
+	__builtin_isnormal(v);
+	__builtin_signbit(v);
+}
+
+static void test_constant(void)
+{
+	__builtin_isfinite(0.0);
+	__builtin_isinf(0.0);
+	__builtin_isinf_sign(0.0);
+	__builtin_isnan(0.0);
+	__builtin_isnormal(0.0);
+	__builtin_signbit(0.0);
+}
+
+/*
+ * check-name: builtin float-point unop
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+builtin-fp-unop.c:3:27: error: not enough arguments for __builtin_isfinite
+builtin-fp-unop.c:4:24: error: not enough arguments for __builtin_isinf
+builtin-fp-unop.c:5:29: error: not enough arguments for __builtin_isinf_sign
+builtin-fp-unop.c:6:24: error: not enough arguments for __builtin_isnan
+builtin-fp-unop.c:7:27: error: not enough arguments for __builtin_isnormal
+builtin-fp-unop.c:8:26: error: not enough arguments for __builtin_signbit
+builtin-fp-unop.c:13:27: error: too many arguments for __builtin_isfinite
+builtin-fp-unop.c:14:24: error: too many arguments for __builtin_isinf
+builtin-fp-unop.c:15:29: error: too many arguments for __builtin_isinf_sign
+builtin-fp-unop.c:16:24: error: too many arguments for __builtin_isnan
+builtin-fp-unop.c:17:27: error: too many arguments for __builtin_isnormal
+builtin-fp-unop.c:18:26: error: too many arguments for __builtin_signbit
+builtin-fp-unop.c:23:27: error: non-floating-point argument in call to __builtin_isfinite()
+builtin-fp-unop.c:24:24: error: non-floating-point argument in call to __builtin_isinf()
+builtin-fp-unop.c:25:29: error: non-floating-point argument in call to __builtin_isinf_sign()
+builtin-fp-unop.c:26:24: error: non-floating-point argument in call to __builtin_isnan()
+builtin-fp-unop.c:27:27: error: non-floating-point argument in call to __builtin_isnormal()
+builtin-fp-unop.c:28:26: error: non-floating-point argument in call to __builtin_signbit()
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:53 2019
+++ new/usr/src/tools/smatch/src/validation/builtin-overflow.c	Mon Nov 18 13:19:53 2019
@@ -0,0 +1,246 @@
+enum e { OK, KO = -1 };
+typedef _Bool bool;
+
+static int test(int i, long l, long long ll, enum e e, bool b, void *p)
+{
+	int rc = 0;
+
+	// should be OK
+	rc += __builtin_add_overflow(i, i, &i);
+	rc += __builtin_add_overflow(l, i, &i);
+	rc += __builtin_add_overflow(i, l, &i);
+	rc += __builtin_add_overflow(i, i, &l);
+	rc += __builtin_add_overflow(ll, i, &i);
+	rc += __builtin_add_overflow(i, ll, &i);
+	rc += __builtin_add_overflow(i, i, &ll);
+
+	rc += __builtin_add_overflow_p(i, i, i);
+	rc += __builtin_add_overflow_p(l, i, i);
+	rc += __builtin_add_overflow_p(i, l, i);
+	rc += __builtin_add_overflow_p(i, i, l);
+	rc += __builtin_add_overflow_p(ll, i, i);
+	rc += __builtin_add_overflow_p(i, ll, i);
+	rc += __builtin_add_overflow_p(i, i, ll);
+
+	rc += __builtin_sub_overflow(i, i, &i);
+	rc += __builtin_sub_overflow(l, i, &i);
+	rc += __builtin_sub_overflow(i, l, &i);
+	rc += __builtin_sub_overflow(i, i, &l);
+	rc += __builtin_sub_overflow(ll, i, &i);
+	rc += __builtin_sub_overflow(i, ll, &i);
+	rc += __builtin_sub_overflow(i, i, &ll);
+
+	rc += __builtin_sub_overflow_p(i, i, i);
+	rc += __builtin_sub_overflow_p(l, i, i);
+	rc += __builtin_sub_overflow_p(i, l, i);
+	rc += __builtin_sub_overflow_p(i, i, l);
+	rc += __builtin_sub_overflow_p(ll, i, i);
+	rc += __builtin_sub_overflow_p(i, ll, i);
+	rc += __builtin_sub_overflow_p(i, i, ll);
+
+	rc += __builtin_mul_overflow(i, i, &i);
+	rc += __builtin_mul_overflow(l, i, &i);
+	rc += __builtin_mul_overflow(i, l, &i);
+	rc += __builtin_mul_overflow(i, i, &l);
+	rc += __builtin_mul_overflow(ll, i, &i);
+	rc += __builtin_mul_overflow(i, ll, &i);
+	rc += __builtin_mul_overflow(i, i, &ll);
+
+	rc += __builtin_mul_overflow_p(i, i, i);
+	rc += __builtin_mul_overflow_p(l, i, i);
+	rc += __builtin_mul_overflow_p(i, l, i);
+	rc += __builtin_mul_overflow_p(i, i, l);
+	rc += __builtin_mul_overflow_p(ll, i, i);
+	rc += __builtin_mul_overflow_p(i, ll, i);
+	rc += __builtin_mul_overflow_p(i, i, ll);
+
+	// should be KO
+	rc += __builtin_add_overflow();
+	rc += __builtin_add_overflow(i);
+	rc += __builtin_add_overflow(i, i);
+	rc += __builtin_add_overflow(i, i, &i, i);
+	rc += __builtin_add_overflow(e, i, &i);
+	rc += __builtin_add_overflow(i, e, &i);
+	rc += __builtin_add_overflow(i, i, &e);
+	rc += __builtin_add_overflow(b, i, &i);
+	rc += __builtin_add_overflow(i, b, &i);
+	rc += __builtin_add_overflow(i, i, &b);
+	rc += __builtin_add_overflow(i, i, p);
+
+	rc += __builtin_add_overflow_p();
+	rc += __builtin_add_overflow_p(i);
+	rc += __builtin_add_overflow_p(i, i);
+	rc += __builtin_add_overflow_p(i, i, i, i);
+	rc += __builtin_add_overflow_p(e, i, i);
+	rc += __builtin_add_overflow_p(i, e, i);
+	rc += __builtin_add_overflow_p(i, i, e);
+	rc += __builtin_add_overflow_p(b, i, i);
+	rc += __builtin_add_overflow_p(i, b, i);
+	rc += __builtin_add_overflow_p(i, i, b);
+	rc += __builtin_add_overflow_p(i, i, p);
+
+	rc += __builtin_sub_overflow();
+	rc += __builtin_sub_overflow(i);
+	rc += __builtin_sub_overflow(i, i);
+	rc += __builtin_sub_overflow(i, i, &i, i);
+	rc += __builtin_sub_overflow(e, i, &i);
+	rc += __builtin_sub_overflow(i, e, &i);
+	rc += __builtin_sub_overflow(i, i, &e);
+	rc += __builtin_sub_overflow(b, i, &i);
+	rc += __builtin_sub_overflow(i, b, &i);
+	rc += __builtin_sub_overflow(i, i, &b);
+	rc += __builtin_sub_overflow(i, i, p);
+
+	rc += __builtin_sub_overflow_p();
+	rc += __builtin_sub_overflow_p(i);
+	rc += __builtin_sub_overflow_p(i, i);
+	rc += __builtin_sub_overflow_p(i, i, i, i);
+	rc += __builtin_sub_overflow_p(e, i, i);
+	rc += __builtin_sub_overflow_p(i, e, i);
+	rc += __builtin_sub_overflow_p(i, i, e);
+	rc += __builtin_sub_overflow_p(b, i, i);
+	rc += __builtin_sub_overflow_p(i, b, i);
+	rc += __builtin_sub_overflow_p(i, i, b);
+	rc += __builtin_sub_overflow_p(i, i, p);
+
+	rc += __builtin_mul_overflow();
+	rc += __builtin_mul_overflow(i);
+	rc += __builtin_mul_overflow(i, i);
+	rc += __builtin_mul_overflow(i, i, &i, i);
+	rc += __builtin_mul_overflow(e, i, &i);
+	rc += __builtin_mul_overflow(i, e, &i);
+	rc += __builtin_mul_overflow(i, i, &e);
+	rc += __builtin_mul_overflow(b, i, &i);
+	rc += __builtin_mul_overflow(i, b, &i);
+	rc += __builtin_mul_overflow(i, i, &b);
+	rc += __builtin_mul_overflow(i, i, p);
+
+	rc += __builtin_mul_overflow_p();
+	rc += __builtin_mul_overflow_p(i);
+	rc += __builtin_mul_overflow_p(i, i);
+	rc += __builtin_mul_overflow_p(i, i, i, i);
+	rc += __builtin_mul_overflow_p(e, i, i);
+	rc += __builtin_mul_overflow_p(i, e, i);
+	rc += __builtin_mul_overflow_p(i, i, e);
+	rc += __builtin_mul_overflow_p(b, i, i);
+	rc += __builtin_mul_overflow_p(i, b, i);
+	rc += __builtin_mul_overflow_p(i, i, b);
+	rc += __builtin_mul_overflow_p(i, i, p);
+
+	return rc;
+}
+
+/*
+ * check-name: builtin-overflow
+ *
+ * check-error-start
+builtin-overflow.c:58:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:59:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:60:37: error: not enough arguments for __builtin_add_overflow
+builtin-overflow.c:61:37: error: too many arguments for __builtin_add_overflow
+builtin-overflow.c:62:38: error: invalid type for argument 1:
+builtin-overflow.c:62:38:         int enum e e
+builtin-overflow.c:63:41: error: invalid type for argument 2:
+builtin-overflow.c:63:41:         int enum e e
+builtin-overflow.c:64:45: error: invalid type for argument 3:
+builtin-overflow.c:64:45:         int enum e *
+builtin-overflow.c:65:38: error: invalid type for argument 1:
+builtin-overflow.c:65:38:         bool [usertype] b
+builtin-overflow.c:66:41: error: invalid type for argument 2:
+builtin-overflow.c:66:41:         bool [usertype] b
+builtin-overflow.c:67:45: error: invalid type for argument 3:
+builtin-overflow.c:67:45:         bool *
+builtin-overflow.c:68:44: error: invalid type for argument 3:
+builtin-overflow.c:68:44:         void *p
+builtin-overflow.c:70:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:71:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:72:39: error: not enough arguments for __builtin_add_overflow_p
+builtin-overflow.c:73:39: error: too many arguments for __builtin_add_overflow_p
+builtin-overflow.c:74:40: error: invalid type for argument 1:
+builtin-overflow.c:74:40:         int enum e [addressable] e
+builtin-overflow.c:75:43: error: invalid type for argument 2:
+builtin-overflow.c:75:43:         int enum e [addressable] e
+builtin-overflow.c:76:46: error: invalid type for argument 3:
+builtin-overflow.c:76:46:         int enum e [addressable] e
+builtin-overflow.c:77:40: error: invalid type for argument 1:
+builtin-overflow.c:77:40:         bool [addressable] [usertype] b
+builtin-overflow.c:78:43: error: invalid type for argument 2:
+builtin-overflow.c:78:43:         bool [addressable] [usertype] b
+builtin-overflow.c:79:46: error: invalid type for argument 3:
+builtin-overflow.c:79:46:         bool [addressable] [usertype] b
+builtin-overflow.c:80:46: error: invalid type for argument 3:
+builtin-overflow.c:80:46:         void *p
+builtin-overflow.c:82:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:83:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:84:37: error: not enough arguments for __builtin_sub_overflow
+builtin-overflow.c:85:37: error: too many arguments for __builtin_sub_overflow
+builtin-overflow.c:86:38: error: invalid type for argument 1:
+builtin-overflow.c:86:38:         int enum e [addressable] e
+builtin-overflow.c:87:41: error: invalid type for argument 2:
+builtin-overflow.c:87:41:         int enum e [addressable] e
+builtin-overflow.c:88:45: error: invalid type for argument 3:
+builtin-overflow.c:88:45:         int enum e *
+builtin-overflow.c:89:38: error: invalid type for argument 1:
+builtin-overflow.c:89:38:         bool [addressable] [usertype] b
+builtin-overflow.c:90:41: error: invalid type for argument 2:
+builtin-overflow.c:90:41:         bool [addressable] [usertype] b
+builtin-overflow.c:91:45: error: invalid type for argument 3:
+builtin-overflow.c:91:45:         bool *
+builtin-overflow.c:92:44: error: invalid type for argument 3:
+builtin-overflow.c:92:44:         void *p
+builtin-overflow.c:94:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:95:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:96:39: error: not enough arguments for __builtin_sub_overflow_p
+builtin-overflow.c:97:39: error: too many arguments for __builtin_sub_overflow_p
+builtin-overflow.c:98:40: error: invalid type for argument 1:
+builtin-overflow.c:98:40:         int enum e [addressable] e
+builtin-overflow.c:99:43: error: invalid type for argument 2:
+builtin-overflow.c:99:43:         int enum e [addressable] e
+builtin-overflow.c:100:46: error: invalid type for argument 3:
+builtin-overflow.c:100:46:         int enum e [addressable] e
+builtin-overflow.c:101:40: error: invalid type for argument 1:
+builtin-overflow.c:101:40:         bool [addressable] [usertype] b
+builtin-overflow.c:102:43: error: invalid type for argument 2:
+builtin-overflow.c:102:43:         bool [addressable] [usertype] b
+builtin-overflow.c:103:46: error: invalid type for argument 3:
+builtin-overflow.c:103:46:         bool [addressable] [usertype] b
+builtin-overflow.c:104:46: error: invalid type for argument 3:
+builtin-overflow.c:104:46:         void *p
+builtin-overflow.c:106:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:107:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:108:37: error: not enough arguments for __builtin_mul_overflow
+builtin-overflow.c:109:37: error: too many arguments for __builtin_mul_overflow
+builtin-overflow.c:110:38: error: invalid type for argument 1:
+builtin-overflow.c:110:38:         int enum e [addressable] e
+builtin-overflow.c:111:41: error: invalid type for argument 2:
+builtin-overflow.c:111:41:         int enum e [addressable] e
+builtin-overflow.c:112:45: error: invalid type for argument 3:
+builtin-overflow.c:112:45:         int enum e *
+builtin-overflow.c:113:38: error: invalid type for argument 1:
+builtin-overflow.c:113:38:         bool [addressable] [usertype] b
+builtin-overflow.c:114:41: error: invalid type for argument 2:
+builtin-overflow.c:114:41:         bool [addressable] [usertype] b
+builtin-overflow.c:115:45: error: invalid type for argument 3:
+builtin-overflow.c:115:45:         bool *
+builtin-overflow.c:116:44: error: invalid type for argument 3:
+builtin-overflow.c:116:44:         void *p
+builtin-overflow.c:118:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:119:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:120:39: error: not enough arguments for __builtin_mul_overflow_p
+builtin-overflow.c:121:39: error: too many arguments for __builtin_mul_overflow_p
+builtin-overflow.c:122:40: error: invalid type for argument 1:
+builtin-overflow.c:122:40:         int enum e [addressable] e
+builtin-overflow.c:123:43: error: invalid type for argument 2:
+builtin-overflow.c:123:43:         int enum e [addressable] e
+builtin-overflow.c:124:46: error: invalid type for argument 3:
+builtin-overflow.c:124:46:         int enum e [addressable] e
+builtin-overflow.c:125:40: error: invalid type for argument 1:
+builtin-overflow.c:125:40:         bool [addressable] [usertype] b
+builtin-overflow.c:126:43: error: invalid type for argument 2:
+builtin-overflow.c:126:43:         bool [addressable] [usertype] b
+builtin-overflow.c:127:46: error: invalid type for argument 3:
+builtin-overflow.c:127:46:         bool [addressable] [usertype] b
+builtin-overflow.c:128:46: error: invalid type for argument 3:
+builtin-overflow.c:128:46:         void *p
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:53 2019
+++ new/usr/src/tools/smatch/src/validation/builtin-prototype.c	Mon Nov 18 13:19:53 2019
@@ -0,0 +1,15 @@
+void memcpy(void *dst, const void *src, unsigned int size);
+void memcpy(void *dst, const void *src, unsigned int size)
+{
+	__builtin_memcpy(dst, src, size);
+}
+
+unsigned int strlen(const char *src);
+unsigned int strlen(const char *src)
+{
+	return __builtin_strlen(src);
+}
+
+/*
+ * check-name: builtin-prototype
+ */
--- old/usr/src/tools/smatch/src/validation/c11-alignas.c	Mon Nov 18 13:19:53 2019
+++ new/usr/src/tools/smatch/src/validation/c11-alignas.c	Mon Nov 18 13:19:53 2019
@@ -36,5 +36,5 @@
  * check-error-end
  *
  * check-output-ignore
- * check-output-contains: ret\\.32 *\$0
+ * check-output-contains: ret\\.32 *\\$0
  */
--- old/usr/src/tools/smatch/src/validation/c11-alignof.c	Mon Nov 18 13:19:54 2019
+++ new/usr/src/tools/smatch/src/validation/c11-alignof.c	Mon Nov 18 13:19:54 2019
@@ -8,5 +8,5 @@
  * check-command: test-linearize -std=c11 $file
  *
  * check-output-ignore
- * check-output-contains: ret\\.32 *\$2
+ * check-output-contains: ret\\.32 *\\$2
  */
--- /dev/null	Mon Nov 18 13:19:54 2019
+++ new/usr/src/tools/smatch/src/validation/c11-atomic.c	Mon Nov 18 13:19:54 2019
@@ -0,0 +1,93 @@
+void f00(int _Atomic  dst);
+void f01(int _Atomic *dst);
+void f02(int _Atomic *dst);
+void f03(int _Atomic *dst);
+
+int _Atomic qo;
+int         uo;
+
+void f00(int dst)	  { }	/* check-should-pass */
+void f01(typeof(&qo) dst) { }	/* check-should-pass */
+void f02(int *dst)	  { }	/* check-should-fail */
+void f03(typeof(&uo) dst) { }	/* check-should-fail */
+
+void foo(void)
+{
+	qo = uo;		/* check-should-pass */
+	uo = qo;		/* check-should-pass */
+}
+
+void ref(void)
+{
+	const int qo;
+	int uo;
+	extern const int *pqo;
+	extern       int *puo;
+
+	pqo = &qo;		/* check-should-pass */
+	pqo = &uo;		/* check-should-pass */
+	pqo = puo;
+
+	puo = &uo;		/* check-should-pass */
+
+	puo = &qo;		/* check-should-fail */
+	puo = pqo;		/* check-should-fail */
+}
+
+void bar(void)
+{
+	extern int _Atomic *pqo;
+	extern int         *puo;
+
+	pqo = &qo;		/* check-should-pass */
+	pqo = &uo;		/* check-should-pass */
+	pqo = puo;
+
+	puo = &uo;		/* check-should-pass */
+
+	puo = &qo;		/* check-should-fail */
+	puo = pqo;		/* check-should-fail */
+}
+
+void baz(void)
+{
+	extern typeof(&qo) pqo;
+	extern typeof(&uo) puo;
+
+	pqo = &qo;		/* check-should-pass */
+	pqo = &uo;		/* check-should-pass */
+	pqo = puo;
+
+	puo = &uo;		/* check-should-pass */
+
+	puo = &qo;		/* check-should-fail */
+	puo = pqo;		/* check-should-fail */
+}
+
+/*
+ * check-name: C11 _Atomic type qualifier
+ * check-command: sparse -Wno-decl $file;
+ *
+ * check-error-start
+c11-atomic.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at c11-atomic.c:3) - incompatible argument 1 (different modifiers)
+c11-atomic.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at c11-atomic.c:4) - incompatible argument 1 (different modifiers)
+c11-atomic.c:33:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:33:13:    expected int *extern [assigned] puo
+c11-atomic.c:33:13:    got int const *
+c11-atomic.c:34:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:34:13:    expected int *extern [assigned] puo
+c11-atomic.c:34:13:    got int const *extern [assigned] pqo
+c11-atomic.c:48:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:48:13:    expected int *extern [assigned] puo
+c11-atomic.c:48:13:    got int [atomic] *
+c11-atomic.c:49:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:49:13:    expected int *extern [assigned] puo
+c11-atomic.c:49:13:    got int [atomic] *extern [assigned] pqo
+c11-atomic.c:63:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:63:13:    expected int *extern [assigned] puo
+c11-atomic.c:63:13:    got int [atomic] *
+c11-atomic.c:64:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:64:13:    expected int *extern [assigned] puo
+c11-atomic.c:64:13:    got int [atomic] *extern [assigned] pqo
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/c11-noreturn.c	Mon Nov 18 13:19:54 2019
+++ new/usr/src/tools/smatch/src/validation/c11-noreturn.c	Mon Nov 18 13:19:54 2019
@@ -5,5 +5,5 @@
  * check-command: test-parsing -std=c11 $file
  *
  * check-output-ignore
- * check-output-contains: \[noreturn\]
+ * check-output-contains: \\[noreturn\\]
  */
--- old/usr/src/tools/smatch/src/validation/c11-thread-local.c	Mon Nov 18 13:19:55 2019
+++ new/usr/src/tools/smatch/src/validation/c11-thread-local.c	Mon Nov 18 13:19:55 2019
@@ -5,5 +5,5 @@
  * check-command: test-parsing -std=c11 $file
  *
  * check-output-ignore
- * check-output-contains: \[tls\]
+ * check-output-contains: \\[tls\\]
  */
--- /dev/null	Mon Nov 18 13:19:55 2019
+++ new/usr/src/tools/smatch/src/validation/call-inlined.c	Mon Nov 18 13:19:55 2019
@@ -0,0 +1,55 @@
+static const char messg[] = "def";
+
+static inline int add(int a, int b)
+{
+	return a + b;
+}
+
+int  foo(int a, int b) { return add(a + b, 1); }
+void bar(int a, int b) {        add(a + b, 1); }
+
+
+static inline const char *lstrip(const char *str)
+{
+	return str + 1;
+}
+
+const char *bas(void) { return lstrip("abc"); }
+const char *qus(void) { return lstrip(messg); }
+
+/*
+ * check-name: call-inlined
+ * check-command: test-linearize -Wno-decl -m64 $file
+ * check-assert: sizeof(void*) == 8
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	add.32      %r3 <- %arg1, %arg2
+	add.32      %r5 <- %r3, $1
+	ret.32      %r5
+
+
+bar:
+.L3:
+	<entry-point>
+	ret
+
+
+bas:
+.L6:
+	<entry-point>
+	add.64      %r16 <- "abc", $1
+	ret.64      %r16
+
+
+qus:
+.L9:
+	<entry-point>
+	add.64      %r21 <- messg, $1
+	ret.64      %r21
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:19:55 2019
+++ new/usr/src/tools/smatch/src/validation/call-variadic.c	Mon Nov 18 13:19:55 2019
@@ -0,0 +1,23 @@
+#define NULL	((void*)0)
+
+extern int print(const char *msg, ...);
+
+int foo(const char *fmt, int a, long l, int *p)
+{
+	return print("msg %c: %d %d/%ld %ld/%p %p\n", 'x', a, __LINE__, l, 0L, p, NULL);
+}
+
+/*
+ * check-name: call-variadic
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	call.32     %r5 <- print, "msg %c: %d %d/%ld %ld/%p %p\n", $120, %arg2, $7, %arg3, $0, %arg4, $0
+	ret.32      %r5
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:19:55 2019
+++ new/usr/src/tools/smatch/src/validation/cast-bad-00.c	Mon Nov 18 13:19:55 2019
@@ -0,0 +1,47 @@
+typedef	unsigned short		u16;
+typedef	unsigned int		u32;
+
+union u {
+	u32	a;
+	u16	b;
+};
+
+struct s {
+	u32	a;
+	u16	b;
+};
+
+
+void bar(u16, u32);
+void union_to_int(u16 val);
+void struct_to_int(u16 val);
+
+
+void union_to_int(u16 val)
+{
+	union u u;
+
+	u.b = val;
+	bar(u.b, u);
+}
+
+void struct_to_int(u16 val)
+{
+	struct s s;
+
+	s.b = val;
+	bar(s.b, s);
+}
+
+/*
+ * check-name: cast-bad 00
+ *
+ * check-error-start
+cast-bad-00.c:25:18: warning: incorrect type in argument 2 (different base types)
+cast-bad-00.c:25:18:    expected unsigned int [usertype]
+cast-bad-00.c:25:18:    got union u [assigned] u
+cast-bad-00.c:33:18: warning: incorrect type in argument 2 (different base types)
+cast-bad-00.c:33:18:    expected unsigned int [usertype]
+cast-bad-00.c:33:18:    got struct s [assigned] s
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:55 2019
+++ new/usr/src/tools/smatch/src/validation/cast-bad-01.c	Mon Nov 18 13:19:56 2019
@@ -0,0 +1,13 @@
+extern unsigned long l;
+
+int foo(void) {
+	return (int) (typeof(fundecl(0))) l;
+}
+
+/*
+ * check-name: cast-bad 01
+ *
+ * check-error-start
+cast-bad-01.c:4:30: error: undefined identifier 'fundecl'
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:56 2019
+++ new/usr/src/tools/smatch/src/validation/cast-kinds-check.c	Mon Nov 18 13:19:56 2019
@@ -0,0 +1,20 @@
+#include "optim/cast-kinds.c"
+
+/*
+ * check-name: cast-kinds check
+ * check-command: sparse -m64 -v -Wno-pointer-to-int-cast $file
+ * check-assert: sizeof(long) == 8
+ *
+ * check-error-start
+optim/cast-kinds.c:5:45: warning: cast drops bits
+optim/cast-kinds.c:6:47: warning: cast drops bits
+optim/cast-kinds.c:7:46: warning: cast drops bits
+optim/cast-kinds.c:8:45: warning: cast drops bits
+optim/cast-kinds.c:12:48: warning: cast drops bits
+optim/cast-kinds.c:13:50: warning: cast drops bits
+optim/cast-kinds.c:14:49: warning: cast drops bits
+optim/cast-kinds.c:15:48: warning: cast drops bits
+optim/cast-kinds.c:37:48: warning: non size-preserving integer to pointer cast
+optim/cast-kinds.c:38:50: warning: non size-preserving integer to pointer cast
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:56 2019
+++ new/usr/src/tools/smatch/src/validation/cast-weirds.c	Mon Nov 18 13:19:56 2019
@@ -0,0 +1,19 @@
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+static int * int_2_iptr(int a) { return (int *)a; }
+static int * uint_2_iptr(uint a) { return (int *)a; }
+
+static void * int_2_vptr(int a) { return (void *)a; }
+static void * uint_2_vptr(uint a) { return (void *)a; }
+
+/*
+ * check-name: cast-weirds
+ * check-command: sparse -m64 $file
+ * check-assert: sizeof(void *) == 8
+ *
+ * check-error-start
+cast-weirds.c:4:48: warning: non size-preserving integer to pointer cast
+cast-weirds.c:5:50: warning: non size-preserving integer to pointer cast
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:56 2019
+++ new/usr/src/tools/smatch/src/validation/char-signed.c	Mon Nov 18 13:19:56 2019
@@ -0,0 +1,9 @@
+void foo(void)
+{
+	_Static_assert((char) -1 == -1, "plain char is not signed");
+}
+
+/*
+ * check-name: fsigned-char
+ * check-command: sparse -fsigned-char -Wno-decl $file
+ */
--- /dev/null	Mon Nov 18 13:19:56 2019
+++ new/usr/src/tools/smatch/src/validation/char-unsigned.c	Mon Nov 18 13:19:56 2019
@@ -0,0 +1,11 @@
+#define	MASK ((1 << __CHAR_BIT__) - 1)
+
+void foo(void)
+{
+	_Static_assert((char) -1 == (-1 & MASK), "plain char is not unsigned");
+}
+
+/*
+ * check-name: fsigned-char
+ * check-command: sparse -funsigned-char -Wno-decl $file
+ */
--- /dev/null	Mon Nov 18 13:19:56 2019
+++ new/usr/src/tools/smatch/src/validation/check_access-multi.c	Mon Nov 18 13:19:56 2019
@@ -0,0 +1,15 @@
+extern int *a;
+extern int b[1];
+
+static void foo(void)
+{
+	*a = b[1];
+}
+
+/*
+ * check-name: check_access-multi
+ *
+ * check-error-start
+check_access-multi.c:6:15: warning: invalid access past the end of 'b' (4 4)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:19:56 2019
+++ new/usr/src/tools/smatch/src/validation/check_access-store.c	Mon Nov 18 13:19:56 2019
@@ -0,0 +1,21 @@
+extern int a[1];
+
+static int r(void)
+{
+	return a[1];
+}
+
+static void w(void)
+{
+	a[1] = 2;
+}
+
+/*
+ * check-name: check_access-store
+ * check-known-to-fail
+ *
+ * check-error-start
+check_access-store.c:5:17: warning: invalid access past the end of 'a' (4 4)
+check_access-store.c:10:17: warning: invalid access past the end of 'a' (4 4)
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/check_byte_count-ice.c	Mon Nov 18 13:19:57 2019
+++ new/usr/src/tools/smatch/src/validation/check_byte_count-ice.c	Mon Nov 18 13:19:57 2019
@@ -8,12 +8,12 @@
  * check-name: Segfault in check_byte_count after syntax error
  *
  * check-error-start
-check_byte_count-ice.c:6:0: warning: Newline in string or character constant
+check_byte_count-ice.c:6:0: warning: missing terminating ' character
 check_byte_count-ice.c:5:23: warning: multi-character character constant
 check_byte_count-ice.c:6:1: error: Expected ) in function call
 check_byte_count-ice.c:6:1: error: got }
-builtin:0:0: error: Expected } at end of function
-builtin:0:0: error: got end-of-input
+check_byte_count-ice.c:20:0: error: Expected } at end of function
+check_byte_count-ice.c:20:0: error: got end-of-input
 check_byte_count-ice.c:5:15: error: not enough arguments for function memset
  * check-error-end
  */
--- old/usr/src/tools/smatch/src/validation/choose_expr.c	Mon Nov 18 13:19:57 2019
+++ new/usr/src/tools/smatch/src/validation/choose_expr.c	Mon Nov 18 13:19:57 2019
@@ -7,11 +7,11 @@
  * check-name: choose expr builtin
  * check-error-start
 choose_expr.c:1:51: warning: incorrect type in initializer (different base types)
-choose_expr.c:1:51:    expected int static [signed] [toplevel] x
-choose_expr.c:1:51:    got void <noident>
+choose_expr.c:1:51:    expected int static [toplevel] x
+choose_expr.c:1:51:    got void
 choose_expr.c:2:41: warning: incorrect type in initializer (different base types)
-choose_expr.c:2:41:    expected int static [signed] [toplevel] y
-choose_expr.c:2:41:    got char *<noident>
+choose_expr.c:2:41:    expected int static [toplevel] y
+choose_expr.c:2:41:    got char *
 choose_expr.c:4:17: warning: division by zero
  * check-error-end
  */
--- old/usr/src/tools/smatch/src/validation/compound-assign-type.c	Mon Nov 18 13:19:57 2019
+++ new/usr/src/tools/smatch/src/validation/compound-assign-type.c	Mon Nov 18 13:19:57 2019
@@ -7,9 +7,12 @@
 /*
  * check-name: compound-assign-type
  * check-command: test-linearize -m64 $file
+ * check-assert: sizeof(long) == 8
+ *
  * check-output-ignore
  *
  * check-output-excludes: divu\\.32
  * check-output-contains: divs\\.64
- * check-output-contains: scast\\.32
+ * check-output-contains: zext.64 .* (32) %arg1
+ * check-output-contains: trunc.32 .* (64)
  */
--- /dev/null	Mon Nov 18 13:19:58 2019
+++ new/usr/src/tools/smatch/src/validation/compound-sizes.c	Mon Nov 18 13:19:58 2019
@@ -0,0 +1,88 @@
+// This tests sparse "-vcompound" output.
+#define NULL ((void*)0)
+typedef unsigned int       uint32_t;
+typedef unsigned long long uint64_t;
+
+// Do not list functions.
+static int do_nothing(void)
+{}
+
+// no:
+static inline int zero(void)
+{
+	return 0 / 1;
+}
+
+// no:
+struct inventory {
+	unsigned char	description[64];
+	unsigned char	department[64];
+	uint32_t	dept_number;
+	uint32_t	item_cost;
+	uint64_t	stock_number;
+	uint32_t	tally[12];	// per month
+};
+
+// no
+static struct inventory *get_inv(uint64_t stocknum)
+{
+	return NULL;
+}
+
+// no
+union un {
+	struct inventory inv;
+	unsigned char	bytes[0];
+};
+
+// yes
+static union un un;
+
+// yes
+static struct inventory	inven[100];
+
+// no
+typedef struct inventory	inventory_t;
+
+// no
+static struct inventory	*invptr;
+
+// yes
+static inventory_t		invent[10];
+
+// no
+static float		floater;
+static double		double_float;
+
+// yes
+static float		floats[42];
+static double		doubles[84];
+
+// no
+int main(void)
+{
+	// no, these are not global.
+	struct inventory inv[10];
+	inventory_t	invt[10];
+	// what about statics?
+	static struct inventory invtop;
+	static inventory_t inv_top;
+	static uint64_t stocknums[100];
+
+	invptr = get_inv(42000);
+	return 0;
+}
+
+/*
+ * check-name: compound-sizes
+ * check-command: sparse -vcompound $file
+ * check-assert: _Alignof(long long) == 8
+ *
+ * check-error-start
+compound-sizes.c:39:17: union un static [toplevel] un: compound size 192, alignment 8
+compound-sizes.c:42:25: struct inventory static [toplevel] inven[100]: compound size 19200, alignment 8
+compound-sizes.c:51:33: struct inventory static [toplevel] [usertype] invent[10]: compound size 1920, alignment 8
+compound-sizes.c:58:25: float static [toplevel] floats[42]: compound size 168, alignment 4
+compound-sizes.c:59:25: double static [toplevel] doubles[84]: compound size 672, alignment 8
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/cond-address-array.c	Mon Nov 18 13:19:58 2019
+++ /dev/null	Mon Nov 18 13:19:58 2019
@@ -1,26 +0,0 @@
-int foo(void) {
-	extern int a[];
-
-	if (a)
-		return 1;
-	return 0;
-}
-
-int bar(void) {
-	int a[2];
-
-	if (a)
-		return 1;
-	return 0;
-}
-
-/*
- * check-name: cond-address-array.c
- * check-command: test-linearize -Wno-decl -Waddress $file
- * check-output-ignore
- *
- * check-error-start
-cond-address-array.c:4:13: warning: the address of an array will always evaluate as true
-cond-address-array.c:12:13: warning: the address of an array will always evaluate as true
- * check-error-end
- */
--- old/usr/src/tools/smatch/src/validation/cond-address-function.c	Mon Nov 18 13:19:58 2019
+++ /dev/null	Mon Nov 18 13:19:58 2019
@@ -1,18 +0,0 @@
-extern void func(void);
-
-int global_function(void)
-{
-	if (func)
-		return 1;
-	return 0;
-}
-
-/*
- * check-name: cond-address-function
- * check-command: test-linearize -Wno-decl -Waddress $file
- * check-output-ignore
- *
- * check-error-start
-cond-address-function.c:5:13: warning: the address of a function will always evaluate as true
- * check-error-end
- */
--- old/usr/src/tools/smatch/src/validation/cond-address.c	Mon Nov 18 13:19:58 2019
+++ new/usr/src/tools/smatch/src/validation/cond-address.c	Mon Nov 18 13:19:58 2019
@@ -10,5 +10,5 @@
  * check-command: test-linearize -Wno-decl $file
  * check-output-ignore
  *
- * check-excludes: VOID
+ * check-output-excludes: VOID
  */
--- old/usr/src/tools/smatch/src/validation/cond-err-expand.c	Mon Nov 18 13:19:59 2019
+++ new/usr/src/tools/smatch/src/validation/cond-err-expand.c	Mon Nov 18 13:19:59 2019
@@ -18,10 +18,14 @@
  * check-command: test-linearize -Wno-decl $file
  *
  * check-error-start
-cond-err-expand.c:8:11: error: incompatible types in conditional expression (different base types)
-cond-err-expand.c:13:11: error: incompatible types in conditional expression (different base types)
+cond-err-expand.c:8:11: error: incompatible types in conditional expression (different base types):
+cond-err-expand.c:8:11:    int
+cond-err-expand.c:8:11:    void
+cond-err-expand.c:13:11: error: incompatible types in conditional expression (different base types):
+cond-err-expand.c:13:11:    void
+cond-err-expand.c:13:11:    int
  * check-error-end
  *
  * check-output-ignore
- * check-excludes: call.* __builtin_constant_p
+ * check-output-excludes: call.* __builtin_constant_p
  */
--- old/usr/src/tools/smatch/src/validation/conditional-type.c	Mon Nov 18 13:19:59 2019
+++ new/usr/src/tools/smatch/src/validation/conditional-type.c	Mon Nov 18 13:19:59 2019
@@ -79,21 +79,21 @@
  * check-name: conditional-type
  *
  * check-error-start
-conditional-type.c:18:18: error: incorrect type in conditional
+conditional-type.c:18:18: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:18:18:    got void
-conditional-type.c:19:13: error: incorrect type in conditional
+conditional-type.c:19:13: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:19:13:    got struct state s
-conditional-type.c:24:18: error: incorrect type in conditional
+conditional-type.c:24:18: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:24:18:    got void
-conditional-type.c:29:21: error: incorrect type in conditional
+conditional-type.c:29:21: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:29:21:    got void
-conditional-type.c:30:16: error: incorrect type in conditional
+conditional-type.c:30:16: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:30:16:    got struct state s
-conditional-type.c:34:21: error: incorrect type in conditional
+conditional-type.c:34:21: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:34:21:    got void
-conditional-type.c:36:20: error: incorrect type in conditional
+conditional-type.c:36:20: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:36:20:    got void
-conditional-type.c:40:21: error: incorrect type in conditional
+conditional-type.c:40:21: error: incorrect type in conditional (non-scalar type)
 conditional-type.c:40:21:    got void
  * check-error-end
  */
--- old/usr/src/tools/smatch/src/validation/constant-suffix-64.c	Mon Nov 18 13:19:59 2019
+++ new/usr/src/tools/smatch/src/validation/constant-suffix-64.c	Mon Nov 18 13:19:59 2019
@@ -7,6 +7,7 @@
 /*
  * check-name: constant-suffix
  * check-command: sparse -m64 -Wconstant-suffix $file
+ * check-assert: sizeof(long) == 8
  *
  * check-error-start
 constant-suffix-64.c:4:26: warning: constant 0xfffff00000000000U is so big it is unsigned long
--- old/usr/src/tools/smatch/src/validation/constexpr-addr-of-static-member.c	Mon Nov 18 13:20:00 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-addr-of-static-member.c	Mon Nov 18 13:20:00 2019
@@ -18,7 +18,7 @@
 static int *g = &(&a.d)->b[1];	// OK
 
 /*
- * check-name: address of static object's member constness verification.
+ * check-name: constexpr static object's member address
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-addr-of-static.c	Mon Nov 18 13:20:00 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-addr-of-static.c	Mon Nov 18 13:20:00 2019
@@ -25,7 +25,7 @@
 }
 
 /*
- * check-name: address of static object constness verification.
+ * check-name: constexpr static object address
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-binop.c	Mon Nov 18 13:20:00 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-binop.c	Mon Nov 18 13:20:00 2019
@@ -19,7 +19,7 @@
 };
 
 /*
- * check-name: Expression constness propagation in binops and alike
+ * check-name: constexprness in binops and alike
  *
  * check-error-start
 constexpr-binop.c:3:12: error: bad constant expression
--- old/usr/src/tools/smatch/src/validation/constexpr-cast.c	Mon Nov 18 13:20:01 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-cast.c	Mon Nov 18 13:20:01 2019
@@ -14,7 +14,7 @@
 
 };
 /*
- * check-name: Expression constness propagation in casts
+ * check-name: constexprness in casts
  *
  * check-error-start
 constexpr-cast.c:9:11: error: bad integer constant expression
--- old/usr/src/tools/smatch/src/validation/constexpr-compound-literal.c	Mon Nov 18 13:20:01 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-compound-literal.c	Mon Nov 18 13:20:01 2019
@@ -9,7 +9,7 @@
 }
 
 /*
- * check-name: compound literal address constness verification
+ * check-name: constexpr compound literal address
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-conditional.c	Mon Nov 18 13:20:01 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-conditional.c	Mon Nov 18 13:20:01 2019
@@ -21,7 +21,7 @@
 };
 
 /*
- * check-name: Expression constness propagation in conditional expressions
+ * check-name: constexprness in conditionals
  *
  * check-error-start
 constexpr-conditional.c:12:13: error: bad constant expression
--- old/usr/src/tools/smatch/src/validation/constexpr-init.c	Mon Nov 18 13:20:02 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-init.c	Mon Nov 18 13:20:02 2019
@@ -39,7 +39,7 @@
 }
 
 /*
- * check-name: static storage object initializer constness verification.
+ * check-name: constexprness static storage object initializer
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-labelref.c	Mon Nov 18 13:20:02 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-labelref.c	Mon Nov 18 13:20:02 2019
@@ -6,7 +6,7 @@
 }
 
 /*
- * check-name: label reference constness verification.
+ * check-name: constexprness label reference
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-offsetof.c	Mon Nov 18 13:20:02 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-offsetof.c	Mon Nov 18 13:20:02 2019
@@ -13,7 +13,7 @@
 };
 
 /*
- * check-name: __builtin_offsetof() constness verification.
+ * check-name: constexprness __builtin_offsetof()
  *
  * check-error-start
 constexpr-offsetof.c:12:39: error: bad constant expression
--- old/usr/src/tools/smatch/src/validation/constexpr-pointer-arith.c	Mon Nov 18 13:20:03 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-pointer-arith.c	Mon Nov 18 13:20:03 2019
@@ -17,7 +17,7 @@
 static int *p = &*(d + 1);				// KO
 
 /*
- * check-name: pointer arithmetic constness verification.
+ * check-name: consrexprness pointer arithmetic
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-pointer-cast.c	Mon Nov 18 13:20:03 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-pointer-cast.c	Mon Nov 18 13:20:03 2019
@@ -4,7 +4,7 @@
 
 
 /*
- * check-name: integer literal cast to pointer type constness verification.
+ * check-name: constexprness integer literal cast to pointer type
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-preop.c	Mon Nov 18 13:20:03 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-preop.c	Mon Nov 18 13:20:03 2019
@@ -16,7 +16,7 @@
 };
 
 /*
- * check-name: Expression constness propagation in preops
+ * check-name: constexprness in preops
  *
  * check-error-start
 constexpr-preop.c:4:5: error: bad constant expression
@@ -25,5 +25,7 @@
 constexpr-preop.c:9:4: error: bad constant expression
 constexpr-preop.c:14:4: error: bad integer constant expression
 constexpr-preop.c:15:4: error: bad integer constant expression
+constexpr-preop.c:10:4: error: index out of bounds in initializer
+constexpr-preop.c:11:4: error: index out of bounds in initializer
  * check-error-end
  */
--- /dev/null	Mon Nov 18 13:20:04 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-shift.c	Mon Nov 18 13:20:04 2019
@@ -0,0 +1,12 @@
+#define __is_constexpr(x) \
+        (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
+
+static void test(int x) {
+	static int b[] = {
+		[__builtin_choose_expr(__is_constexpr(1 << 1), 1, x)] = 0,
+	};
+}
+
+/*
+ * check-name: constexpr-shift
+ */
--- old/usr/src/tools/smatch/src/validation/constexpr-string.c	Mon Nov 18 13:20:04 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-string.c	Mon Nov 18 13:20:04 2019
@@ -1,7 +1,7 @@
 static char *a = "foobar";	// OK
 
 /*
- * check-name: string literal constness verification.
+ * check-name: constness of string literal
  * check-command: sparse -Wconstexpr-not-const $file
  *
  * check-error-start
--- old/usr/src/tools/smatch/src/validation/constexpr-types-compatible-p.c	Mon Nov 18 13:20:04 2019
+++ new/usr/src/tools/smatch/src/validation/constexpr-types-compatible-p.c	Mon Nov 18 13:20:04 2019
@@ -1,7 +1,7 @@
 static int a[] = {[__builtin_types_compatible_p(int, int)] = 0};
 
 /*
- * check-name: __builtin_types_compatible_p() constness verification.
+ * check-name: constness of __builtin_types_compatible_p()
  *
  * check-error-start
  * check-error-end
--- /dev/null	Mon Nov 18 13:20:05 2019
+++ new/usr/src/tools/smatch/src/validation/context-stmt.c	Mon Nov 18 13:20:05 2019
@@ -0,0 +1,62 @@
+static void foo(int x)
+{
+	__context__(0);		// OK
+	__context__(x, 0);	// OK
+	__context__ (x, 1);	// OK
+
+	__context__(x);		// KO: no const expr
+	__context__(1,x);	// KO: no const expr
+
+	__context__;		// KO: no expression at all
+	__context__(;		// KO: no expression at all
+
+	__context__ 0;		// KO: need parens
+	__context__ x, 0;	// KO: need parens
+	__context__(x, 0;	// KO: unmatched parens
+	__context__ x, 0);	// KO: unmatched parens
+	__context__(0;		// KO: unmatched parens
+	__context__ 0);		// KO: unmatched parens
+
+	__context__();		// KO: no expression at all
+	__context__(,0);	// KO: no expression at all
+	__context__(x,);	// KO: no expression at all
+	__context__(,);		// KO: no expression at all
+}
+
+/*
+ * check-name: context-stmt
+ * check-command: sparse -Wno-context $file
+ *
+ * check-error-start
+context-stmt.c:10:20: error: Expected ( after __context__ statement
+context-stmt.c:10:20: error: got ;
+context-stmt.c:11:21: error: expression expected after '('
+context-stmt.c:11:21: error: got ;
+context-stmt.c:11:21: error: Expected ) at end of __context__ statement
+context-stmt.c:11:21: error: got ;
+context-stmt.c:13:21: error: Expected ( after __context__ statement
+context-stmt.c:13:21: error: got 0
+context-stmt.c:14:21: error: Expected ( after __context__ statement
+context-stmt.c:14:21: error: got x
+context-stmt.c:15:25: error: Expected ) at end of __context__ statement
+context-stmt.c:15:25: error: got ;
+context-stmt.c:16:21: error: Expected ( after __context__ statement
+context-stmt.c:16:21: error: got x
+context-stmt.c:17:22: error: Expected ) at end of __context__ statement
+context-stmt.c:17:22: error: got ;
+context-stmt.c:18:21: error: Expected ( after __context__ statement
+context-stmt.c:18:21: error: got 0
+context-stmt.c:20:21: error: expression expected after '('
+context-stmt.c:20:21: error: got )
+context-stmt.c:21:21: error: expression expected after '('
+context-stmt.c:21:21: error: got ,
+context-stmt.c:22:23: error: expression expected after ','
+context-stmt.c:22:23: error: got )
+context-stmt.c:23:21: error: expression expected after '('
+context-stmt.c:23:21: error: got ,
+context-stmt.c:23:22: error: expression expected after ','
+context-stmt.c:23:22: error: got )
+context-stmt.c:7:21: error: bad constant expression
+context-stmt.c:8:23: error: bad constant expression
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:05 2019
+++ new/usr/src/tools/smatch/src/validation/crash-select.c	Mon Nov 18 13:20:05 2019
@@ -0,0 +1,18 @@
+struct s {
+	void *b;
+	long c;
+};
+
+long d(void);
+static long f(void)
+{
+	struct s s;
+	s.c = d();
+	if (s.c)
+		s.c = 2;
+	return s.c;
+}
+
+/*
+ * check-name: crash-select
+ */
--- /dev/null	Mon Nov 18 13:20:05 2019
+++ new/usr/src/tools/smatch/src/validation/doc/cdoc.cdoc	Mon Nov 18 13:20:05 2019
@@ -0,0 +1,177 @@
+///
+// Title
+// -----
+
+///
+// short description
+int a(int param, int arg);
+
+///
+// short description
+// longer description
+int b(int param, int arg);
+
+///
+// short description
+//
+// longer description with empty line
+int c(int param, int arg);
+
+///
+// short description
+// longer description
+// which needs two lines
+int d(int param, int arg);
+
+///
+// short description
+//
+// longer description with empty line
+// which needs two lines
+int e(int param, int arg);
+
+///
+// condensed format
+// @param: desc param
+// @arg: desc arg
+// @return: desc return
+// longer description
+int f(int param, int arg);
+
+///
+// more airy format
+//
+// @param: desc param
+// @arg: desc arg
+// @return: desc return
+//
+// longer description
+int g(int param, int arg);
+
+///
+// short description
+// @return: ``1`` if @param is zero,
+//	``0`` otherwise.
+int h(int param, int arg);
+
+///
+// short description
+// @return:
+//	* ``1`` if @param is zero,
+//	* ``0`` otherwise.
+int i(int param, int arg);
+
+///
+// short description
+int m(int param, int arg)
+{ return 0; }
+
+///
+// short description
+int n(int param,
+	int arg)
+{ return 0; }
+
+///
+// short description
+int o(int param, int arg);
+
+///
+// short description
+int p(int param,
+	int arg);
+
+
+/*
+ * check-name: cdoc
+ * check-command: Documentation/sphinx/cdoc.py < $file
+ *
+ * check-output-start
+   2: Title
+   3: -----
+   4: 
+   4: 
+   5: 
+   7: .. c:function:: int a(int param, int arg)
+   8: 
+   6: 	Short description.
+   7: 
+  12: .. c:function:: int b(int param, int arg)
+  13: 
+  10: 	Short description.
+  11: 
+  11: 	longer description
+  12: 
+  18: .. c:function:: int c(int param, int arg)
+  19: 
+  15: 	Short description.
+  16: 
+  17: 	longer description with empty line
+  18: 
+  24: .. c:function:: int d(int param, int arg)
+  25: 
+  21: 	Short description.
+  22: 
+  22: 	longer description
+  23: 	which needs two lines
+  24: 
+  31: .. c:function:: int e(int param, int arg)
+  32: 
+  27: 	Short description.
+  28: 
+  29: 	longer description with empty line
+  30: 	which needs two lines
+  31: 
+  39: .. c:function:: int f(int param, int arg)
+  40: 
+  34: 	Condensed format.
+  35: 
+  35: 	:param param: desc param
+  36: 	:param arg: desc arg
+  37: 	:return: desc return
+  38: 
+  38: 	longer description
+  39: 
+  49: .. c:function:: int g(int param, int arg)
+  50: 
+  42: 	More airy format.
+  43: 
+  44: 	:param param: desc param
+  45: 	:param arg: desc arg
+  46: 	:return: desc return
+  47: 
+  48: 	longer description
+  49: 
+  55: .. c:function:: int h(int param, int arg)
+  56: 
+  52: 	Short description.
+  53: 
+  53: 	:return: ``1`` if **param** is zero,
+  54: 		``0`` otherwise.
+  54: 
+  62: .. c:function:: int i(int param, int arg)
+  63: 
+  58: 	Short description.
+  59: 
+  59: 	:return: 
+  60: 		* ``1`` if **param** is zero,
+  61: 		* ``0`` otherwise.
+  60: 
+  66: .. c:function:: int m(int param, int arg)
+  67: 
+  65: 	Short description.
+  66: 
+  71: .. c:function:: int n(int param, int arg)
+  72: 
+  70: 	Short description.
+  71: 
+  77: .. c:function:: int o(int param, int arg)
+  78: 
+  76: 	Short description.
+  77: 
+  81: .. c:function:: int p(int param, int arg)
+  82: 
+  80: 	Short description.
+  81: 
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:05 2019
+++ new/usr/src/tools/smatch/src/validation/empty-expr.c	Mon Nov 18 13:20:05 2019
@@ -0,0 +1,26 @@
+static int foo(void)
+{
+	switch () {
+	case 0:
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+static int bar(void)
+{
+	if ()
+		return 0;
+	else
+		return 1;
+}
+
+/*
+ * check-name: empty expression
+ *
+ * check-error-start
+empty-expr.c:3:17: error: an expression is expected before ')'
+empty-expr.c:13:13: error: an expression is expected before ')'
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:05 2019
+++ new/usr/src/tools/smatch/src/validation/enum+mode.c	Mon Nov 18 13:20:05 2019
@@ -0,0 +1,18 @@
+enum e { ZERO, ONE, TWO };
+
+struct s {
+	enum e __attribute__ ((mode(__byte__))) b;
+	enum e __attribute__ ((mode(__word__))) w;
+	enum e __attribute__ ((mode(__TI__))) t;
+};
+
+static struct s s;
+
+_Static_assert(sizeof(s.b) == 1, "");
+_Static_assert(sizeof(s.w) == sizeof(long), "");
+_Static_assert(sizeof(s.t) == sizeof(long long), "");
+
+/*
+ * check-name: enum+mode
+ * check-known-to-fail
+ */
--- /dev/null	Mon Nov 18 13:20:05 2019
+++ new/usr/src/tools/smatch/src/validation/enum-base-type.c	Mon Nov 18 13:20:05 2019
@@ -0,0 +1,29 @@
+enum n {
+	NA,
+	NB = 1L,
+	NC = 1UL,
+	ND = 1LL,
+	NE = 1ULL,
+	NF = -1,
+	NG = -1L,
+	NH = -1LL,
+};
+_Static_assert(sizeof(enum n) == sizeof(int), "+-1");
+
+enum m {
+	MA = 0L,
+	MB = 1L,
+	MG = -1L,
+};
+_Static_assert(sizeof(enum m) == sizeof(int), "+-1L");
+
+enum p {
+	PA = 0UL,
+	PB = 1UL,
+};
+_Static_assert(sizeof(enum p) == sizeof(int), "UL");
+
+/*
+ * check-name: enum-base-type
+ * check-command: sparse -m64 $file
+ */
--- /dev/null	Mon Nov 18 13:20:05 2019
+++ new/usr/src/tools/smatch/src/validation/enum-bitwise-bad.c	Mon Nov 18 13:20:05 2019
@@ -0,0 +1,20 @@
+#define __bitwise __attribute__((bitwise))
+#define __force   __attribute__((force))
+
+typedef int __bitwise apple_t;
+typedef int __bitwise orange_t;
+
+enum fruit {
+	A = (__force  apple_t) 0,
+	B = (__force orange_t) 1,
+};
+
+/*
+ * check-name: enum-bitwise-bad
+ *
+ * check-error-start
+enum-bitwise-bad.c:9:14: error: incompatible restricted type
+enum-bitwise-bad.c:9:14:    expected: restricted apple_t
+enum-bitwise-bad.c:9:14:         got: restricted orange_t
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:06 2019
+++ new/usr/src/tools/smatch/src/validation/enum-bitwise-mixed.c	Mon Nov 18 13:20:06 2019
@@ -0,0 +1,29 @@
+#define __bitwise __attribute__((bitwise))
+#define __force   __attribute__((force))
+
+typedef long long __bitwise bits;
+
+enum a {
+	AR = (__force bits) 0,
+	AP = 0,
+	AS = (__force bits) 1,
+	AQ = 1,
+};
+_Static_assert(sizeof(AP) == sizeof(int), "is bad?");
+
+enum b {
+	BP = 0,
+	BR = (__force bits) 0,
+	BQ = 1,
+	BS = (__force bits) 1,
+};
+_Static_assert(sizeof(BP) == sizeof(int), "is bad?");
+
+/*
+ * check-name: enum-bitwise-mixed
+ *
+ * check-error-start
+enum-bitwise-mixed.c:8:14: warning: mixed bitwiseness
+enum-bitwise-mixed.c:16:15: warning: mixed bitwiseness
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:06 2019
+++ new/usr/src/tools/smatch/src/validation/enum-bitwise.c	Mon Nov 18 13:20:06 2019
@@ -0,0 +1,19 @@
+#define __bitwise __attribute__((bitwise))
+#define __force   __attribute__((force))
+
+typedef long long __bitwise bits;
+
+enum r {
+	RZ = (__force bits) 0,
+	RO = (__force bits) 1,
+	RM = (__force bits) -1,
+};
+
+_Static_assert([typeof(RZ)] == [bits], "RZ");
+_Static_assert([typeof(RO)] == [bits], "RO");
+_Static_assert([typeof(RM)] == [bits], "RM");
+_Static_assert(sizeof(enum r) == sizeof(bits), "bits");
+
+/*
+ * check-name: enum-bitwise
+ */
--- /dev/null	Mon Nov 18 13:20:06 2019
+++ new/usr/src/tools/smatch/src/validation/enum-bounds.c	Mon Nov 18 13:20:06 2019
@@ -0,0 +1,25 @@
+enum bound_int_max {
+	IMAX = __INT_MAX__,
+};
+_Static_assert([typeof(IMAX)] == [int], "");
+
+enum bound_int_maxp1 {
+	IMP1 = __INT_MAX__ + 1L,
+};
+_Static_assert([typeof(IMP1)] == [unsigned int], "");
+
+enum bound_int_maxm1 {
+	IMM1 = -__INT_MAX__ - 1L,
+};
+_Static_assert([typeof(IMM1)] == [int], "");
+
+enum bound_int_maxm2 {
+	IMM2 = -__INT_MAX__ - 2L,
+};
+_Static_assert([typeof(IMM2)] == [long], "");
+
+/*
+ * check-name: enum-bounds
+ * check-command: sparse -m64 $file
+ * check-assert: sizeof(long) == 8
+ */
--- /dev/null	Mon Nov 18 13:20:06 2019
+++ new/usr/src/tools/smatch/src/validation/enum-init-constness.c	Mon Nov 18 13:20:06 2019
@@ -0,0 +1,9 @@
+extern int invalid;
+
+enum e {
+	E = 1 ? 1 : invalid
+};
+
+/*
+ * check-name: enum-init-constness
+ */
--- /dev/null	Mon Nov 18 13:20:06 2019
+++ new/usr/src/tools/smatch/src/validation/enum-invalid.c	Mon Nov 18 13:20:06 2019
@@ -0,0 +1,11 @@
+enum e { };
+enum f { F = 0.1 };
+
+/*
+ * check-name: enum-invalid
+ *
+ * check-error-start
+enum-invalid.c:1:10: error: empty enum definition
+enum-invalid.c:2:14: error: bad constant expression
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:06 2019
+++ new/usr/src/tools/smatch/src/validation/enum-min-size.c	Mon Nov 18 13:20:06 2019
@@ -0,0 +1,29 @@
+enum i { I = 1 };
+_Static_assert(sizeof(enum i) == sizeof(int), "int");
+enum u { U = 1U };
+_Static_assert(sizeof(enum u) == sizeof(int), "uint");
+
+enum l { L = 1L };
+_Static_assert(sizeof(enum l) == sizeof(int), "long");
+enum m { M = 1UL };
+_Static_assert(sizeof(enum m) == sizeof(int), "ulong");
+
+enum n { N = 1LL };
+_Static_assert(sizeof(enum n) == sizeof(int), "llong");
+enum o { O = 1ULL };
+_Static_assert(sizeof(enum o) == sizeof(int), "ullong");
+
+
+enum mi { MI = -1 };
+_Static_assert(sizeof(enum i) == sizeof(int), "int");
+
+enum ml { ML = -1L };
+_Static_assert(sizeof(enum l) == sizeof(int), "long");
+
+enum mn { MN = -1LL };
+_Static_assert(sizeof(enum n) == sizeof(int), "llong");
+
+
+/*
+ * check-name: enum-min-size
+ */
--- old/usr/src/tools/smatch/src/validation/enum-mismatch.c	Mon Nov 18 13:20:06 2019
+++ new/usr/src/tools/smatch/src/validation/enum-mismatch.c	Mon Nov 18 13:20:06 2019
@@ -13,7 +13,7 @@
  *
  * check-error-start
 enum-mismatch.c:7:16: warning: mixing different enum types
-enum-mismatch.c:7:16:     int enum ea  versus
-enum-mismatch.c:7:16:     int enum eb 
+enum-mismatch.c:7:16:     unsigned int enum ea versus
+enum-mismatch.c:7:16:     unsigned int enum eb
  * check-error-end
  */
--- /dev/null	Mon Nov 18 13:20:07 2019
+++ new/usr/src/tools/smatch/src/validation/enum-same-type.c	Mon Nov 18 13:20:07 2019
@@ -0,0 +1,14 @@
+enum num {
+	NEG = -1,
+	NIL = 0,
+	ONE = 1U,
+	DUO = 2LL,
+};
+
+_Static_assert([typeof(NIL)] == [typeof(NEG)], "enum same type");
+_Static_assert([typeof(ONE)] == [typeof(NEG)], "enum same type");
+_Static_assert([typeof(DUO)] == [typeof(NEG)], "enum same type");
+
+/*
+ * check-name: enum-same-type
+ */
--- /dev/null	Mon Nov 18 13:20:07 2019
+++ new/usr/src/tools/smatch/src/validation/enum-sign-gcc.c	Mon Nov 18 13:20:07 2019
@@ -0,0 +1,64 @@
+// For enum's underlying/compatible type:
+//  std C:	unspecified
+//  GCC:	'unsigned int' if no negative values,
+//		otherwise 'int' (see GCC manul 4.9).
+//		But also accept ulong, long
+// For the type of the enumerators:
+// std C:	'int'
+// GCC:		'int' if the value fit in a 'int'
+//		otherwise same as the enum underlying type?
+//
+// The following tests match GCC's choices
+
+#define is_unsigned(X) ((typeof(X))-1 > 0)
+
+enum u {
+	U = 1U,			// fit in 'int'
+	// no negatives
+};
+_Static_assert(sizeof(enum u) == sizeof(int), "size");
+_Static_assert(is_unsigned(enum u), "enum u");
+_Static_assert(is_unsigned(U) == 0, "value U");		// fail
+
+enum v {
+	V = __INT_MAX__ + 1U,	// doesn't fit in 'int'
+	// no negatives
+};
+_Static_assert(sizeof(enum v) == sizeof(int), "size");
+_Static_assert(is_unsigned(enum v), "enum v");
+_Static_assert(is_unsigned(V) == 1, "value V");
+
+enum w {
+	W = __LONG_MAX__ + 1UL,	// doesn't fit in 'long'
+};
+_Static_assert(sizeof(enum w) == sizeof(long), "size");
+_Static_assert(is_unsigned(enum w), "enum w");
+_Static_assert(is_unsigned(W) == 1, "value W");
+
+enum x {
+	A = 1,			// fit in 'int'
+	B = 0x100000000UL,	// doesn't fit in int
+};
+_Static_assert(sizeof(enum x) == sizeof(long), "size");
+_Static_assert(is_unsigned(enum x), "enum x");
+_Static_assert(sizeof(A) == sizeof(int), "size A");	// fail
+_Static_assert(is_unsigned(A) == 0, "enum A");		// fail
+_Static_assert(sizeof(B) == sizeof(long), "size B");
+_Static_assert(is_unsigned(B) == 1, "enum B");
+
+enum y {
+	C = 1,			// fit in 'int'
+	D = 0x100000000L,	// doesn't fit in int
+};
+_Static_assert(sizeof(enum y) == sizeof(long), "size");
+_Static_assert(is_unsigned(enum y), "enum y");
+_Static_assert(sizeof(C) == sizeof(int), "size C");	// fail
+_Static_assert(is_unsigned(C) == 0, "enum C");		// fail
+_Static_assert(sizeof(D) == sizeof(long), "size D");
+_Static_assert(is_unsigned(D) == 1, "enum D");
+
+/*
+ * check-name: enum-sign-gcc
+ * check-command: sparse -m64 $file
+ * check-assert: sizeof(long) == 8
+ */
--- /dev/null	Mon Nov 18 13:20:07 2019
+++ new/usr/src/tools/smatch/src/validation/enum-typecheck.c	Mon Nov 18 13:20:07 2019
@@ -0,0 +1,39 @@
+enum good { G, };
+enum bad  { B, };
+enum good g;
+
+enum good compat_int(void) { return 1; }
+
+void parg(enum good);
+void parg(enum bad);
+
+void farg(enum good a);
+void farg(enum bad  a) { }
+
+enum good pret(void);
+enum bad  pret(void);
+
+enum good fret(void);
+enum bad  fret(void) { return 0; }
+
+
+enum good *ptr;
+enum bad  *ptr;
+
+enum good *gptr = &g;
+enum bad  *bptr = &g;
+
+/*
+ * check-name: enum-typecheck
+ * check-command: sparse -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-error-start
+enum-typecheck.c:8:6: error: symbol 'parg' redeclared with different type
+enum-typecheck.c:11:6: error: symbol 'farg' redeclared with different type
+enum-typecheck.c:14:11: error: symbol 'pret' redeclared with different type
+enum-typecheck.c:17:11: error: symbol 'fret' redeclared with different type
+enum-typecheck.c:21:12: error: symbol 'ptr' redeclared with different type
+enum-typecheck.c:24:20: warning: incorrect type in initializer (different type sizes)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:07 2019
+++ new/usr/src/tools/smatch/src/validation/error-at-eof.c	Mon Nov 18 13:20:07 2019
@@ -0,0 +1,10 @@
+/*
+ * check-name: error-at-eof
+ *
+ * check-error-start
+error-at-eof.c:11:0: error: Expected ; at end of declaration
+error-at-eof.c:11:0: error: got end-of-input
+ * check-error-end
+ */
+
+int a
--- /dev/null	Mon Nov 18 13:20:07 2019
+++ new/usr/src/tools/smatch/src/validation/eval-typeof-vla.c	Mon Nov 18 13:20:07 2019
@@ -0,0 +1,26 @@
+extern int a[1];
+
+static int foo(int n)
+{
+	int i = 0;
+	int (*p)[1] = (typeof(++i, (int (*)[n])a)) &a;
+
+	(void) p;
+
+	return i;
+}
+
+/*
+ * check-name: eval-typeof-vla
+ * check-command: test-linearize -Wno-vla $file
+ * check-known-to-fail
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	ret.32      $1
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:07 2019
+++ new/usr/src/tools/smatch/src/validation/expand/bad-shift.c	Mon Nov 18 13:20:07 2019
@@ -0,0 +1,64 @@
+#define MAX	(sizeof(int) * __CHAR_BIT__)
+
+static int lmax(int a)
+{
+	return 1 << MAX;
+}
+
+static int lneg(int a)
+{
+	return 1 << -1;
+}
+
+static int rmax(int a)
+{
+	return 1 >> MAX;
+}
+
+static int rneg(int a)
+{
+	return 1 >> -1;
+}
+
+/*
+ * check-name: bad-shift
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+lmax:
+.L0:
+	<entry-point>
+	shl.32      %r1 <- $1, $32
+	ret.32      %r1
+
+
+lneg:
+.L2:
+	<entry-point>
+	shl.32      %r3 <- $1, $0xffffffff
+	ret.32      %r3
+
+
+rmax:
+.L4:
+	<entry-point>
+	asr.32      %r5 <- $1, $32
+	ret.32      %r5
+
+
+rneg:
+.L6:
+	<entry-point>
+	asr.32      %r7 <- $1, $0xffffffff
+	ret.32      %r7
+
+
+ * check-output-end
+ *
+ * check-error-start
+expand/bad-shift.c:5:18: warning: shift too big (32) for type int
+expand/bad-shift.c:10:18: warning: shift count is negative (-1)
+expand/bad-shift.c:15:18: warning: shift too big (32) for type int
+expand/bad-shift.c:20:18: warning: shift count is negative (-1)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:07 2019
+++ new/usr/src/tools/smatch/src/validation/expand/builtin-expect.c	Mon Nov 18 13:20:07 2019
@@ -0,0 +1,100 @@
+int flia(long a)
+{
+	return __builtin_expect(a, 1);
+}
+
+int flic(void)
+{
+	return __builtin_expect(1L << 32 | 1, 1);
+}
+
+long fila(int a)
+{
+	return __builtin_expect(a, 1);
+}
+
+long filc(void)
+{
+	return __builtin_expect(1L << 32 | 1, 1);
+}
+
+long filu(void)
+{
+	return __builtin_expect(0x80000000U, 1);
+}
+
+long fils(void)
+{
+	return __builtin_expect((int)0x80000000, 1);
+}
+
+void *fptr(void *a)
+{
+	return __builtin_expect(a, a);
+}
+
+/*
+ * check-name: builtin-expect
+ * check-command: test-linearize -m64 -Wno-decl $file
+ * check-assert: sizeof(long) == 8
+ *
+ * check-output-start
+flia:
+.L0:
+	<entry-point>
+	trunc.32    %r2 <- (64) %arg1
+	ret.32      %r2
+
+
+flic:
+.L2:
+	<entry-point>
+	ret.32      $1
+
+
+fila:
+.L4:
+	<entry-point>
+	sext.64     %r6 <- (32) %arg1
+	ret.64      %r6
+
+
+filc:
+.L6:
+	<entry-point>
+	ret.64      $0x100000001
+
+
+filu:
+.L8:
+	<entry-point>
+	ret.64      $0x80000000
+
+
+fils:
+.L10:
+	<entry-point>
+	ret.64      $0xffffffff80000000
+
+
+fptr:
+.L12:
+	<entry-point>
+	ret.64      %arg1
+
+
+ * check-output-end
+ *
+ * check-error-start
+expand/builtin-expect.c:33:33: warning: incorrect type in argument 1 (different base types)
+expand/builtin-expect.c:33:33:    expected long
+expand/builtin-expect.c:33:33:    got void *a
+expand/builtin-expect.c:33:36: warning: incorrect type in argument 2 (different base types)
+expand/builtin-expect.c:33:36:    expected long
+expand/builtin-expect.c:33:36:    got void *a
+expand/builtin-expect.c:33:32: warning: incorrect type in return expression (different base types)
+expand/builtin-expect.c:33:32:    expected void *
+expand/builtin-expect.c:33:32:    got long
+expand/builtin-expect.c:8:42: warning: cast truncates bits from constant value (100000001 becomes 1)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:08 2019
+++ new/usr/src/tools/smatch/src/validation/expand/builtin_fpclassify.c	Mon Nov 18 13:20:08 2019
@@ -0,0 +1,26 @@
+enum { FP_NAN, FP_INF, FP_NOR, FP_SUB, FP_ZERO };
+
+#define	classify(X) __builtin_fpclassify(FP_NAN,FP_INF,FP_NOR,FP_SUB,FP_ZERO,X)
+
+int test(void)
+{
+	if (classify(__builtin_nan("0")) != FP_NAN)
+		return 0;
+	if (classify(__builtin_inf("0")) != FP_INF)
+		return 0;
+	if (classify(1.0) != FP_NOR)
+		return 0;
+	if (classify(0.0) != FP_ZERO)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * check-name: builtin_fpclassify
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:08 2019
+++ new/usr/src/tools/smatch/src/validation/expand/builtin_huge_val.c	Mon Nov 18 13:20:08 2019
@@ -0,0 +1,39 @@
+static float huge_valf(void)
+{
+	return __builtin_huge_valf();
+}
+
+static double huge_val(void)
+{
+	return __builtin_huge_val();
+}
+
+static long double huge_vall(void)
+{
+	return __builtin_huge_vall();
+}
+
+
+static float inff(void)
+{
+	return __builtin_inff();
+}
+
+static double inf(void)
+{
+	return __builtin_inf();
+}
+
+static long double infl(void)
+{
+	return __builtin_infl();
+}
+
+/*
+ * check-name: builtin_huge_val expand
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: call
+ */
--- /dev/null	Mon Nov 18 13:20:08 2019
+++ new/usr/src/tools/smatch/src/validation/expand/builtin_isinf.c	Mon Nov 18 13:20:08 2019
@@ -0,0 +1,20 @@
+int test(void)
+{
+	if (!__builtin_isinf(__builtin_inff()))
+		return 0;
+	if (!__builtin_isinf(__builtin_inf()))
+		return 0;
+	if (!__builtin_isinf(__builtin_infl()))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * check-name: builtin_isinf expand
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:08 2019
+++ new/usr/src/tools/smatch/src/validation/expand/builtin_isnan.c	Mon Nov 18 13:20:08 2019
@@ -0,0 +1,20 @@
+int test(void)
+{
+	if (!__builtin_isnan(__builtin_nanf("0")))
+		return 0;
+	if (!__builtin_isnan(__builtin_nan("0")))
+		return 0;
+	if (!__builtin_isnan(__builtin_nanl("0")))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * check-name: builtin_isnan expand
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:08 2019
+++ new/usr/src/tools/smatch/src/validation/expand/builtin_isnormal.c	Mon Nov 18 13:20:08 2019
@@ -0,0 +1,20 @@
+int test(void)
+{
+	if (!__builtin_isnormal(1.0F))
+		return 0;
+	if (!__builtin_isnormal(1.0))
+		return 0;
+	if (!__builtin_isnormal(1.0L))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * check-name: builtin_isnormal expand
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:08 2019
+++ new/usr/src/tools/smatch/src/validation/expand/builtin_nan.c	Mon Nov 18 13:20:08 2019
@@ -0,0 +1,23 @@
+static float nanf(void)
+{
+	return __builtin_nanf("0");
+}
+
+static double nan(void)
+{
+	return __builtin_nan("0");
+}
+
+static long double nanl(void)
+{
+	return __builtin_nanl("0");
+}
+
+/*
+ * check-name: builtin_nan expand
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: call
+ */
--- /dev/null	Mon Nov 18 13:20:08 2019
+++ new/usr/src/tools/smatch/src/validation/expand/function-pointer.c	Mon Nov 18 13:20:08 2019
@@ -0,0 +1,22 @@
+struct s {
+	int (*fun)(void);
+};
+
+inline struct s *inl(struct s *p)
+{
+	1 + 0;
+	return p;
+}
+
+static void tst(struct s *s)
+{
+	inl(s)->fun();
+}
+
+/*
+ * check-name: function-pointer
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-excludes: add\\.32.*\\$1, \\$0
+ */
--- old/usr/src/tools/smatch/src/validation/external-function-has-definition.c	Mon Nov 18 13:20:09 2019
+++ /dev/null	Mon Nov 18 13:20:09 2019
@@ -1,15 +0,0 @@
-
-extern void myfunction(void);
-
-extern void
-myfunction(void)
-{
-	return;
-}
-
-/*
- * check-name: -Wno-external-function-has-definition works
- * check-command: sparse -Wno-external-function-has-definition
- * check-error-start
- * check-error-end
- */
--- /dev/null	Mon Nov 18 13:20:09 2019
+++ new/usr/src/tools/smatch/src/validation/fdiag-prefix.c	Mon Nov 18 13:20:09 2019
@@ -0,0 +1,11 @@
+int a.
+
+/*
+ * check-name: fdiag-prefix
+ * check-command: sparse -fdiagnostic-prefix=prefix $file
+ *
+ * check-error-start
+fdiag-prefix.c:1:6: prefix: error: Expected ; at end of declaration
+fdiag-prefix.c:1:6: prefix: error: got .
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:09 2019
+++ new/usr/src/tools/smatch/src/validation/fp-ops.c	Mon Nov 18 13:20:09 2019
@@ -0,0 +1,57 @@
+double fadd(double x, double y) { return x + y; }
+double fsub(double x, double y) { return x - y; }
+double fmul(double x, double y) { return x * y; }
+double fdiv(double x, double y) { return x / y; }
+double fneg(double x)           { return -x; }
+_Bool  ftst(double x)           { return !x; }
+
+/*
+ * check-name: floating-point ops
+ * check-command: test-linearize -Wno-decl $file
+
+ * check-output-start
+fadd:
+.L0:
+	<entry-point>
+	fadd.64     %r3 <- %arg1, %arg2
+	ret.64      %r3
+
+
+fsub:
+.L2:
+	<entry-point>
+	fsub.64     %r7 <- %arg1, %arg2
+	ret.64      %r7
+
+
+fmul:
+.L4:
+	<entry-point>
+	fmul.64     %r11 <- %arg1, %arg2
+	ret.64      %r11
+
+
+fdiv:
+.L6:
+	<entry-point>
+	fdiv.64     %r15 <- %arg1, %arg2
+	ret.64      %r15
+
+
+fneg:
+.L8:
+	<entry-point>
+	fneg.64     %r18 <- %arg1
+	ret.64      %r18
+
+
+ftst:
+.L10:
+	<entry-point>
+	setfval.64  %r21 <- 0.000000e+00
+	fcmpoeq.1   %r23 <- %arg1, %r21
+	ret.1       %r23
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:09 2019
+++ new/usr/src/tools/smatch/src/validation/function-pointer-type.c	Mon Nov 18 13:20:09 2019
@@ -0,0 +1,12 @@
+extern int fun(void);
+
+void fa(void) { int (*f)(void); f = &fun; }
+void f0(void) { int (*f)(void); f = fun; }	// C99,C11 6.3.2.1p4
+void f1(void) { int (*f)(void); f = *fun; }	// C99,C11 6.5.3.2p4
+void f2(void) { int (*f)(void); f = **fun; }	// C99,C11 6.5.3.2p4
+void f3(void) { int (*f)(void); f = ***fun; }	// C99,C11 6.5.3.2p4
+
+/*
+ * check-name: type of function pointers
+ * check-command: sparse -Wno-decl $file
+ */
--- /dev/null	Mon Nov 18 13:20:09 2019
+++ new/usr/src/tools/smatch/src/validation/function-redecl2.c	Mon Nov 18 13:20:09 2019
@@ -0,0 +1,31 @@
+extern void exit (int __status) __attribute__ ((__noreturn__));
+
+int func0(int a) __attribute__ ((pure));
+
+__attribute__ ((pure))
+int func0(int a)
+{
+	return 0;
+}
+
+__attribute__ ((noreturn)) void func1(int a);
+
+void func1(int a)
+{
+	exit(0);
+}
+
+void func2(int a) __attribute__ ((noreturn));
+
+__attribute__ ((noreturn))
+void func2(int a)
+{
+	exit(0);
+}
+
+/*
+ * check-name: function-redecl2
+ *
+ * check-known-to-fail
+ *
+ */
--- /dev/null	Mon Nov 18 13:20:09 2019
+++ new/usr/src/tools/smatch/src/validation/goto-reserved.c	Mon Nov 18 13:20:09 2019
@@ -0,0 +1,12 @@
+static void foo(void)
+{
+	goto return;
+}
+
+/*
+ * check-name: goto-reserved
+ *
+ * check-error-start
+goto-reserved.c:3:14: error: Trying to use reserved word 'return' as identifier
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:09 2019
+++ new/usr/src/tools/smatch/src/validation/implicit-KR-arg-type1.c	Mon Nov 18 13:20:09 2019
@@ -0,0 +1,16 @@
+int foo(a, b)
+	int a;
+{
+	if (b)
+		return a;
+}
+
+/*
+ * check-name: implicit-KR-arg-type1
+ * check-command: sparse -Wold-style-definition -Wimplicit-int $file
+ *
+ * check-error-start
+implicit-KR-arg-type1.c:2:9: warning: non-ANSI definition of function 'foo'
+implicit-KR-arg-type1.c:1:12: error: missing type declaration for parameter 'b'
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:10 2019
+++ new/usr/src/tools/smatch/src/validation/inc-dec-float.c	Mon Nov 18 13:20:10 2019
@@ -0,0 +1,13 @@
+double fincpre(double a)  { ++a; return a; }
+double fdecpre(double a)  { --a; return a; }
+double fincpost(double a) { a++; return a; }
+double fdecpost(double a) { a--; return a; }
+
+/*
+ * check-name: float inc & dec
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: \\$1$
+ * check-output-excludes: \\$-1$
+ */
--- /dev/null	Mon Nov 18 13:20:10 2019
+++ new/usr/src/tools/smatch/src/validation/incomplete-struct.c	Mon Nov 18 13:20:10 2019
@@ -0,0 +1,23 @@
+struct s;
+
+void foo(struct s s)
+{
+}
+
+struct s bar(void)
+{
+	struct s s;
+	return s;
+}
+
+/*
+ * check-name: incomplete struct
+ * check-command: sparse -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-error-start
+incomplete-struct.c:3:19: error: parameter 's' has incomplete type
+incomplete-struct.c:7:10: error: return type is incomplete
+incomplete-struct.c:9:11: error: 's' has incompelete type
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:10 2019
+++ new/usr/src/tools/smatch/src/validation/infinite-loop01.c	Mon Nov 18 13:20:10 2019
@@ -0,0 +1,54 @@
+void fnp(void)
+{
+	int a;
+	for (;;)
+		a += 1;
+}
+
+void fnm(void)
+{
+	int a;
+	for (;;)
+		a -= 1;
+}
+
+void fna(void)
+{
+	int a;
+	for (;;)
+		a &= 1;
+}
+
+void fno(void)
+{
+	int a;
+	for (;;)
+		a |= 1;
+}
+
+void fnx(void)
+{
+	int a;
+	for (;;)
+		a ^= 1;
+}
+
+void fnl(void)
+{
+	int a;
+	for (;;)
+		a <<= 1;
+}
+
+void fnr(void)
+{
+	int a;
+	for (;;)
+		a >>= 1;
+}
+
+/*
+ * check-name: infinite loop 01
+ * check-command: sparse -Wno-decl $file
+ * check-timeout:
+ */
--- old/usr/src/tools/smatch/src/validation/infinite-loop02.c	Mon Nov 18 13:20:10 2019
+++ new/usr/src/tools/smatch/src/validation/infinite-loop02.c	Mon Nov 18 13:20:10 2019
@@ -8,4 +8,5 @@
 /*
  * check-name: infinite loop 02
  * check-command: sparse -Wno-decl $file
+ * check-timeout:
  */
--- old/usr/src/tools/smatch/src/validation/infinite-loop03.c	Mon Nov 18 13:20:10 2019
+++ new/usr/src/tools/smatch/src/validation/infinite-loop03.c	Mon Nov 18 13:20:10 2019
@@ -13,4 +13,5 @@
 /*
  * check-name: infinite loop 03
  * check-command: sparse -Wno-decl $file
+ * check-timeout:
  */
--- /dev/null	Mon Nov 18 13:20:11 2019
+++ new/usr/src/tools/smatch/src/validation/infinite-loop04.c	Mon Nov 18 13:20:11 2019
@@ -0,0 +1,18 @@
+extern void use(char);
+
+static void foo(char *b)
+{
+	while (b) {
+		if (b++)
+			continue;
+		++b;
+		use(*b);
+		&b;
+	}
+}
+
+/*
+ * check-name: internal infinite loop (4)
+ * check-command: sparse $file
+ * check-timeout:
+ */
--- old/usr/src/tools/smatch/src/validation/int128.c	Mon Nov 18 13:20:11 2019
+++ new/usr/src/tools/smatch/src/validation/int128.c	Mon Nov 18 13:20:11 2019
@@ -30,7 +30,7 @@
  * check-output-ignore
  *
  * check-output-contains: ret\\..*\\$16
- * check-output-contains: mulu\\.128
+ * check-output-contains: mul\\.128
  * check-output-contains: add\\.128
  *
  * check-error-start
--- /dev/null	Mon Nov 18 13:20:11 2019
+++ new/usr/src/tools/smatch/src/validation/integer-const-expr.c	Mon Nov 18 13:20:11 2019
@@ -0,0 +1,85 @@
+extern void *malloc(unsigned long);
+
+static inline __attribute__((__const__)) unsigned squarec(unsigned n)
+{
+        return n*n;
+}
+
+static inline unsigned square(unsigned n)
+{
+        return n*n;
+}
+
+static inline unsigned long long bignum(void)
+{
+        return 1000000000000ULL;
+}
+
+static inline __attribute__((__const__)) unsigned long long bignumc(void)
+{
+        return 1000000000000ULL;
+}
+
+// test if x is an integer constant expression [C99,C11 6.6p6]
+#define ICE_P(x) \
+    (__builtin_types_compatible_p(typeof(0?((void*)((long)(x)*0l)):(int*)1),int*))
+
+#define CHX_P(X)	__builtin_choose_expr(ICE_P(X), 1, 0)
+#define CST_P(X)	__builtin_constant_p(ICE_P(X))
+
+#define TEST(R, X)	_Static_assert(ICE_P(X) == R, "ICE_P(" #X ") => " #R);	\
+			_Static_assert(ICE_P(ICE_P(X)), "ICE_P2(" #X ")");	\
+			_Static_assert(CHX_P(X) == R, "CHX_P(" #X ") => " #R);	\
+			_Static_assert(CST_P(X) == 1, "CST_P(" #X ")")
+
+int main(int argc, char *argv[])
+{
+        char fla[3];
+        char vla[argc++];
+        char **p, **q;
+        int x = 5, y = 8;
+        void *v;
+
+        p = &argv[3];
+        q = &argv[6];
+
+        TEST(1, 4);
+        TEST(1, sizeof(long));
+        TEST(1, 5ull - 3u);
+        TEST(1, 3.2);
+        TEST(1, sizeof(fla));
+
+        TEST(0, square(2));
+        TEST(0, square(argc));
+        TEST(0, squarec(2));
+        TEST(0, squarec(argc));
+        TEST(0, 1+argc-argc);
+        TEST(0, 1+argc+argc+1-argc-argc);
+        TEST(0, bignum() - 1);
+        TEST(0, 0*bignum());
+        TEST(0, 0*bignumc());
+        TEST(0, sizeof(vla));
+        TEST(0, p);
+        TEST(0, p < q);
+        TEST(0, p++);
+        TEST(0, main);
+        TEST(0, malloc(8));
+        TEST(0, v = malloc(8));
+        TEST(0, v);
+        TEST(0, x++);
+        TEST(0, y++);
+        TEST(0, (3, 2, 1));
+        TEST(0, ({x++; 0; }));
+        TEST(0, ({square(y--); 0; }));
+        TEST(0, (square(x), 3));
+        TEST(0, (squarec(x), 3));
+        TEST(0, ({squarec(x); 3;}));
+        TEST(0, ({squarec(x);}));
+
+        return 0;
+}
+
+/*
+ * check-name: integer-const-expr
+ * check-command: sparse -Wno-vla $file
+ */
--- old/usr/src/tools/smatch/src/validation/kill-load.c	Mon Nov 18 13:20:11 2019
+++ new/usr/src/tools/smatch/src/validation/kill-load.c	Mon Nov 18 13:20:11 2019
@@ -13,5 +13,5 @@
  *	- bb unreachable.
  *
  * check-output-ignore
- * check-output-pattern-1-times: load\\.
+ * check-output-pattern(1): load\\.
  */
--- old/usr/src/tools/smatch/src/validation/kill-phi-ttsbb.c	Mon Nov 18 13:20:12 2019
+++ new/usr/src/tools/smatch/src/validation/kill-phi-ttsbb.c	Mon Nov 18 13:20:12 2019
@@ -1,7 +1,7 @@
 int def(void);
 void use(int);
 
-static int foo(int a, int b)
+static void foo(int a, int b)
 {
 	int c;
 
--- old/usr/src/tools/smatch/src/validation/kill-store.c	Mon Nov 18 13:20:12 2019
+++ new/usr/src/tools/smatch/src/validation/kill-store.c	Mon Nov 18 13:20:12 2019
@@ -12,5 +12,5 @@
  *	- bb unreachable.
  *
  * check-output-ignore
- * check-output-pattern-1-times: store\\.
+ * check-output-pattern(1): store\\.
  */
--- /dev/null	Mon Nov 18 13:20:12 2019
+++ new/usr/src/tools/smatch/src/validation/kill-switch.c	Mon Nov 18 13:20:12 2019
@@ -0,0 +1,17 @@
+extern int i;
+
+static void foo(void)
+{
+	switch (i) {
+	case 0:
+		;
+	}
+}
+
+/*
+ * check-name: kill-switch
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ */
--- /dev/null	Mon Nov 18 13:20:12 2019
+++ new/usr/src/tools/smatch/src/validation/label-redefined.c	Mon Nov 18 13:20:13 2019
@@ -0,0 +1,17 @@
+extern void fun(void);
+
+static void foo(int p)
+{
+l:
+	if (p)
+l:
+		fun();
+}
+
+/*
+ * check-name: label-redefined
+ *
+ * check-error-start
+label-redefined.c:7:1: error: label 'l' redefined
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/asm-toplevel.c	Mon Nov 18 13:20:13 2019
+++ /dev/null	Mon Nov 18 13:20:12 2019
@@ -1,7 +0,0 @@
-__asm__("/* nothing */");
-/*
- * check-name: asm-toplevel.c
- * check-command: test-linearize $file
- * check-output-ignore
- * check-output-contains: asm *".. nothing .."
- */
--- /dev/null	Mon Nov 18 13:20:12 2019
+++ new/usr/src/tools/smatch/src/validation/linear/asm-toplevel.c	Mon Nov 18 13:20:13 2019
@@ -0,0 +1,7 @@
+__asm__("/* nothing */");
+/*
+ * check-name: asm-toplevel.c
+ * check-command: test-linearize $file
+ * check-output-ignore
+ * check-output-contains: asm *".. nothing .."
+ */
--- /dev/null	Mon Nov 18 13:20:13 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bitfield-expand-deref.c	Mon Nov 18 13:20:13 2019
@@ -0,0 +1,27 @@
+struct s {
+	int a:8;
+	int b:8;
+};
+
+int foo(void)
+{
+	struct s x = { .a = 12, .b = 34, };
+
+	return x.b;
+}
+
+int bar(int a)
+{
+	struct s x = { .a = 12, .b = a, };
+
+	return x.b;
+}
+
+/*
+ * check-name: bitfield expand deref
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: ret\\..*\\$12
+ * check-output-contains: ret\\..*\\$34
+ */
--- /dev/null	Mon Nov 18 13:20:13 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bitfield-inc.c	Mon Nov 18 13:20:13 2019
@@ -0,0 +1,16 @@
+struct s {
+	int f:5;
+};
+
+void inc(struct s *p)
+{
+	p->f++;
+}
+
+/*
+ * check-name: bitfield-inc
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: add\\.5
+ */
--- old/usr/src/tools/smatch/src/validation/linear/bitfield-init-mask.c	Mon Nov 18 13:20:13 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bitfield-init-mask.c	Mon Nov 18 13:20:13 2019
@@ -18,7 +18,7 @@
 
 /*
  * check-name: bitfield initializer mask
- * check-command: test-linearize -fdump-linearize=only -Wno-decl $file
+ * check-command: test-linearize -fdump-ir=linearize -Wno-decl $file
  * check-output-ignore
  *
  * check-output-contains: and\\..*fffff800\$
--- /dev/null	Mon Nov 18 13:20:13 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bitfield-preinc.c	Mon Nov 18 13:20:14 2019
@@ -0,0 +1,18 @@
+struct s {
+	int f:3;
+};
+
+int preinc(void)
+{
+	struct s s = { 7 };
+	return ++s.f;
+}
+
+/*
+ * check-name: bitfield-preinc
+ * check-description: ++X is equivalent to X+=1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret.32 *\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:14 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bitfield-size.c	Mon Nov 18 13:20:14 2019
@@ -0,0 +1,183 @@
+struct u {
+	unsigned int f:3;
+};
+
+unsigned int upostinc(struct u *x)
+{
+	return x->f++;
+}
+
+unsigned int upreinc(struct u *x)
+{
+	return ++x->f;
+}
+
+void ucpy(struct u *d, const struct u *s)
+{
+	d->f = s->f;
+}
+
+
+struct s {
+	int f:3;
+};
+
+int spostinc(struct s *x)
+{
+	return x->f++;
+}
+
+int spreinc(struct s *x)
+{
+	return ++x->f;
+}
+
+void scpy(struct s *d, const struct s *s)
+{
+	d->f = s->f;
+}
+
+/*
+ * check-name: bitfield-size
+ * check-command: test-linearize -m64 -Wno-decl -fdump-ir  $file
+  * check-assert: sizeof(void *) == 8
+ *
+ * check-output-start
+upostinc:
+.L0:
+	<entry-point>
+	store.64    %arg1 -> 0[x]
+	load.64     %r1 <- 0[x]
+	load.32     %r2 <- 0[%r1]
+	trunc.3     %r3 <- (32) %r2
+	zext.32     %r4 <- (3) %r3
+	add.32      %r5 <- %r4, $1
+	trunc.3     %r6 <- (32) %r5
+	load.32     %r7 <- 0[%r1]
+	zext.32     %r8 <- (3) %r6
+	and.32      %r9 <- %r7, $0xfffffff8
+	or.32       %r10 <- %r9, %r8
+	store.32    %r10 -> 0[%r1]
+	zext.32     %r11 <- (3) %r4
+	phisrc.32   %phi1(return) <- %r11
+	br          .L1
+
+.L1:
+	phi.32      %r12 <- %phi1(return)
+	ret.32      %r12
+
+
+upreinc:
+.L2:
+	<entry-point>
+	store.64    %arg1 -> 0[x]
+	load.64     %r13 <- 0[x]
+	load.32     %r14 <- 0[%r13]
+	trunc.3     %r15 <- (32) %r14
+	zext.32     %r16 <- (3) %r15
+	add.32      %r17 <- %r16, $1
+	trunc.3     %r18 <- (32) %r17
+	load.32     %r19 <- 0[%r13]
+	zext.32     %r20 <- (3) %r18
+	and.32      %r21 <- %r19, $0xfffffff8
+	or.32       %r22 <- %r21, %r20
+	store.32    %r22 -> 0[%r13]
+	zext.32     %r23 <- (3) %r18
+	phisrc.32   %phi2(return) <- %r23
+	br          .L3
+
+.L3:
+	phi.32      %r24 <- %phi2(return)
+	ret.32      %r24
+
+
+ucpy:
+.L4:
+	<entry-point>
+	store.64    %arg1 -> 0[d]
+	store.64    %arg2 -> 0[s]
+	load.64     %r25 <- 0[s]
+	load.32     %r26 <- 0[%r25]
+	trunc.3     %r27 <- (32) %r26
+	load.64     %r28 <- 0[d]
+	load.32     %r29 <- 0[%r28]
+	zext.32     %r30 <- (3) %r27
+	and.32      %r31 <- %r29, $0xfffffff8
+	or.32       %r32 <- %r31, %r30
+	store.32    %r32 -> 0[%r28]
+	br          .L5
+
+.L5:
+	ret
+
+
+spostinc:
+.L6:
+	<entry-point>
+	store.64    %arg1 -> 0[x]
+	load.64     %r33 <- 0[x]
+	load.32     %r34 <- 0[%r33]
+	trunc.3     %r35 <- (32) %r34
+	zext.32     %r36 <- (3) %r35
+	add.32      %r37 <- %r36, $1
+	trunc.3     %r38 <- (32) %r37
+	load.32     %r39 <- 0[%r33]
+	zext.32     %r40 <- (3) %r38
+	and.32      %r41 <- %r39, $0xfffffff8
+	or.32       %r42 <- %r41, %r40
+	store.32    %r42 -> 0[%r33]
+	zext.32     %r43 <- (3) %r36
+	phisrc.32   %phi3(return) <- %r43
+	br          .L7
+
+.L7:
+	phi.32      %r44 <- %phi3(return)
+	ret.32      %r44
+
+
+spreinc:
+.L8:
+	<entry-point>
+	store.64    %arg1 -> 0[x]
+	load.64     %r45 <- 0[x]
+	load.32     %r46 <- 0[%r45]
+	trunc.3     %r47 <- (32) %r46
+	zext.32     %r48 <- (3) %r47
+	add.32      %r49 <- %r48, $1
+	trunc.3     %r50 <- (32) %r49
+	load.32     %r51 <- 0[%r45]
+	zext.32     %r52 <- (3) %r50
+	and.32      %r53 <- %r51, $0xfffffff8
+	or.32       %r54 <- %r53, %r52
+	store.32    %r54 -> 0[%r45]
+	zext.32     %r55 <- (3) %r50
+	phisrc.32   %phi4(return) <- %r55
+	br          .L9
+
+.L9:
+	phi.32      %r56 <- %phi4(return)
+	ret.32      %r56
+
+
+scpy:
+.L10:
+	<entry-point>
+	store.64    %arg1 -> 0[d]
+	store.64    %arg2 -> 0[s]
+	load.64     %r57 <- 0[s]
+	load.32     %r58 <- 0[%r57]
+	trunc.3     %r59 <- (32) %r58
+	load.64     %r60 <- 0[d]
+	load.32     %r61 <- 0[%r60]
+	zext.32     %r62 <- (3) %r59
+	and.32      %r63 <- %r61, $0xfffffff8
+	or.32       %r64 <- %r63, %r62
+	store.32    %r64 -> 0[%r60]
+	br          .L11
+
+.L11:
+	ret
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:14 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bitfield-store.c	Mon Nov 18 13:20:14 2019
@@ -0,0 +1,22 @@
+int foo(void)
+{
+	struct {
+		int a:8;
+		int b:16;
+		int c:8;
+	} s = { 0xff, 0x0000, 0xff };
+
+	return s.b = 0x56781234;
+}
+
+/*
+ * check-name: bitfield-store
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0x1234
+ *
+ * check-error-start
+linear/bitfield-store.c:9:22: warning: cast truncates bits from constant value (56781234 becomes 1234)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:14 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bool-cast-lp32.c	Mon Nov 18 13:20:14 2019
@@ -0,0 +1,19 @@
+extern int ffun(void);
+typedef void *vdp;
+typedef int  *sip;
+
+static _Bool fvdp_i(vdp a) { return a; }
+static _Bool fvdp_e(vdp a) { return (_Bool)a; }
+static _Bool fsip_i(sip a) { return a; }
+static _Bool fsip_e(sip a) { return (_Bool)a; }
+static _Bool ffun_i(void)  { return ffun; }
+static _Bool ffun_e(void)  { return (_Bool)ffun; }
+
+/*
+ * check-name: bool-cast-pointer
+ * check-command: test-linearize -m32 -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: ptrtu\\.
+ */
--- /dev/null	Mon Nov 18 13:20:14 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bool-cast-lp64.c	Mon Nov 18 13:20:14 2019
@@ -0,0 +1,19 @@
+extern int ffun(void);
+typedef void *vdp;
+typedef int  *sip;
+
+static _Bool fvdp_i(vdp a) { return a; }
+static _Bool fvdp_e(vdp a) { return (_Bool)a; }
+static _Bool fsip_i(sip a) { return a; }
+static _Bool fsip_e(sip a) { return (_Bool)a; }
+static _Bool ffun_i(void)  { return ffun; }
+static _Bool ffun_e(void)  { return (_Bool)ffun; }
+
+/*
+ * check-name: bool-cast-pointer
+ * check-command: test-linearize -m64 -fdump-ir $file
+ * check-assert: sizeof(void *) == 8
+ *
+ * check-output-ignore
+ * check-output-excludes: ptrtu\\.
+ */
--- /dev/null	Mon Nov 18 13:20:14 2019
+++ new/usr/src/tools/smatch/src/validation/linear/bool-cast.c	Mon Nov 18 13:20:14 2019
@@ -0,0 +1,37 @@
+extern int fun(void);
+typedef unsigned int	u32;
+typedef          int	s32;
+typedef void *vdp;
+typedef int  *sip;
+typedef double dbl;
+typedef unsigned short __attribute__((bitwise)) le16;
+
+static _Bool fs32_i(s32 a) { return a; }
+static _Bool fs32_e(s32 a) { return (_Bool)a; }
+static _Bool fu32_i(u32 a) { return a; }
+static _Bool fu32_e(u32 a) { return (_Bool)a; }
+static _Bool fvdp_i(vdp a) { return a; }
+static _Bool fvdp_e(vdp a) { return (_Bool)a; }
+static _Bool fsip_i(sip a) { return a; }
+static _Bool fsip_e(sip a) { return (_Bool)a; }
+static _Bool ffun_i(void)  { return fun; }
+static _Bool ffun_e(void)  { return (_Bool)fun; }
+static _Bool fres_i(le16 a) { return a; }
+static _Bool fres_e(le16 a) { return (_Bool)a; }
+static _Bool fdbl_i(dbl a) { return a; }
+static _Bool fdbl_e(dbl a) { return (_Bool)a; }
+
+/*
+ * check-name: bool-cast
+ * check-command: test-linearize -m64 -fdump-ir=linearize $file
+ * check-assert: sizeof(void*) == 8 && sizeof(long) == 8 && sizeof(double) == 8
+ *
+ * check-output-ignore
+ * check-output-excludes: cast\\.
+ * check-output-excludes: fcvt[us]\\.
+ * check-output-excludes: ptrtu\\.
+ * check-output-excludes: [sz]ext\\.
+ * check-output-excludes: trunc\\.
+ * check-output-pattern(12): setne\\.
+ * check-output-pattern(2): fcmpune\\.
+ */
--- /dev/null	Mon Nov 18 13:20:14 2019
+++ new/usr/src/tools/smatch/src/validation/linear/builtin_unreachable.c	Mon Nov 18 13:20:14 2019
@@ -0,0 +1,31 @@
+void function_that_never_returns(void);
+
+int foo(int c)
+{
+	if (c)
+		return 1;
+	function_that_never_returns();
+	__builtin_unreachable();
+}
+
+/*
+ * check-name: __builtin_unreachable()
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-known-to-fail
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	cbr         %arg1, .L3, .L2
+
+.L2:
+	call        function_that_never_returns
+	unreach
+
+.L3:
+	ret.32      $1
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/call-basic.c	Mon Nov 18 13:20:15 2019
@@ -0,0 +1,57 @@
+extern int fun(int a);
+
+void symbol(int a)
+{
+	fun(a);
+}
+
+void pointer0(int a, int (*fun)(int))
+{
+	fun(a);
+}
+
+void pointer1(int a, int (*fun)(int))
+{
+	(*fun)(a);
+}
+
+void builtin(int a)
+{
+	__builtin_popcount(a);
+}
+
+/*
+ * check-name: basic function calls
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+symbol:
+.L0:
+	<entry-point>
+	call.32     %r2 <- fun, %arg1
+	ret
+
+
+pointer0:
+.L2:
+	<entry-point>
+	call.32     %r5 <- %arg2, %arg1
+	ret
+
+
+pointer1:
+.L4:
+	<entry-point>
+	call.32     %r8 <- %arg2, %arg1
+	ret
+
+
+builtin:
+.L6:
+	<entry-point>
+	call.32     %r10 <- __builtin_popcount, %arg1
+	ret
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/call-builtin.c	Mon Nov 18 13:20:15 2019
@@ -0,0 +1,17 @@
+typedef unsigned int u32;
+
+u32 ff(u32 a) { return __builtin_popcount(a); }
+
+u32 f0(u32 a) { return (__builtin_popcount)(a); }
+u32 f1(u32 a) { return (*__builtin_popcount)(a); }	// C99,C11 6.5.3.2p4
+u32 f2(u32 a) { return (**__builtin_popcount)(a); }	// C99,C11 6.5.3.2p4
+u32 f3(u32 a) { return (***__builtin_popcount)(a); }	// C99,C11 6.5.3.2p4
+
+/*
+ * check-name: builtin calls
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load
+ * check-output-pattern(5): call\\..*__builtin_.*, %arg1
+ */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/call-casted-pointer.c	Mon Nov 18 13:20:15 2019
@@ -0,0 +1,31 @@
+typedef int (*fun_t)(void*);
+
+int foo(void *a, void *fun)
+{
+	return ((fun_t)fun)(a);
+}
+
+int bar(void *a, void *fun)
+{
+	return ((int (*)(void *))fun)(a);
+}
+
+int qux(void *a, void *fun)
+{
+	return (*(fun_t)fun)(a);
+}
+
+int quz(void *a, void *fun)
+{
+	return (*(int (*)(void *))fun)(a);
+}
+
+/*
+ * check-name: call via casted function pointer
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load
+ * check-output-pattern(4): ptrcast\\..* %arg2
+ * check-output-pattern(4): call\\..* %arg1
+ */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/call-complex-pointer.c	Mon Nov 18 13:20:15 2019
@@ -0,0 +1,33 @@
+int foo(int p, int (*f0)(int), int (*f1)(int), int arg)
+{
+	return (p ? f0 : f1)(arg);
+}
+
+/*
+ * check-name: call-complex-pointer
+ * check-command: test-linearize -m64 -Wno-decl $file
+ * check-assert: sizeof(void *) == 8
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	cbr         %arg1, .L2, .L3
+
+.L2:
+	phisrc.64   %phi1 <- %arg2
+	br          .L4
+
+.L3:
+	ptrcast.64  %r6 <- (64) %arg3
+	phisrc.64   %phi2 <- %r6
+	br          .L4
+
+.L4:
+	phi.64      %r7 <- %phi1, %phi2
+	call.32     %r8 <- %r7, %arg4
+	ret.32      %r8
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/call-direct.c	Mon Nov 18 13:20:15 2019
@@ -0,0 +1,17 @@
+extern int fun(void);
+
+int ff(void) { return fun(); }
+
+int f0(void) { return (fun)(); }
+int f1(void) { return (*fun)(); }	// C99,C11 6.5.3.2p4
+int f2(void) { return (**fun)(); }	// C99,C11 6.5.3.2p4
+int f3(void) { return (***fun)(); }	// C99,C11 6.5.3.2p4
+
+/*
+ * check-name: direct calls
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load
+ * check-output-pattern(5): call\\..* fun
+ */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/call-indirect.c	Mon Nov 18 13:20:15 2019
@@ -0,0 +1,15 @@
+int gg(int (*fun)(void)) { return fun(); }
+
+int g0(int (*fun)(void)) { return (fun)(); }
+int g1(int (*fun)(void)) { return (*fun)(); }	// C99,C11 6.5.3.2p4
+int g2(int (*fun)(void)) { return (**fun)(); }	// C99,C11 6.5.3.2p4
+int g3(int (*fun)(void)) { return (***fun)(); }	// C99,C11 6.5.3.2p4
+
+/*
+ * check-name: indirect calls
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load
+ * check-output-pattern(5): call\\..* %arg1
+ */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/call-inline.c	Mon Nov 18 13:20:15 2019
@@ -0,0 +1,18 @@
+static inline int fun(void) { return 42; }
+
+int fi(void) { return fun(); }
+
+int i0(void) { return (fun)(); }
+int i1(void) { return (*fun)(); }		// C99,C11 6.5.3.2p4
+int i2(void) { return (**fun)(); }		// C99,C11 6.5.3.2p4
+int i3(void) { return (***fun)(); }		// C99,C11 6.5.3.2p4
+
+/*
+ * check-name: inline calls
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load
+ * check-output-excludes: call
+ * check-output-pattern(5): ret\\..* \\$42
+ */
--- old/usr/src/tools/smatch/src/validation/cast-constant-to-float.c	Mon Nov 18 13:20:16 2019
+++ /dev/null	Mon Nov 18 13:20:15 2019
@@ -1,35 +0,0 @@
-typedef unsigned int uint;
-typedef unsigned long ulong;
-
-double f1(void) { return -1; }
-double f2(void) { return (double)-1; }
-double f3(void) { return -1.0; }
-
-/*
- * check-name: cast-constant-to-float
- * check-command: test-linearize -Wno-decl $file
- *
- * check-output-start
-f1:
-.L0:
-	<entry-point>
-	set.64      %r1 <- -1.000000
-	ret.64      %r1
-
-
-f2:
-.L2:
-	<entry-point>
-	set.64      %r3 <- -1.000000
-	ret.64      %r3
-
-
-f3:
-.L4:
-	<entry-point>
-	set.64      %r5 <- -1.000000
-	ret.64      %r5
-
-
- * check-output-end
- */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/cast-constant-to-float.c	Mon Nov 18 13:20:16 2019
@@ -0,0 +1,35 @@
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+double f1(void) { return -1; }
+double f2(void) { return (double)-1; }
+double f3(void) { return -1.0; }
+
+/*
+ * check-name: cast-constant-to-float
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+f1:
+.L0:
+	<entry-point>
+	setfval.64  %r1 <- -1.000000e+00
+	ret.64      %r1
+
+
+f2:
+.L2:
+	<entry-point>
+	setfval.64  %r3 <- -1.000000e+00
+	ret.64      %r3
+
+
+f3:
+.L4:
+	<entry-point>
+	setfval.64  %r5 <- -1.000000e+00
+	ret.64      %r5
+
+
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/cast-constants.c	Mon Nov 18 13:20:16 2019
+++ /dev/null	Mon Nov 18 13:20:15 2019
@@ -1,357 +0,0 @@
-typedef unsigned int uint;
-typedef unsigned long ulong;
-
-static int uint_2_int(void) { return (int)123U; }
-static int long_2_int(void) { return (int)123L; }
-static int ulong_2_int(void) { return (int)123UL; }
-static int vptr_2_int(void) { return (int)((void*)123); }
-static int iptr_2_int(void) { return (int)((int*)128); }
-static int float_2_int(void) { return (int)1.123F; }
-static int double_2_int(void) { return (int)1.123L; }
-static uint int_2_uint(void) { return (uint)123; }
-static uint long_2_uint(void) { return (uint)123L; }
-static uint ulong_2_uint(void) { return (uint)123UL; }
-static uint vptr_2_uint(void) { return (uint)((void*)123); }
-static uint iptr_2_uint(void) { return (uint)((int*)128); }
-static uint float_2_uint(void) { return (uint)1.123F; }
-static uint double_2_uint(void) { return (uint)1.123L; }
-static long int_2_long(void) { return (long)123; }
-static long uint_2_long(void) { return (long)123U; }
-static long ulong_2_long(void) { return (long)123UL; }
-static long vptr_2_long(void) { return (long)((void*)123); }
-static long iptr_2_long(void) { return (long)((int*)128); }
-static long float_2_long(void) { return (long)1.123F; }
-static long double_2_long(void) { return (long)1.123L; }
-static ulong int_2_ulong(void) { return (ulong)123; }
-static ulong uint_2_ulong(void) { return (ulong)123U; }
-static ulong long_2_ulong(void) { return (ulong)123L; }
-static ulong vptr_2_ulong(void) { return (ulong)((void*)123); }
-static ulong iptr_2_ulong(void) { return (ulong)((int*)128); }
-static ulong float_2_ulong(void) { return (ulong)1.123F; }
-static ulong double_2_ulong(void) { return (ulong)1.123L; }
-static void * int_2_vptr(void) { return (void *)123; }
-static void * uint_2_vptr(void) { return (void *)123U; }
-static void * long_2_vptr(void) { return (void *)123L; }
-static void * ulong_2_vptr(void) { return (void *)123UL; }
-static void * iptr_2_vptr(void) { return (void *)((int*)128); }
-static int * int_2_iptr(void) { return (int *)123; }
-static int * uint_2_iptr(void) { return (int *)123U; }
-static int * long_2_iptr(void) { return (int *)123L; }
-static int * ulong_2_iptr(void) { return (int *)123UL; }
-static int * vptr_2_iptr(void) { return (int *)((void*)123); }
-static float int_2_float(void) { return (float)123; }
-static float uint_2_float(void) { return (float)123U; }
-static float long_2_float(void) { return (float)123L; }
-static float ulong_2_float(void) { return (float)123UL; }
-static float double_2_float(void) { return (float)1.123L; }
-static double int_2_double(void) { return (double)123; }
-static double uint_2_double(void) { return (double)123U; }
-static double long_2_double(void) { return (double)123L; }
-static double ulong_2_double(void) { return (double)123UL; }
-static double float_2_double(void) { return (double)1.123F; }
-
-/*
- * check-name: cast-constants.c
- * check-command: test-linearize -m64 $file
- *
- * check-output-start
-uint_2_int:
-.L0:
-	<entry-point>
-	ret.32      $123
-
-
-long_2_int:
-.L2:
-	<entry-point>
-	ret.32      $123
-
-
-ulong_2_int:
-.L4:
-	<entry-point>
-	ret.32      $123
-
-
-vptr_2_int:
-.L6:
-	<entry-point>
-	ret.32      $123
-
-
-iptr_2_int:
-.L8:
-	<entry-point>
-	ret.32      $128
-
-
-float_2_int:
-.L10:
-	<entry-point>
-	ret.32      $1
-
-
-double_2_int:
-.L12:
-	<entry-point>
-	ret.32      $1
-
-
-int_2_uint:
-.L14:
-	<entry-point>
-	ret.32      $123
-
-
-long_2_uint:
-.L16:
-	<entry-point>
-	ret.32      $123
-
-
-ulong_2_uint:
-.L18:
-	<entry-point>
-	ret.32      $123
-
-
-vptr_2_uint:
-.L20:
-	<entry-point>
-	ret.32      $123
-
-
-iptr_2_uint:
-.L22:
-	<entry-point>
-	ret.32      $128
-
-
-float_2_uint:
-.L24:
-	<entry-point>
-	ret.32      $1
-
-
-double_2_uint:
-.L26:
-	<entry-point>
-	ret.32      $1
-
-
-int_2_long:
-.L28:
-	<entry-point>
-	ret.64      $123
-
-
-uint_2_long:
-.L30:
-	<entry-point>
-	ret.64      $123
-
-
-ulong_2_long:
-.L32:
-	<entry-point>
-	ret.64      $123
-
-
-vptr_2_long:
-.L34:
-	<entry-point>
-	ret.64      $123
-
-
-iptr_2_long:
-.L36:
-	<entry-point>
-	ret.64      $128
-
-
-float_2_long:
-.L38:
-	<entry-point>
-	ret.64      $1
-
-
-double_2_long:
-.L40:
-	<entry-point>
-	ret.64      $1
-
-
-int_2_ulong:
-.L42:
-	<entry-point>
-	ret.64      $123
-
-
-uint_2_ulong:
-.L44:
-	<entry-point>
-	ret.64      $123
-
-
-long_2_ulong:
-.L46:
-	<entry-point>
-	ret.64      $123
-
-
-vptr_2_ulong:
-.L48:
-	<entry-point>
-	ret.64      $123
-
-
-iptr_2_ulong:
-.L50:
-	<entry-point>
-	ret.64      $128
-
-
-float_2_ulong:
-.L52:
-	<entry-point>
-	ret.64      $1
-
-
-double_2_ulong:
-.L54:
-	<entry-point>
-	ret.64      $1
-
-
-int_2_vptr:
-.L56:
-	<entry-point>
-	ret.64      $123
-
-
-uint_2_vptr:
-.L58:
-	<entry-point>
-	ret.64      $123
-
-
-long_2_vptr:
-.L60:
-	<entry-point>
-	ret.64      $123
-
-
-ulong_2_vptr:
-.L62:
-	<entry-point>
-	ret.64      $123
-
-
-iptr_2_vptr:
-.L64:
-	<entry-point>
-	ret.64      $128
-
-
-int_2_iptr:
-.L66:
-	<entry-point>
-	ret.64      $123
-
-
-uint_2_iptr:
-.L68:
-	<entry-point>
-	ret.64      $123
-
-
-long_2_iptr:
-.L70:
-	<entry-point>
-	ret.64      $123
-
-
-ulong_2_iptr:
-.L72:
-	<entry-point>
-	ret.64      $123
-
-
-vptr_2_iptr:
-.L74:
-	<entry-point>
-	ret.64      $123
-
-
-int_2_float:
-.L76:
-	<entry-point>
-	set.32      %r39 <- 123.000000
-	ret.32      %r39
-
-
-uint_2_float:
-.L78:
-	<entry-point>
-	set.32      %r41 <- 123.000000
-	ret.32      %r41
-
-
-long_2_float:
-.L80:
-	<entry-point>
-	set.32      %r43 <- 123.000000
-	ret.32      %r43
-
-
-ulong_2_float:
-.L82:
-	<entry-point>
-	set.32      %r45 <- 123.000000
-	ret.32      %r45
-
-
-double_2_float:
-.L84:
-	<entry-point>
-	set.32      %r47 <- 1.123000
-	ret.32      %r47
-
-
-int_2_double:
-.L86:
-	<entry-point>
-	set.64      %r49 <- 123.000000
-	ret.64      %r49
-
-
-uint_2_double:
-.L88:
-	<entry-point>
-	set.64      %r51 <- 123.000000
-	ret.64      %r51
-
-
-long_2_double:
-.L90:
-	<entry-point>
-	set.64      %r53 <- 123.000000
-	ret.64      %r53
-
-
-ulong_2_double:
-.L92:
-	<entry-point>
-	set.64      %r55 <- 123.000000
-	ret.64      %r55
-
-
-float_2_double:
-.L94:
-	<entry-point>
-	set.64      %r57 <- 1.123000
-	ret.64      %r57
-
-
- * check-output-end
- */
--- /dev/null	Mon Nov 18 13:20:15 2019
+++ new/usr/src/tools/smatch/src/validation/linear/cast-constants.c	Mon Nov 18 13:20:16 2019
@@ -0,0 +1,358 @@
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+static int uint_2_int(void) { return (int)123U; }
+static int long_2_int(void) { return (int)123L; }
+static int ulong_2_int(void) { return (int)123UL; }
+static int vptr_2_int(void) { return (int)((void*)123); }
+static int iptr_2_int(void) { return (int)((int*)128); }
+static int float_2_int(void) { return (int)1.123F; }
+static int double_2_int(void) { return (int)1.123L; }
+static uint int_2_uint(void) { return (uint)123; }
+static uint long_2_uint(void) { return (uint)123L; }
+static uint ulong_2_uint(void) { return (uint)123UL; }
+static uint vptr_2_uint(void) { return (uint)((void*)123); }
+static uint iptr_2_uint(void) { return (uint)((int*)128); }
+static uint float_2_uint(void) { return (uint)1.123F; }
+static uint double_2_uint(void) { return (uint)1.123L; }
+static long int_2_long(void) { return (long)123; }
+static long uint_2_long(void) { return (long)123U; }
+static long ulong_2_long(void) { return (long)123UL; }
+static long vptr_2_long(void) { return (long)((void*)123); }
+static long iptr_2_long(void) { return (long)((int*)128); }
+static long float_2_long(void) { return (long)1.123F; }
+static long double_2_long(void) { return (long)1.123L; }
+static ulong int_2_ulong(void) { return (ulong)123; }
+static ulong uint_2_ulong(void) { return (ulong)123U; }
+static ulong long_2_ulong(void) { return (ulong)123L; }
+static ulong vptr_2_ulong(void) { return (ulong)((void*)123); }
+static ulong iptr_2_ulong(void) { return (ulong)((int*)128); }
+static ulong float_2_ulong(void) { return (ulong)1.123F; }
+static ulong double_2_ulong(void) { return (ulong)1.123L; }
+static void * int_2_vptr(void) { return (void *)123; }
+static void * uint_2_vptr(void) { return (void *)123U; }
+static void * long_2_vptr(void) { return (void *)123L; }
+static void * ulong_2_vptr(void) { return (void *)123UL; }
+static void * iptr_2_vptr(void) { return (void *)((int*)128); }
+static int * int_2_iptr(void) { return (int *)123; }
+static int * uint_2_iptr(void) { return (int *)123U; }
+static int * long_2_iptr(void) { return (int *)123L; }
+static int * ulong_2_iptr(void) { return (int *)123UL; }
+static int * vptr_2_iptr(void) { return (int *)((void*)123); }
+static float int_2_float(void) { return (float)123; }
+static float uint_2_float(void) { return (float)123U; }
+static float long_2_float(void) { return (float)123L; }
+static float ulong_2_float(void) { return (float)123UL; }
+static float double_2_float(void) { return (float)1.123L; }
+static double int_2_double(void) { return (double)123; }
+static double uint_2_double(void) { return (double)123U; }
+static double long_2_double(void) { return (double)123L; }
+static double ulong_2_double(void) { return (double)123UL; }
+static double float_2_double(void) { return (double)1.123F; }
+
+/*
+ * check-name: cast-constants.c
+ * check-command: test-linearize -m64 $file
+ * check-assert: sizeof(void *) == 8 && sizeof(long) == 8 && sizeof(double) == 8
+ *
+ * check-output-start
+uint_2_int:
+.L0:
+	<entry-point>
+	ret.32      $123
+
+
+long_2_int:
+.L2:
+	<entry-point>
+	ret.32      $123
+
+
+ulong_2_int:
+.L4:
+	<entry-point>
+	ret.32      $123
+
+
+vptr_2_int:
+.L6:
+	<entry-point>
+	ret.32      $123
+
+
+iptr_2_int:
+.L8:
+	<entry-point>
+	ret.32      $128
+
+
+float_2_int:
+.L10:
+	<entry-point>
+	ret.32      $1
+
+
+double_2_int:
+.L12:
+	<entry-point>
+	ret.32      $1
+
+
+int_2_uint:
+.L14:
+	<entry-point>
+	ret.32      $123
+
+
+long_2_uint:
+.L16:
+	<entry-point>
+	ret.32      $123
+
+
+ulong_2_uint:
+.L18:
+	<entry-point>
+	ret.32      $123
+
+
+vptr_2_uint:
+.L20:
+	<entry-point>
+	ret.32      $123
+
+
+iptr_2_uint:
+.L22:
+	<entry-point>
+	ret.32      $128
+
+
+float_2_uint:
+.L24:
+	<entry-point>
+	ret.32      $1
+
+
+double_2_uint:
+.L26:
+	<entry-point>
+	ret.32      $1
+
+
+int_2_long:
+.L28:
+	<entry-point>
+	ret.64      $123
+
+
+uint_2_long:
+.L30:
+	<entry-point>
+	ret.64      $123
+
+
+ulong_2_long:
+.L32:
+	<entry-point>
+	ret.64      $123
+
+
+vptr_2_long:
+.L34:
+	<entry-point>
+	ret.64      $123
+
+
+iptr_2_long:
+.L36:
+	<entry-point>
+	ret.64      $128
+
+
+float_2_long:
+.L38:
+	<entry-point>
+	ret.64      $1
+
+
+double_2_long:
+.L40:
+	<entry-point>
+	ret.64      $1
+
+
+int_2_ulong:
+.L42:
+	<entry-point>
+	ret.64      $123
+
+
+uint_2_ulong:
+.L44:
+	<entry-point>
+	ret.64      $123
+
+
+long_2_ulong:
+.L46:
+	<entry-point>
+	ret.64      $123
+
+
+vptr_2_ulong:
+.L48:
+	<entry-point>
+	ret.64      $123
+
+
+iptr_2_ulong:
+.L50:
+	<entry-point>
+	ret.64      $128
+
+
+float_2_ulong:
+.L52:
+	<entry-point>
+	ret.64      $1
+
+
+double_2_ulong:
+.L54:
+	<entry-point>
+	ret.64      $1
+
+
+int_2_vptr:
+.L56:
+	<entry-point>
+	ret.64      $123
+
+
+uint_2_vptr:
+.L58:
+	<entry-point>
+	ret.64      $123
+
+
+long_2_vptr:
+.L60:
+	<entry-point>
+	ret.64      $123
+
+
+ulong_2_vptr:
+.L62:
+	<entry-point>
+	ret.64      $123
+
+
+iptr_2_vptr:
+.L64:
+	<entry-point>
+	ret.64      $128
+
+
+int_2_iptr:
+.L66:
+	<entry-point>
+	ret.64      $123
+
+
+uint_2_iptr:
+.L68:
+	<entry-point>
+	ret.64      $123
+
+
+long_2_iptr:
+.L70:
+	<entry-point>
+	ret.64      $123
+
+
+ulong_2_iptr:
+.L72:
+	<entry-point>
+	ret.64      $123
+
+
+vptr_2_iptr:
+.L74:
+	<entry-point>
+	ret.64      $123
+
+
+int_2_float:
+.L76:
+	<entry-point>
+	setfval.32  %r39 <- 1.230000e+02
+	ret.32      %r39
+
+
+uint_2_float:
+.L78:
+	<entry-point>
+	setfval.32  %r41 <- 1.230000e+02
+	ret.32      %r41
+
+
+long_2_float:
+.L80:
+	<entry-point>
+	setfval.32  %r43 <- 1.230000e+02
+	ret.32      %r43
+
+
+ulong_2_float:
+.L82:
+	<entry-point>
+	setfval.32  %r45 <- 1.230000e+02
+	ret.32      %r45
+
+
+double_2_float:
+.L84:
+	<entry-point>
+	setfval.32  %r47 <- 1.123000e+00
+	ret.32      %r47
+
+
+int_2_double:
+.L86:
+	<entry-point>
+	setfval.64  %r49 <- 1.230000e+02
+	ret.64      %r49
+
+
+uint_2_double:
+.L88:
+	<entry-point>
+	setfval.64  %r51 <- 1.230000e+02
+	ret.64      %r51
+
+
+long_2_double:
+.L90:
+	<entry-point>
+	setfval.64  %r53 <- 1.230000e+02
+	ret.64      %r53
+
+
+ulong_2_double:
+.L92:
+	<entry-point>
+	setfval.64  %r55 <- 1.230000e+02
+	ret.64      %r55
+
+
+float_2_double:
+.L94:
+	<entry-point>
+	setfval.64  %r57 <- 1.123000e+00
+	ret.64      %r57
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:16 2019
+++ new/usr/src/tools/smatch/src/validation/linear/cast-volatile.c	Mon Nov 18 13:20:16 2019
@@ -0,0 +1,15 @@
+static int foo(volatile int *a, int v)
+{
+	*a = v;
+	return *a;
+}
+
+/*
+ * check-name: cast-volatile
+ * check-command: test-linearize -fdump-ir=linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ * check-output-excludes: trunc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:16 2019
+++ new/usr/src/tools/smatch/src/validation/linear/compound-literal00.c	Mon Nov 18 13:20:17 2019
@@ -0,0 +1,18 @@
+struct bfs {
+        int a: 2;
+        int b: 30;
+};
+
+int foo(void)
+{
+        return (struct bfs){ .a = 1, .b = 2}.b;
+}
+
+/*
+ * check-name: compound-literal00.c
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$2
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:17 2019
+++ new/usr/src/tools/smatch/src/validation/linear/compound-literal01.c	Mon Nov 18 13:20:17 2019
@@ -0,0 +1,18 @@
+struct bfs {
+        int a: 2;
+        int b: 30;
+};
+
+int foo(void)
+{
+        struct bfs bf = { .a = 1, .b = 2 };
+        return (struct bfs[]){bf}[0].b;
+}
+
+/*
+ * check-name: compound-literal01.c
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$2
+ */
--- /dev/null	Mon Nov 18 13:20:17 2019
+++ new/usr/src/tools/smatch/src/validation/linear/compound-literal02.c	Mon Nov 18 13:20:17 2019
@@ -0,0 +1,19 @@
+struct bfs {
+        int a: 2;
+        int b: 30;
+};
+
+int bar(void)
+{
+        struct bfs bf = { .a = 1, .b = 4 };
+        return (struct bfs[]){bf, { .a = 3, .b = 6}}[1].b;
+}
+
+/*
+ * check-name: compound-literal02.c
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-known-to-fail
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$6
+ */
--- /dev/null	Mon Nov 18 13:20:17 2019
+++ new/usr/src/tools/smatch/src/validation/linear/degen-array.c	Mon Nov 18 13:20:17 2019
@@ -0,0 +1,32 @@
+extern int a[3];
+
+int (*fa(int i))[] { return &a; }
+int *f0(int i) { return &a[0]; }
+int *fd(int i) { return  a; }
+
+/*
+ * check-name: degen-array
+ * check-command: test-linearize -m64 -Wno-decl $file
+ * check-assert: sizeof(void *) == 8
+ *
+ * check-output-start
+fa:
+.L0:
+	<entry-point>
+	ret.64      a
+
+
+f0:
+.L2:
+	<entry-point>
+	ret.64      a
+
+
+fd:
+.L4:
+	<entry-point>
+	ret.64      a
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:17 2019
+++ new/usr/src/tools/smatch/src/validation/linear/degen-function.c	Mon Nov 18 13:20:17 2019
@@ -0,0 +1,52 @@
+extern int fun(int);
+
+typedef int (*fun_t)(int);
+
+fun_t fa(void) { return &fun; }
+fun_t f0(void) { return  fun; }
+fun_t f1(void) { return *fun; }
+
+/*
+ * check-name: degen-function
+ * check-command: test-linearize -m64 -Wno-decl -fdump-ir=linearize $file
+ * check-assert: sizeof(void *) == 8
+ *
+ * check-output-start
+fa:
+.L0:
+	<entry-point>
+	symaddr.64  %r1 <- fun
+	phisrc.64   %phi1(return) <- %r1
+	br          .L1
+
+.L1:
+	phi.64      %r2 <- %phi1(return)
+	ret.64      %r2
+
+
+f0:
+.L2:
+	<entry-point>
+	symaddr.64  %r3 <- fun
+	phisrc.64   %phi2(return) <- %r3
+	br          .L3
+
+.L3:
+	phi.64      %r4 <- %phi2(return)
+	ret.64      %r4
+
+
+f1:
+.L4:
+	<entry-point>
+	symaddr.64  %r5 <- fun
+	phisrc.64   %phi3(return) <- %r5
+	br          .L5
+
+.L5:
+	phi.64      %r6 <- %phi3(return)
+	ret.64      %r6
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:17 2019
+++ new/usr/src/tools/smatch/src/validation/linear/degen-log-not.c	Mon Nov 18 13:20:17 2019
@@ -0,0 +1,40 @@
+extern int arr[];
+int test_arr_addr(int i)
+{
+	if (!&arr) return 1;
+	return 0;
+}
+
+int test_arr_addr0(int i)
+{
+	if (!&arr[0]) return 1;
+	return 0;
+}
+
+int test_arr_degen(int i)
+{
+	if (!arr) return 1;
+	return 0;
+}
+
+extern int fun(void);
+int test_fun_addr(int i)
+{
+	if (!&fun) return 1;
+	return 0;
+}
+
+int test_fun_degen(int i)
+{
+	if (!fun) return 1;
+	return 0;
+}
+
+/*
+ * check-name: degenerate logical-not
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load
+ * check-output-excludes: VOID
+ */
--- /dev/null	Mon Nov 18 13:20:17 2019
+++ new/usr/src/tools/smatch/src/validation/linear/deref-ptr-ptr.c	Mon Nov 18 13:20:17 2019
@@ -0,0 +1,27 @@
+char *foo(char **pfmt)
+{
+	return ++*pfmt;
+}
+
+/*
+ * check-name: deref-ptr-ptr
+ * check-command: test-linearize -m64 -Wno-decl $file
+ * check-assert: sizeof(void *) == 8
+ *
+ * check-output-excludes: load[^.]
+ * check-output-contains: load\\.
+ * check-output-excludes: store[^.]
+ * check-output-contains: store\\.
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	load.64     %r2 <- 0[%arg1]
+	add.64      %r3 <- %r2, $1
+	store.64    %r3 -> 0[%arg1]
+	ret.64      %r3
+
+
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/fp-vs-ptrcast.c	Mon Nov 18 13:20:18 2019
+++ /dev/null	Mon Nov 18 13:20:17 2019
@@ -1,13 +0,0 @@
-float *f01(void* p)
-{
-	return p;
-}
-
-/*
- * check-name: fp-vs-ptrcast
- * check-command: test-linearize -Wno-decl $file
- * check-output-ignore
- *
- * check-output-excludes: fpcast
- * check-output-contains: ptrcast
- */
--- /dev/null	Mon Nov 18 13:20:17 2019
+++ new/usr/src/tools/smatch/src/validation/linear/fp-vs-ptrcast.c	Mon Nov 18 13:20:18 2019
@@ -0,0 +1,13 @@
+float *f01(void* p)
+{
+	return p;
+}
+
+/*
+ * check-name: fp-vs-ptrcast
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: fpcast
+ * check-output-contains: ptrcast
+ */
--- /dev/null	Mon Nov 18 13:20:18 2019
+++ new/usr/src/tools/smatch/src/validation/linear/fp2i-cast.c	Mon Nov 18 13:20:18 2019
@@ -0,0 +1,31 @@
+#if __SIZEOF_INT__ == __SIZEOF_FLOAT__
+typedef   signed int si;
+typedef unsigned int ui;
+#else
+#error "no float-sized integer type"
+#endif
+
+#if __SIZEOF_LONG_LONG__ == __SIZEOF_DOUBLE__
+typedef   signed long long sl;
+typedef unsigned long long ul;
+#else
+#error "no double-sized integer type"
+#endif
+
+si f2si(float  a) { return a; }
+ui f2ui(float  a) { return a; }
+sl f2sl(float  a) { return a; }
+ul f2ul(float  a) { return a; }
+si d2si(double a) { return a; }
+ui d2ui(double a) { return a; }
+sl d2sl(double a) { return a; }
+ul d2ul(double a) { return a; }
+
+/*
+ * check-name: fp2i cast
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(4): fcvts\\.
+ * check-output-pattern(4): fcvtu\\.
+ */
--- /dev/null	Mon Nov 18 13:20:18 2019
+++ new/usr/src/tools/smatch/src/validation/linear/logical-phi0.c	Mon Nov 18 13:20:18 2019
@@ -0,0 +1,48 @@
+int a(void);
+int b(void);
+int c(void);
+
+static int laa(void)
+{
+	return (a() && b()) && c();
+}
+
+static int lao(void)
+{
+	return (a() && b()) || c();
+}
+
+static int loa(void)
+{
+	return (a() || b()) && c();
+}
+
+static int loo(void)
+{
+	return (a() || b()) || c();
+}
+
+static int raa(void)
+{
+	return a() && (b() && c());
+}
+
+static int rao(void)
+{
+	return a() && (b() || c());
+}
+
+static int roa(void)
+{
+	return a() || (b() && c());
+}
+
+static int roo(void)
+{
+	return a() || (b() || c());
+}
+
+/*
+ * check-name: bad-logical-phi0
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:18 2019
+++ new/usr/src/tools/smatch/src/validation/linear/logical.c	Mon Nov 18 13:20:18 2019
@@ -0,0 +1,260 @@
+struct S {
+	         int  :1;
+	  signed int s:2;
+	unsigned int u:3;
+	        long l;
+	      double d;
+};
+
+int os(int i, struct S *b) { return i || b->s; }
+int ou(int i, struct S *b) { return i || b->u; }
+int ol(int i, struct S *b) { return i || b->l; }
+int od(int i, struct S *b) { return i || b->d; }
+
+int as(int i, struct S *b) { return i && b->s; }
+int au(int i, struct S *b) { return i && b->u; }
+int al(int i, struct S *b) { return i && b->l; }
+int ad(int i, struct S *b) { return i && b->d; }
+
+/*
+ * check-name: logical
+ * check-command: test-linearize -m64 -fdump-ir -Wno-decl $file
+ * check-assert: sizeof(void *) == 8 && sizeof(long) == 8 && sizeof(double) == 8
+ *
+ * check-output-start
+os:
+.L0:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r2 <- 0[i]
+	setne.1     %r3 <- %r2, $0
+	phisrc.32   %phi1 <- $1
+	cbr         %r3, .L3, .L2
+
+.L2:
+	load.64     %r4 <- 0[b]
+	load.32     %r5 <- 0[%r4]
+	lsr.32      %r6 <- %r5, $1
+	trunc.2     %r7 <- (32) %r6
+	setne.1     %r8 <- %r7, $0
+	zext.32     %r9 <- (1) %r8
+	phisrc.32   %phi2 <- %r9
+	br          .L3
+
+.L3:
+	phi.32      %r1 <- %phi1, %phi2
+	phisrc.32   %phi3(return) <- %r1
+	br          .L1
+
+.L1:
+	phi.32      %r10 <- %phi3(return)
+	ret.32      %r10
+
+
+ou:
+.L4:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r12 <- 0[i]
+	setne.1     %r13 <- %r12, $0
+	phisrc.32   %phi4 <- $1
+	cbr         %r13, .L7, .L6
+
+.L6:
+	load.64     %r14 <- 0[b]
+	load.32     %r15 <- 0[%r14]
+	lsr.32      %r16 <- %r15, $3
+	trunc.3     %r17 <- (32) %r16
+	setne.1     %r18 <- %r17, $0
+	zext.32     %r19 <- (1) %r18
+	phisrc.32   %phi5 <- %r19
+	br          .L7
+
+.L7:
+	phi.32      %r11 <- %phi4, %phi5
+	phisrc.32   %phi6(return) <- %r11
+	br          .L5
+
+.L5:
+	phi.32      %r20 <- %phi6(return)
+	ret.32      %r20
+
+
+ol:
+.L8:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r22 <- 0[i]
+	setne.1     %r23 <- %r22, $0
+	phisrc.32   %phi7 <- $1
+	cbr         %r23, .L11, .L10
+
+.L10:
+	load.64     %r24 <- 0[b]
+	load.64     %r25 <- 8[%r24]
+	setne.1     %r26 <- %r25, $0
+	zext.32     %r27 <- (1) %r26
+	phisrc.32   %phi8 <- %r27
+	br          .L11
+
+.L11:
+	phi.32      %r21 <- %phi7, %phi8
+	phisrc.32   %phi9(return) <- %r21
+	br          .L9
+
+.L9:
+	phi.32      %r28 <- %phi9(return)
+	ret.32      %r28
+
+
+od:
+.L12:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r30 <- 0[i]
+	setne.1     %r31 <- %r30, $0
+	phisrc.32   %phi10 <- $1
+	cbr         %r31, .L15, .L14
+
+.L14:
+	load.64     %r32 <- 0[b]
+	load.64     %r33 <- 16[%r32]
+	setfval.64  %r34 <- 0.000000e+00
+	fcmpune.1   %r35 <- %r33, %r34
+	zext.32     %r36 <- (1) %r35
+	phisrc.32   %phi11 <- %r36
+	br          .L15
+
+.L15:
+	phi.32      %r29 <- %phi10, %phi11
+	phisrc.32   %phi12(return) <- %r29
+	br          .L13
+
+.L13:
+	phi.32      %r37 <- %phi12(return)
+	ret.32      %r37
+
+
+as:
+.L16:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r39 <- 0[i]
+	setne.1     %r40 <- %r39, $0
+	phisrc.32   %phi13 <- $0
+	cbr         %r40, .L18, .L19
+
+.L18:
+	load.64     %r41 <- 0[b]
+	load.32     %r42 <- 0[%r41]
+	lsr.32      %r43 <- %r42, $1
+	trunc.2     %r44 <- (32) %r43
+	setne.1     %r45 <- %r44, $0
+	zext.32     %r46 <- (1) %r45
+	phisrc.32   %phi14 <- %r46
+	br          .L19
+
+.L19:
+	phi.32      %r38 <- %phi13, %phi14
+	phisrc.32   %phi15(return) <- %r38
+	br          .L17
+
+.L17:
+	phi.32      %r47 <- %phi15(return)
+	ret.32      %r47
+
+
+au:
+.L20:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r49 <- 0[i]
+	setne.1     %r50 <- %r49, $0
+	phisrc.32   %phi16 <- $0
+	cbr         %r50, .L22, .L23
+
+.L22:
+	load.64     %r51 <- 0[b]
+	load.32     %r52 <- 0[%r51]
+	lsr.32      %r53 <- %r52, $3
+	trunc.3     %r54 <- (32) %r53
+	setne.1     %r55 <- %r54, $0
+	zext.32     %r56 <- (1) %r55
+	phisrc.32   %phi17 <- %r56
+	br          .L23
+
+.L23:
+	phi.32      %r48 <- %phi16, %phi17
+	phisrc.32   %phi18(return) <- %r48
+	br          .L21
+
+.L21:
+	phi.32      %r57 <- %phi18(return)
+	ret.32      %r57
+
+
+al:
+.L24:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r59 <- 0[i]
+	setne.1     %r60 <- %r59, $0
+	phisrc.32   %phi19 <- $0
+	cbr         %r60, .L26, .L27
+
+.L26:
+	load.64     %r61 <- 0[b]
+	load.64     %r62 <- 8[%r61]
+	setne.1     %r63 <- %r62, $0
+	zext.32     %r64 <- (1) %r63
+	phisrc.32   %phi20 <- %r64
+	br          .L27
+
+.L27:
+	phi.32      %r58 <- %phi19, %phi20
+	phisrc.32   %phi21(return) <- %r58
+	br          .L25
+
+.L25:
+	phi.32      %r65 <- %phi21(return)
+	ret.32      %r65
+
+
+ad:
+.L28:
+	<entry-point>
+	store.32    %arg1 -> 0[i]
+	store.64    %arg2 -> 0[b]
+	load.32     %r67 <- 0[i]
+	setne.1     %r68 <- %r67, $0
+	phisrc.32   %phi22 <- $0
+	cbr         %r68, .L30, .L31
+
+.L30:
+	load.64     %r69 <- 0[b]
+	load.64     %r70 <- 16[%r69]
+	setfval.64  %r71 <- 0.000000e+00
+	fcmpune.1   %r72 <- %r70, %r71
+	zext.32     %r73 <- (1) %r72
+	phisrc.32   %phi23 <- %r73
+	br          .L31
+
+.L31:
+	phi.32      %r66 <- %phi22, %phi23
+	phisrc.32   %phi24(return) <- %r66
+	br          .L29
+
+.L29:
+	phi.32      %r74 <- %phi24(return)
+	ret.32      %r74
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:18 2019
+++ new/usr/src/tools/smatch/src/validation/linear/missing-return0.c	Mon Nov 18 13:20:18 2019
@@ -0,0 +1,10 @@
+static int foo(int a)
+{
+	if (a)
+		return 1;
+}
+
+/*
+ * check-name: missing-return0
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:18 2019
+++ new/usr/src/tools/smatch/src/validation/linear/missing-return1.c	Mon Nov 18 13:20:18 2019
@@ -0,0 +1,15 @@
+static inline int fun(int a)
+{
+	if (a)
+		return 1;
+}
+
+static int foo(int a)
+{
+	return fun(a);
+}
+
+/*
+ * check-name: missing-return1
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:19 2019
+++ new/usr/src/tools/smatch/src/validation/linear/missing-return2.c	Mon Nov 18 13:20:19 2019
@@ -0,0 +1,11 @@
+static int foo(int a)
+{
+	switch (a)
+	case 3:
+		return 4;
+}
+
+/*
+ * check-name: missing-return2
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:19 2019
+++ new/usr/src/tools/smatch/src/validation/linear/missing-return3.c	Mon Nov 18 13:20:19 2019
@@ -0,0 +1,18 @@
+static int foo(int a)
+{
+	if (a)
+		return;
+}
+
+static void ref(void)
+{
+}
+
+/*
+ * check-name: missing-return3
+ * check-command: sparse -vir -flinearize=last $file
+ *
+ * check-error-start
+linear/missing-return3.c:4:17: error: return with no return value
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:19 2019
+++ new/usr/src/tools/smatch/src/validation/linear/missing-return4.c	Mon Nov 18 13:20:19 2019
@@ -0,0 +1,14 @@
+static int foo(int a)
+{
+	int r = a;
+	r;
+}
+
+/*
+ * check-name: missing-return4
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-contains: ret\\..*UNDEF
+ */
--- /dev/null	Mon Nov 18 13:20:19 2019
+++ new/usr/src/tools/smatch/src/validation/linear/missing-return5.c	Mon Nov 18 13:20:19 2019
@@ -0,0 +1,23 @@
+int foo(int p)
+{
+	if (p)
+		return 0;
+}
+
+int bar(int p)
+{
+	if (p)
+		return 0;
+	p++;
+}
+
+/*
+ * check-name: missing/undef return
+ * check-command: test-linearize -Wno-decl -fdump-ir=linearize $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): phi\\..*,.*
+ * check-output-pattern(2): phisrc\\..*\\$0
+ * check-output-pattern(2): phisrc\\..*UNDEF
+ * check-output-excludes: ret\\..*\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:19 2019
+++ new/usr/src/tools/smatch/src/validation/linear/non-const-case.c	Mon Nov 18 13:20:19 2019
@@ -0,0 +1,37 @@
+static int foo(int a)
+{
+	switch (a) {
+	case 0:
+		return a;
+	case a:
+		return 0;
+	case (a - a):
+		return 1;
+	default:
+		return a;
+	}
+}
+
+static int bar(int a)
+{
+	switch (a) {
+	case 0:
+		break;
+	case a:
+		a++;
+label:
+		return a;
+	}
+
+	goto label;
+}
+
+
+/*
+ * check-name: non-const-case
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes:switch \\.
+ */
--- /dev/null	Mon Nov 18 13:20:19 2019
+++ new/usr/src/tools/smatch/src/validation/linear/phi-order01.c	Mon Nov 18 13:20:19 2019
@@ -0,0 +1,16 @@
+int fun(void);
+
+static int foo(int a)
+{
+	return a && fun();
+}
+
+static int bar(int a)
+{
+	return a || fun();
+}
+
+/*
+ * check-name: phi-order01
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:19 2019
+++ new/usr/src/tools/smatch/src/validation/linear/phi-order02.c	Mon Nov 18 13:20:19 2019
@@ -0,0 +1,16 @@
+int fun(void);
+
+static int foo(int a) { return 0 || fun(); }
+static int bar(int a) { return 1 || fun(); }
+static int baz(int a) { return 0 && fun(); }
+static int qux(int a) { return 1 && fun(); }
+
+static int oof(int a) { return fun() || 1; }
+static int rab(int a) { return fun() || 0; }
+static int zab(int a) { return fun() && 1; }
+static int xuq(int a) { return fun() && 0; }
+
+/*
+ * check-name: phi-order02
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:20 2019
+++ new/usr/src/tools/smatch/src/validation/linear/phi-order03.c	Mon Nov 18 13:20:20 2019
@@ -0,0 +1,8 @@
+int fun(void);
+
+static int foo(void) { return ((0 || fun()) && fun()); }
+
+/*
+ * check-name: phi-order03
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:20 2019
+++ new/usr/src/tools/smatch/src/validation/linear/phi-order04.c	Mon Nov 18 13:20:20 2019
@@ -0,0 +1,12 @@
+static void foo(int *b)
+{
+	if (1) {
+		int c;
+		b = &c;
+	}
+}
+
+/*
+ * check-name: phi-order04
+ * check-command: sparse -vir -flinearize=last $file
+ */
--- /dev/null	Mon Nov 18 13:20:20 2019
+++ new/usr/src/tools/smatch/src/validation/linear/range-op.c	Mon Nov 18 13:20:20 2019
@@ -0,0 +1,31 @@
+static void foo(int a)
+{
+	__range__(a, 0, 8);
+}
+
+static void bar(int a, int b, int c)
+{
+	__range__(a, b, c);
+}
+
+/*
+ * check-name: range-op
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	range-check %arg1 between $0..$8
+	ret
+
+
+bar:
+.L2:
+	<entry-point>
+	range-check %arg1 between %arg2..%arg3
+	ret
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:20 2019
+++ new/usr/src/tools/smatch/src/validation/linear/unexamined-base-type.c	Mon Nov 18 13:20:20 2019
@@ -0,0 +1,36 @@
+# define __force	__attribute__((force))
+
+struct s {
+	int a;
+};
+
+static int foo(struct s *s)
+{
+	return (*((typeof(s->a) __force *) &s->a)) & 1;
+}
+
+static void bar(struct s *d, struct s *s1, struct s *s2)
+{
+	*d = *s1, *d = *s2;
+}
+
+/*
+ * check-name: unexamined base type
+ * check-command: test-linearize -Wno-decl $file
+ * check-description:
+ *	Test case for missing examine in evaluate_dereference()'s
+ *	target base type. In this case, the loaded value has a
+ *	a null size, giving the wrongly generated code for foo():
+ *		ptrcast.64  %r3 <- (64) %arg1
+ *		load        %r4 <- 0[%r3]
+ *		    ^^^				!! WRONG !!
+ *		cast.32     %r5 <- (0) %r4
+ *		                   ^^^		!! WRONG !!
+ *		and.32      %r6 <- %r5, $1
+ *		ret.32      %r6
+ *
+ * check-output-ignore
+ * check-output-excludes: load[^.]
+ * check-output-excludes: cast\\..*(0)
+ * check-output-excludes: store[^.]
+ */
--- /dev/null	Mon Nov 18 13:20:20 2019
+++ new/usr/src/tools/smatch/src/validation/linear/unreachable-label0.c	Mon Nov 18 13:20:20 2019
@@ -0,0 +1,19 @@
+static int foo(int a)
+{
+	goto label;
+	switch(a) {
+	default:
+label:
+		break;
+	}
+	return 0;
+}
+
+/*
+ * check-name: unreachable-label0
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\.
+ * check-output-excludes: END
+ */
--- old/usr/src/tools/smatch/src/validation/loop-linearization.c	Mon Nov 18 13:20:20 2019
+++ /dev/null	Mon Nov 18 13:20:20 2019
@@ -1,136 +0,0 @@
-extern int p(int);
-
-static int ffor(void)
-{
-	int i;
-	for (int i = 0; i < 10; i++) {
-		if (!p(i))
-			return 0;
-	}
-	return 1;
-}
-
-static int fwhile(void)
-{
-	int i = 0;
-	while (i < 10) {
-		if (!p(i))
-			return 0;
-		i++;
-	}
-	return 1;
-}
-
-static int fdo(void)
-{
-	int i = 0;
-	do {
-		if (!p(i))
-			return 0;
-	} while (i++ < 10);
-	return 1;
-}
-
-/*
- * check-name: loop-linearization
- * check-command: test-linearize $file
- *
- * check-output-start
-ffor:
-.L0:
-	<entry-point>
-	phisrc.32   %phi5(i) <- $0
-	br          .L4
-
-.L4:
-	phi.32      %r1(i) <- %phi5(i), %phi6(i)
-	setlt.32    %r2 <- %r1(i), $10
-	cbr         %r2, .L1, .L3
-
-.L1:
-	call.32     %r4 <- p, %r1(i)
-	cbr         %r4, .L2, .L5
-
-.L5:
-	phisrc.32   %phi1(return) <- $0
-	br          .L7
-
-.L2:
-	add.32      %r7 <- %r1(i), $1
-	phisrc.32   %phi6(i) <- %r7
-	br          .L4
-
-.L3:
-	phisrc.32   %phi2(return) <- $1
-	br          .L7
-
-.L7:
-	phi.32      %r5 <- %phi1(return), %phi2(return)
-	ret.32      %r5
-
-
-fwhile:
-.L8:
-	<entry-point>
-	phisrc.32   %phi11(i) <- $0
-	br          .L12
-
-.L12:
-	phi.32      %r8(i) <- %phi11(i), %phi12(i)
-	setlt.32    %r9 <- %r8(i), $10
-	cbr         %r9, .L9, .L11
-
-.L9:
-	call.32     %r11 <- p, %r8(i)
-	cbr         %r11, .L14, .L13
-
-.L13:
-	phisrc.32   %phi7(return) <- $0
-	br          .L15
-
-.L14:
-	add.32      %r14 <- %r8(i), $1
-	phisrc.32   %phi12(i) <- %r14
-	br          .L12
-
-.L11:
-	phisrc.32   %phi8(return) <- $1
-	br          .L15
-
-.L15:
-	phi.32      %r12 <- %phi7(return), %phi8(return)
-	ret.32      %r12
-
-
-fdo:
-.L16:
-	<entry-point>
-	phisrc.32   %phi16(i) <- $0
-	br          .L17
-
-.L17:
-	phi.32      %r15(i) <- %phi16(i), %phi17(i)
-	call.32     %r16 <- p, %r15(i)
-	cbr         %r16, .L18, .L20
-
-.L20:
-	phisrc.32   %phi13(return) <- $0
-	br          .L22
-
-.L18:
-	add.32      %r19 <- %r15(i), $1
-	setlt.32    %r20 <- %r15(i), $10
-	phisrc.32   %phi17(i) <- %r19
-	cbr         %r20, .L17, .L19
-
-.L19:
-	phisrc.32   %phi14(return) <- $1
-	br          .L22
-
-.L22:
-	phi.32      %r17 <- %phi13(return), %phi14(return)
-	ret.32      %r17
-
-
- * check-output-end
- */
--- /dev/null	Mon Nov 18 13:20:21 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/address-used00.c	Mon Nov 18 13:20:21 2019
@@ -0,0 +1,18 @@
+int foo(int **g, int j)
+{
+	int i = 1;
+	int *a;
+	int **p;
+
+	a = &i;
+	p = &a;
+	*p[0] = 0;
+	return i;
+}
+
+/*
+ * check-name: address-used00
+ * check-command: test-linearize -Wno-decl -fdump-ir=final $file
+ * check-output-ignore
+ * check-output-excludes: ret\\..* \\$1
+ */
--- old/usr/src/tools/smatch/src/validation/alias-distinct.c	Mon Nov 18 13:20:21 2019
+++ /dev/null	Mon Nov 18 13:20:21 2019
@@ -1,17 +0,0 @@
-extern int g;
-extern int h;
-
-static int foo(void)
-{
-	g = 1;
-	h = 2;
-	return g == 1;
-}
-
-/*
- * check-name: alias distinct symbols
- * check-command: test-linearize $file
- * check-output-ignore
- *
- * check-output-contains: ret\\..* *\\$1
- */
--- /dev/null	Mon Nov 18 13:20:21 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/alias-distinct.c	Mon Nov 18 13:20:21 2019
@@ -0,0 +1,17 @@
+extern int g;
+extern int h;
+
+static int foo(void)
+{
+	g = 1;
+	h = 2;
+	return g == 1;
+}
+
+/*
+ * check-name: alias distinct symbols
+ * check-command: test-linearize $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..* *\\$1
+ */
--- old/usr/src/tools/smatch/src/validation/alias-mixed.c	Mon Nov 18 13:20:21 2019
+++ /dev/null	Mon Nov 18 13:20:21 2019
@@ -1,30 +0,0 @@
-extern int g;
-
-
-static int foo(int *p)
-{
-	*p = 1;
-	g = 2;
-	return *p == 1;
-}
-
-static int bar(int *p)
-{
-	g = 1;
-	*p = 2;
-	return g == 1;
-}
-
-static void test(void)
-{
-	foo(&g);
-	bar(&g);
-}
-
-/*
- * check-name: alias symbol/pointer
- * check-command: test-linearize $file
- * check-output-ignore
- *
- * check-output-excludes: ret\\..* *\\$1
- */
--- /dev/null	Mon Nov 18 13:20:21 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/alias-mixed.c	Mon Nov 18 13:20:21 2019
@@ -0,0 +1,30 @@
+extern int g;
+
+
+static int foo(int *p)
+{
+	*p = 1;
+	g = 2;
+	return *p == 1;
+}
+
+static int bar(int *p)
+{
+	g = 1;
+	*p = 2;
+	return g == 1;
+}
+
+static void test(void)
+{
+	foo(&g);
+	bar(&g);
+}
+
+/*
+ * check-name: alias symbol/pointer
+ * check-command: test-linearize $file
+ * check-output-ignore
+ *
+ * check-output-excludes: ret\\..* *\\$1
+ */
--- old/usr/src/tools/smatch/src/validation/alias-same.c	Mon Nov 18 13:20:21 2019
+++ /dev/null	Mon Nov 18 13:20:21 2019
@@ -1,17 +0,0 @@
-extern int g;
-
-
-static int foo(void)
-{
-	g = 1;
-	g = 2;
-	return g != 1;
-}
-
-/*
- * check-name: alias same symbols
- * check-command: test-linearize $file
- * check-output-ignore
- *
- * check-output-contains: ret\\..* *\\$1
- */
--- /dev/null	Mon Nov 18 13:20:21 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/alias-same.c	Mon Nov 18 13:20:21 2019
@@ -0,0 +1,17 @@
+extern int g;
+
+
+static int foo(void)
+{
+	g = 1;
+	g = 2;
+	return g != 1;
+}
+
+/*
+ * check-name: alias same symbols
+ * check-command: test-linearize $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..* *\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:21 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/broken-phi02.c	Mon Nov 18 13:20:21 2019
@@ -0,0 +1,27 @@
+int foo(int a, int b)
+{
+	int x;
+	int i;
+
+	if (a)
+		i = 0;
+	else
+		i = 1;
+
+	x = 0;
+	if (b)
+		x = i;
+	return x;
+}
+
+/*
+ * check-name: broken-phi02
+ * check-description:
+ *	This is an indirect test to check correctness of phi-node placement.
+ *	The misplaced phi-node for 'i' (not at the meet point but where 'i'
+ *	is used) causes a missed select-conversion at later stage.
+ *
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ * check-output-contains: select\\.
+ */
--- /dev/null	Mon Nov 18 13:20:21 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/broken-phi03.c	Mon Nov 18 13:20:21 2019
@@ -0,0 +1,28 @@
+int foo(int a, int b)
+{
+	int x;
+	int i;
+
+	switch (a) {
+	case  0: i = 0; break;
+	case  1: i = 1; break;
+	default: i = -1; break;
+	}
+
+	x = 0;
+	if (b)
+		x = i;
+	return x;
+}
+
+/*
+ * check-name: broken-phi03
+ * check-description:
+ *	This is an indirect test to check correctness of phi-node placement.
+ *	The misplaced phi-node for 'i' (not at the meet point but where 'i'
+ *	is used) causes a missed select-conversion at later stage.
+ *
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ * check-output-contains: select\\.
+ */
--- /dev/null	Mon Nov 18 13:20:22 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/cond-expr.c	Mon Nov 18 13:20:22 2019
@@ -0,0 +1,14 @@
+int fun(int);
+
+int foo(int a, int b, int c)
+{
+	return a ? fun(b) : fun(c);
+}
+
+/*
+ * check-name: cond-expr
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(2): phi\\.
+ * check-output-pattern(3): phisrc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:22 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/cond-expr5.c	Mon Nov 18 13:20:22 2019
@@ -0,0 +1,21 @@
+int foo(int p, int q, int a)
+{
+	if (p)
+		a = 0;
+	if (q)
+		a = 1;
+
+	return a;
+}
+
+/*
+ * check-name: cond-expr5
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ * check-output-excludes: store\\.
+ * check-output-excludes: phi\\..*, .*, .*
+ * check-output-pattern(3): phi\\.
+ * check-output-pattern(5): phisrc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:22 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/dead-phisrc.c	Mon Nov 18 13:20:22 2019
@@ -0,0 +1,17 @@
+static void foo(void)
+{
+	extern int *a;
+
+	if (a || *a)
+		;
+	if (a[0] || a[1])
+		;
+}
+
+/*
+ * check-name: dead-phisrc
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: phisrc
+ */
--- /dev/null	Mon Nov 18 13:20:22 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/global-direct-undef.c	Mon Nov 18 13:20:22 2019
@@ -0,0 +1,23 @@
+int a, c, d;
+
+int foo(void)
+{
+	int b, e;
+	if (a)
+		b = c;
+	else
+		b = d;
+	if (c)
+		a = b;
+	if (b)
+		e = a;
+	return e;
+}
+
+/*
+ * check-name: global direct undef
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(4,5): load\\.
+ * check-output-pattern(1): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:22 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/global-direct.c	Mon Nov 18 13:20:22 2019
@@ -0,0 +1,23 @@
+int a, c, d;
+
+int foo(void)
+{
+	int b, e = 0;
+	if (a)
+		b = c;
+	else
+		b = d;
+	if (c)
+		a = b;
+	if (b)
+		e = a;
+	return e;
+}
+
+/*
+ * check-name: global direct
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(4,5): load\\.
+ * check-output-pattern(1): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:22 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/global-loop.c	Mon Nov 18 13:20:22 2019
@@ -0,0 +1,20 @@
+struct s {
+	int c;
+	int a[];
+} s;
+int f;
+
+void fun(void);
+void foo(void)
+{
+	for (f = 1;;)
+		if (s.a[f])
+			fun();
+}
+
+/*
+ * check-name: global var as loop index
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-contains: load\\..*\\[f\\]
+ */
--- /dev/null	Mon Nov 18 13:20:22 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/global-noalias.c	Mon Nov 18 13:20:22 2019
@@ -0,0 +1,21 @@
+int a, b, c, d, e;
+
+void foo(void)
+{
+	if (a)
+		b = c;
+	else
+		b = d;
+	if (c)
+		a = b;
+	if (b)
+		e = a;
+}
+
+/*
+ * check-name: global no-alias
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(4,7): load\\.
+ * check-output-pattern(4): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:23 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/global-pointer.c	Mon Nov 18 13:20:23 2019
@@ -0,0 +1,26 @@
+int a, c, d;
+
+int foo_ptr(void)
+{
+	int b, *bp = &b;
+	int e, *ep = &e;
+
+	if (a)
+		*bp = c;
+	else
+		*bp = d;
+	if (c)
+		a = *bp;
+	if (b)
+		e = a;
+	return e;
+}
+
+/*
+ * check-name: global pointer
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-known-to-fail
+ * check-output-ignore
+ * check-output-pattern(4,5): load\\.
+ * check-output-pattern(3): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:23 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/if-direct.c	Mon Nov 18 13:20:23 2019
@@ -0,0 +1,19 @@
+int foo(int c, int a, int b)
+{
+	int l;
+
+	if (c)
+		l = a;
+	else
+		l = b;
+
+	return l;
+}
+
+/*
+ * check-name: if-then-else direct
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ * check-output-contains: phi\\.
+ */
--- /dev/null	Mon Nov 18 13:20:23 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/if-pointer.c	Mon Nov 18 13:20:23 2019
@@ -0,0 +1,21 @@
+int foo(int c, int a, int b)
+{
+	int l, *p = &l;
+
+	if (c)
+		*p = a;
+	else
+		*p = b;
+
+	return l + *p;
+}
+
+/*
+ * check-name: if-then-else pointer
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-known-to-fail
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ * check-output-excludes: store\\.
+ * check-output-contains: phi\\.
+ */
--- /dev/null	Mon Nov 18 13:20:23 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/init-global-array.c	Mon Nov 18 13:20:23 2019
@@ -0,0 +1,21 @@
+struct s {
+	int a[2];
+};
+
+
+static struct s s;
+
+static int sarray(void)
+{
+	s.a[1] = 1;
+	return s.a[1];
+}
+
+/*
+ * check-name: init global array
+ * check-command: test-linearize $file
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ * check-output-pattern(1): store\\.
+ * check-output-pattern(1): ret.32 *\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:23 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/init-local-array.c	Mon Nov 18 13:20:23 2019
@@ -0,0 +1,28 @@
+static int array(void)
+{
+	int a[2];
+
+	a[1] = 1;
+	a[0] = 0;
+	return a[1];
+}
+
+static int sarray(void)
+{
+	struct {
+		int a[2];
+	} s;
+
+	s.a[1] = 1;
+	s.a[0] = 0;
+	return s.a[1];
+}
+
+/*
+ * check-name: init local array
+ * check-command: test-linearize $file
+ * check-output-ignore
+ * check-output-excludes: load
+ * check-output-excludes: store
+ * check-output-pattern(2): ret.32 *\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:23 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/init-local-union0.c	Mon Nov 18 13:20:23 2019
@@ -0,0 +1,18 @@
+double uintfloat(void)
+{
+	union {
+		int a;
+		double f;
+	} s;
+
+	s.a = 1;
+	return s.f;
+}
+
+/*
+ * check-name: init-local union 0
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(1): store\\.32
+ * check-output-pattern(1): load\\.64
+ */
--- /dev/null	Mon Nov 18 13:20:24 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/init-local-union1.c	Mon Nov 18 13:20:24 2019
@@ -0,0 +1,32 @@
+double uintfloat(void)
+{
+	union {
+		int a;
+		double f;
+	} s;
+
+	s.a = 1;
+	return s.f;
+}
+
+
+int uarray(void)
+{
+	union {
+		double d;
+		int a[2];
+	} s;
+
+	s.d = 1;
+	return s.a[0];
+}
+
+/*
+ * check-name: init-local union 1
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(1): store\\.32
+ * check-output-pattern(1): load\\.64
+ * check-output-pattern(1): store\\.64
+ * check-output-pattern(1): load\\.32
+ */
--- /dev/null	Mon Nov 18 13:20:24 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/init-local32.c	Mon Nov 18 13:20:24 2019
@@ -0,0 +1,27 @@
+int ssimple(void)
+{
+	struct {
+		int a;
+	} s;
+
+	s.a = 1;
+	return s.a;
+}
+
+double sdouble(void)
+{
+	struct {
+		double a;
+	} s;
+
+	s.a = 1.23;
+	return s.a;
+}
+
+/*
+ * check-name: init-local32
+ * check-command: test-linearize -Wno-decl -m32 -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ * check-output-excludes: store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:24 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/init-local64.c	Mon Nov 18 13:20:24 2019
@@ -0,0 +1,27 @@
+int ssimple(void)
+{
+	struct {
+		int a;
+	} s;
+
+	s.a = 1;
+	return s.a;
+}
+
+double sdouble(void)
+{
+	struct {
+		double a;
+	} s;
+
+	s.a = 1.23;
+	return s.a;
+}
+
+/*
+ * check-name: init-local64
+ * check-command: test-linearize -Wno-decl -m64 -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ * check-output-excludes: store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:24 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/load-dead.c	Mon Nov 18 13:20:24 2019
@@ -0,0 +1,18 @@
+int fun(int);
+
+static inline int fake(void)
+{
+}
+
+static void foo(int a)
+{
+	0 || fun((a, fake(), a));
+}
+
+/*
+ * check-name: load-dead
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: VOID
+ */
--- /dev/null	Mon Nov 18 13:20:24 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/load-deadborn.c	Mon Nov 18 13:20:24 2019
@@ -0,0 +1,9 @@
+static void foo(int a)
+{
+	return;
+	a;
+}
+
+/*
+ * check-name: load-deadborn
+ */
--- /dev/null	Mon Nov 18 13:20:24 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/loop00.c	Mon Nov 18 13:20:24 2019
@@ -0,0 +1,16 @@
+int loop00(int n)
+{
+	int i, r = 0;
+
+	for (i = 1; i <= n; ++i)
+		r += i;
+	return r;
+}
+
+/*
+ * check-name: loop00
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-excludes: store\\.
+ * check-output-excludes: load\\.
+ */
--- /dev/null	Mon Nov 18 13:20:24 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/loop01-global.c	Mon Nov 18 13:20:24 2019
@@ -0,0 +1,18 @@
+extern int g;
+
+void fun(void);
+void loop01(void)
+{
+	int i;
+	for (i = 0; i <= 2;)
+		if (g)
+			fun();
+}
+
+/*
+ * check-name: loop01 global
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-excludes: load\\..*\\[i\\]
+ * check-output-contains: load\\..*\\[g\\]
+ */
--- /dev/null	Mon Nov 18 13:20:25 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/loop02-array.c	Mon Nov 18 13:20:25 2019
@@ -0,0 +1,23 @@
+
+
+int foo(int i[])
+{
+	int j = 1;
+	i[0] = 6;
+
+	do {
+		if (i[0] != 6)
+			i[0]++;
+		i[0]++;
+	} while (i[0] != j);
+
+	return j;
+}
+
+/*
+ * check-name: loop02 array
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(0,4): load\\.
+ * check-output-pattern(1,3): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:25 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/loop02-global.c	Mon Nov 18 13:20:25 2019
@@ -0,0 +1,22 @@
+int i;
+
+int foo(void)
+{
+	int j = 1;
+	i = 6;
+
+	do {
+		if (i != 6)
+			i++;
+		i++;
+	} while (i != j);
+
+	return j;
+}
+
+/*
+ * check-name: loop02 global
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ */
--- /dev/null	Mon Nov 18 13:20:25 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/loop02-local.c	Mon Nov 18 13:20:25 2019
@@ -0,0 +1,23 @@
+
+
+int foo(void)
+{
+	int j = 1;
+	int i = 6;
+
+	do {
+		if (i != 6)
+			i++;
+		i++;
+	} while (i != j);
+
+	return j;
+}
+
+/*
+ * check-name: loop02 pointer
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ *
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ */
--- /dev/null	Mon Nov 18 13:20:25 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/loop02-pointer.c	Mon Nov 18 13:20:25 2019
@@ -0,0 +1,23 @@
+
+
+int foo(int *i)
+{
+	int j = 1;
+	*i = 6;
+
+	do {
+		if (*i != 6)
+			(*i)++;
+		(*i)++;
+	} while (*i != j);
+
+	return j;
+}
+
+/*
+ * check-name: loop02 pointer
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(0,4): load\\.
+ * check-output-pattern(1,3): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:25 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/missing-return.c	Mon Nov 18 13:20:25 2019
@@ -0,0 +1,34 @@
+int f1(void)
+{
+	if (1)
+		return 1;
+}
+
+int f0(void)
+{
+	if (0)
+		return 0;
+}
+
+int fx(int p)
+{
+	if (p)
+		return 0;
+}
+
+int bar(int p)
+{
+	if (p)
+		return 0;
+	p++;
+}
+
+/*
+ * check-name: missing-return
+ * check-command: test-linearize -m32 -fdump-ir=mem2reg -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(1): ret.32 *\\$1
+ * check-output-pattern(3): ret.32 *UNDEF
+ */
--- /dev/null	Mon Nov 18 13:20:25 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/quadra00.c	Mon Nov 18 13:20:25 2019
@@ -0,0 +1,27 @@
+#define	TEST(N)			\
+	do {			\
+		d = b + a[N];	\
+		if (d < b)	\
+			c++;	\
+		b = d;		\
+	} while (0)
+
+int foo(int *a, int b, int c)
+{
+	int d;
+
+	TEST(0);
+	TEST(1);
+	TEST(2);
+
+	return d + c;
+}
+
+/*
+ * check-name: quadratic phisrc
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ * check-output-excludes: phi\\..*, .*, .*
+ * check-output-excludes: phi\\..*, .*, .*, .*
+ * check-output-pattern(6): phisrc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:25 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/quadra01.c	Mon Nov 18 13:20:25 2019
@@ -0,0 +1,27 @@
+#include "repeat.h"
+
+void use(void *, void *, void *, void *);
+void *def(void);
+
+#define BLOCK(n) {				\
+	void *label;				\
+	use(&&w##n, &&x##n, &&y##n, &&z##n);	\
+w##n:	label = def(); goto *label;		\
+x##n:	label = def(); goto *label;		\
+y##n:	label = def(); goto *label;		\
+z##n:	label = def(); goto *label;		\
+}
+
+static void foo(void) {
+	REPEAT2(5, BLOCK)
+}
+
+/*
+ * check-name: quadratic @ liveness
+ * check-command: test-linearize -I. $file
+ * check-timeout:
+ *
+ * check-output-ignore
+ * check-output-excludes: phi\\.
+ * check-output-excludes: phisrc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:26 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/quadra02.c	Mon Nov 18 13:20:26 2019
@@ -0,0 +1,18 @@
+#include "repeat.h"
+
+#define	PAT(X)	int a##X = X;
+static void foo(void)
+{
+	REPEAT2(12, PAT)
+}
+
+/*
+ * check-name: quadratic vars
+ * check-command: test-linearize -I. $file
+ * check-timeout:
+ *
+ * check-output-ignore
+ * check-output-excludes: phi\\.
+ * check-output-excludes: phisrc\\.
+ * check-output-excludes: store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:26 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/reload-aliasing.c	Mon Nov 18 13:20:26 2019
@@ -0,0 +1,41 @@
+extern int g, h;
+
+void f00(int *s)
+{
+	g = *s;
+	h = *s;
+}
+
+void f01(int *a, int *b, int *s)
+{
+	*a = *s;
+	*b = *s;
+}
+
+/*
+ * check-name: reload-aliasing.c
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+f00:
+.L0:
+	<entry-point>
+	load.32     %r2 <- 0[%arg1]
+	store.32    %r2 -> 0[g]
+	load.32     %r4 <- 0[%arg1]
+	store.32    %r4 -> 0[h]
+	ret
+
+
+f01:
+.L2:
+	<entry-point>
+	load.32     %r6 <- 0[%arg3]
+	store.32    %r6 -> 0[%arg1]
+	load.32     %r9 <- 0[%arg3]
+	store.32    %r9 -> 0[%arg2]
+	ret
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:26 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/short-load.c	Mon Nov 18 13:20:26 2019
@@ -0,0 +1,29 @@
+#ifdef __SIZEOF_INT__ == 4
+typedef unsigned int u32;
+#endif
+#ifdef __SIZEOF_SHORT__ == 2
+typedef unsigned short u16;
+#endif
+
+
+union u {
+	u32	a;
+	u16	b;
+};
+
+void bar(u16, union u);
+
+void foo(u16 val)
+{
+	union u u;
+
+	u.b = val;
+	bar(u.b, u);
+}
+
+/*
+ * check-name: short-load
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-contains: load\\.32
+ */
--- /dev/null	Mon Nov 18 13:20:26 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/store-deadborn.c	Mon Nov 18 13:20:26 2019
@@ -0,0 +1,9 @@
+static void foo(int a)
+{
+	return;
+	a = 0;
+}
+
+/*
+ * check-name: store-deadborn
+ */
--- /dev/null	Mon Nov 18 13:20:26 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/stray-phisrc.c	Mon Nov 18 13:20:26 2019
@@ -0,0 +1,24 @@
+static int foo(int **g)
+{
+	int i = 1;
+	int *a[2];
+	int **p;
+
+	a[1] = &i;
+	if (g)
+		p = g;
+	else
+		p = &a[0];
+	p += 1;			// will point to a[1] = &i
+	if (!g)
+		**p = 0;
+	return i;
+}
+
+/*
+ * check-name: stray phisrc
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: phisrc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:26 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/struct.c	Mon Nov 18 13:20:26 2019
@@ -0,0 +1,32 @@
+struct s {
+	int a;
+	int b;
+};
+
+int f0(void)
+{
+	struct s s;
+
+	s.a = 0;
+	s.b = 1;
+
+	return s.a;
+}
+
+int f1(void)
+{
+	struct s s;
+
+	s.a = 1;
+	s.b = 0;
+
+	return s.b;
+}
+
+/*
+ * check-name: struct
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): ret.32 *\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:26 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/undef00.c	Mon Nov 18 13:20:26 2019
@@ -0,0 +1,21 @@
+static int badr(void)
+{
+	int *a;
+	return *a;
+}
+
+static void badw(int v)
+{
+	int *a;
+	*a = v;
+}
+
+/*
+ * check-name: undef00
+ * check-command: test-linearize -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(1): load\\.
+ * check-output-pattern(1): load\\..*\\[UNDEF\\]
+ * check-output-pattern(1): store\\.
+ * check-output-pattern(1): store\\..*\\[UNDEF\\]
+ */
--- /dev/null	Mon Nov 18 13:20:27 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/undef01.c	Mon Nov 18 13:20:27 2019
@@ -0,0 +1,16 @@
+static void foo(void)
+{
+	int *b;
+	for (;;)
+		*b++ = 0;
+}
+
+/*
+ * check-name: undef01
+ * check-command: sparse -Wmaybe-uninitialized $file
+ * check-known-to-fail
+ *
+ * check-error-start
+crazy04.c:3:13: warning: variable 'b' may be uninitialized
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:27 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/unused-var.c	Mon Nov 18 13:20:27 2019
@@ -0,0 +1,23 @@
+int foo(int a)
+{
+	switch (a) {
+		int u = 1;
+
+	default:
+		return a;
+	}
+}
+
+/*
+ * check-name: unused-var
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	ret.32      %arg1
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:27 2019
+++ new/usr/src/tools/smatch/src/validation/mem2reg/volatile-store00.c	Mon Nov 18 13:20:27 2019
@@ -0,0 +1,27 @@
+void foo(volatile int *p)
+{
+	*p = 0;
+	*p = 0;
+}
+
+void bar(void)
+{
+	extern volatile int i;
+	i = 0;
+	i = 0;
+}
+
+
+void baz(void)
+{
+	volatile int i;
+	i = 0;
+	i = 0;
+}
+
+/*
+ * check-name: keep volatile stores
+ * check-command: test-linearize -Wno-decl -fdump-ir=mem2reg $file
+ * check-output-ignore
+ * check-output-pattern(1,6): store\\.
+ */
--- old/usr/src/tools/smatch/src/validation/memops-volatile.c	Mon Nov 18 13:20:27 2019
+++ new/usr/src/tools/smatch/src/validation/memops-volatile.c	Mon Nov 18 13:20:27 2019
@@ -1,6 +1,7 @@
 static int foo(volatile int *a, int v)
 {
 	*a = v;
+	*a = 0;
 	return *a;
 }
 
@@ -8,14 +9,8 @@
  * check-name: memops-volatile
  * check-command: test-linearize $file
  *
- * check-output-start
-foo:
-.L0:
-	<entry-point>
-	store.32    %arg2 -> 0[%arg1]
-	load.32     %r5 <- 0[%arg1]
-	ret.32      %r5
-
-
- * check-output-end
+ * check-output-ignore
+ * check-output-contains: store\\..*%arg2 -> 0\\[%arg1]
+ * check-output-contains: store\\..*\\$0 -> 0\\[%arg1]
+ * check-output-contains: load\\..*%r.* <- 0\\[%arg1]
  */
--- /dev/null	Mon Nov 18 13:20:27 2019
+++ new/usr/src/tools/smatch/src/validation/missing-return.c	Mon Nov 18 13:20:27 2019
@@ -0,0 +1,20 @@
+int foo(int a)
+{
+}
+
+int bar(int a)
+{
+	if (a)
+		return 0;
+}
+
+/*
+ * check-name: missing return
+ * check-command: sparse -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-error-start
+missing-return.c:3:1: warning: control reaches end of non-void function
+missing-return.c:9:1: warning: control reaches end of non-void function
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:27 2019
+++ new/usr/src/tools/smatch/src/validation/multi-input.c	Mon Nov 18 13:20:27 2019
@@ -0,0 +1,11 @@
+int a = 1;
+int foo(void) {}
+
+static int b = 1;
+static int bar(void) {}
+
+/*
+ * check-name: multi-input
+ * check-command: sparse -Wno-decl $file $file
+ * check-known-to-fail
+ */
--- old/usr/src/tools/smatch/src/validation/nested-declarator.c	Mon Nov 18 13:20:28 2019
+++ new/usr/src/tools/smatch/src/validation/nested-declarator.c	Mon Nov 18 13:20:28 2019
@@ -15,7 +15,7 @@
 int j(int [2](*));
 /*
  * check-name: nested declarator vs. parameters
- * check-error-start:
+ * check-error-start
 nested-declarator.c:11:23: warning: missing identifier in declaration
 nested-declarator.c:11:23: error: Expected ; at the end of type declaration
 nested-declarator.c:11:23: error: got (
@@ -25,5 +25,5 @@
 nested-declarator.c:14:18: error: got (
 nested-declarator.c:15:14: error: Expected ) in function declarator
 nested-declarator.c:15:14: error: got (
- * check-error-end:
+ * check-error-end
  */
--- old/usr/src/tools/smatch/src/validation/nested-declarator2.c	Mon Nov 18 13:20:28 2019
+++ new/usr/src/tools/smatch/src/validation/nested-declarator2.c	Mon Nov 18 13:20:28 2019
@@ -27,7 +27,7 @@
 static void [2](*bad3);
 /*
  * check-name: more on handling of ( in direct-declarator
- * check-error-start:
+ * check-error-start
 nested-declarator2.c:17:1: warning: non-ANSI definition of function 'w1'
 nested-declarator2.c:21:21: warning: non-ANSI function declaration of function '<noident>'
 nested-declarator2.c:22:16: warning: variadic functions must have one named argument
@@ -37,5 +37,5 @@
 nested-declarator2.c:26:13: error: got -
 nested-declarator2.c:27:16: error: Expected ; at the end of type declaration
 nested-declarator2.c:27:16: error: got (
- * check-error-end:
+ * check-error-end
  */
--- old/usr/src/tools/smatch/src/validation/nocast.c	Mon Nov 18 13:20:28 2019
+++ new/usr/src/tools/smatch/src/validation/nocast.c	Mon Nov 18 13:20:28 2019
@@ -160,7 +160,7 @@
 nocast.c:34:33: warning: implicit cast to nocast type
 nocast.c:35:39: warning: incorrect type in initializer (different modifiers)
 nocast.c:35:39:    expected unsigned long *static [toplevel] bad_ptr_from
-nocast.c:35:39:    got unsigned long [nocast] *<noident>
+nocast.c:35:39:    got unsigned long [nocast] *
 nocast.c:35:39: warning: implicit cast from nocast type
 nocast.c:50:16: warning: implicit cast from nocast type
 nocast.c:54:16: warning: implicit cast from nocast type
--- old/usr/src/tools/smatch/src/validation/noderef.c	Mon Nov 18 13:20:29 2019
+++ new/usr/src/tools/smatch/src/validation/noderef.c	Mon Nov 18 13:20:29 2019
@@ -46,6 +46,6 @@
  * check-error-start
 noderef.c:24:12: warning: incorrect type in assignment (different modifiers)
 noderef.c:24:12:    expected char *[noderef] *q2
-noderef.c:24:12:    got char [noderef] **<noident>
+noderef.c:24:12:    got char [noderef] **
  * check-error-end
  */
--- /dev/null	Mon Nov 18 13:20:29 2019
+++ new/usr/src/tools/smatch/src/validation/optim/address-used01.c	Mon Nov 18 13:20:29 2019
@@ -0,0 +1,18 @@
+int foo(int **g, int j)
+{
+	int i = 1;
+	int *a;
+	int **p;
+
+	a = &i;
+	p = &a;
+	*p[0] = 0;
+	return i;
+}
+
+/*
+ * check-name: address-used01
+ * check-command: test-linearize -Wno-decl -fdump-ir=final $file
+ * check-output-ignore
+ * check-output-contains: ret\\..* \\$0
+ */
--- /dev/null	Mon Nov 18 13:20:29 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-extend.c	Mon Nov 18 13:20:29 2019
@@ -0,0 +1,27 @@
+typedef unsigned short u16;
+typedef          short s16;
+typedef unsigned   int u32;
+typedef            int s32;
+
+u32 ufoo(u32 x)
+{
+	u16 i = ((u16)x) & 0x7fffU;
+	return i;
+}
+
+u32 sfoo(u32 x)
+{
+	s16 i = ((s16)x) & 0x7fff;
+	return i;
+}
+
+/*
+ * check-name: and-extend
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: zext\\.
+ * check-output-excludes: sext\\.
+ * check-output-contains: and\\.32.*0x7fff
+ */
--- /dev/null	Mon Nov 18 13:20:29 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-extendx.c	Mon Nov 18 13:20:29 2019
@@ -0,0 +1,24 @@
+typedef unsigned short u16;
+typedef          short s16;
+typedef unsigned   int u32;
+typedef            int s32;
+typedef unsigned  long long u64;
+typedef           long long s64;
+
+u64 ufoo(int x)
+{
+	return x & 0x7fff;
+}
+
+u64 sfoo(int x)
+{
+	return x & 0x7fff;
+}
+
+/*
+ * check-name: and-extend
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\.64.*0x7fff
+ */
--- /dev/null	Mon Nov 18 13:20:29 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-lsr.c	Mon Nov 18 13:20:29 2019
@@ -0,0 +1,15 @@
+// (x & M) >> S to (x >> S) & (M >> S)
+
+unsigned int foo(unsigned int x)
+{
+	return (x & 0xffff) >> 12;
+}
+
+/*
+ * check-name: and-lsr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$15
+ * check-output-excludes: and\\..*\\$0xffff
+ */
--- /dev/null	Mon Nov 18 13:20:29 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-bf0.c	Mon Nov 18 13:20:29 2019
@@ -0,0 +1,24 @@
+struct s {
+	int f:3;
+};
+
+void foo(struct s *p, int a)
+{
+	p->f = 1;
+	p->f = a;
+}
+
+void bar(struct s *p, int a)
+{
+	p->f = a;
+	p->f = 1;
+}
+
+/*
+ * check-name: and-or-bf0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(3): and\\.
+ * check-output-pattern(2): or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:30 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-bf1.c	Mon Nov 18 13:20:30 2019
@@ -0,0 +1,18 @@
+struct s {
+	int  :2;
+	int f:3;
+};
+
+void foo(struct s *d, const struct s *s, int a)
+{
+	d->f = s->f | a;
+}
+
+/*
+ * check-name: and-or-bf1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): and\\.
+ * check-output-pattern(2): or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:30 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-bf2.c	Mon Nov 18 13:20:30 2019
@@ -0,0 +1,27 @@
+struct s {
+	char a:3;
+	char b:3;
+	char c:2;
+};
+
+void foo(struct s *p)
+{
+	p->a = 1;
+	p->b = 2;
+	p->c = 3;
+}
+
+/*
+ * check-name: and-or-bf2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	store.8     $209 -> 0[%arg1]
+	ret
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:30 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-bfs.c	Mon Nov 18 13:20:30 2019
@@ -0,0 +1,23 @@
+struct s {
+	  signed int  :2;
+	  signed int f:3;
+};
+
+int bfs(struct s s, int a)
+{
+	s.f = a;
+	return s.f;
+}
+
+/*
+ * check-name: and-or-bfs
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): trunc\\.
+ * check-output-pattern(1): sext\\.
+ * check-output-excludes: and\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ */
--- /dev/null	Mon Nov 18 13:20:30 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-bfu.c	Mon Nov 18 13:20:30 2019
@@ -0,0 +1,21 @@
+struct u {
+	unsigned int  :2;
+	unsigned int f:3;
+};
+
+int bfu(struct u s, int a)
+{
+	s.f = a;
+	return s.f;
+}
+
+/*
+ * check-name: and-or-bfu
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ */
--- /dev/null	Mon Nov 18 13:20:30 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-bfx.c	Mon Nov 18 13:20:30 2019
@@ -0,0 +1,18 @@
+struct s {
+	int f:3;
+};
+
+void foo(struct s *p, int a, int b)
+{
+	p->f = a;
+	p->f = b;
+}
+
+/*
+ * check-name: and-or-bfx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): and\\.
+ * check-output-pattern(1): or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:30 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-constant0.c	Mon Nov 18 13:20:30 2019
@@ -0,0 +1,12 @@
+int foo(int x)
+{
+	return (x | 0xfffff000) & 0xfff;
+}
+
+/*
+ * check-name: and-or-constant0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:30 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-constant1.c	Mon Nov 18 13:20:30 2019
@@ -0,0 +1,14 @@
+int foo(int x)
+{
+	return (x | 0x000fffff) & 0xfff;
+}
+
+/*
+ * check-name: or-and-constant1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0xfff
+ * check-output-excludes: and\\.
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:31 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-constant2.c	Mon Nov 18 13:20:31 2019
@@ -0,0 +1,13 @@
+int foo(int x)
+{
+	return (x | 0xfffffff0) & 0xfff;
+}
+
+/*
+ * check-name: and-or-constant2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: or\\..*\\$0xff0
+ * check-output-excludes: or\\..*\\$0xfffffff0
+ */
--- /dev/null	Mon Nov 18 13:20:31 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-crash.c	Mon Nov 18 13:20:31 2019
@@ -0,0 +1,5 @@
+static unsigned a(unsigned b, unsigned c) { (c << 1 | b & 1 << 1) >> 1; }
+
+/*
+ * check-name: catch crashes during AND-OR simplifications
+ */
--- /dev/null	Mon Nov 18 13:20:31 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-lsr0.c	Mon Nov 18 13:20:31 2019
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+	return ((a & 0x00000fff) | b) >> 12;
+}
+
+/*
+ * check-name: and-or-lsr0
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:31 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-lsr1.c	Mon Nov 18 13:20:31 2019
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+	return ((a & 0xfffff000) | b) >> 12;
+}
+
+/*
+ * check-name: and-or-lsr1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(0): and\\.
+ * check-output-pattern(1): or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:31 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-lsr2.c	Mon Nov 18 13:20:31 2019
@@ -0,0 +1,13 @@
+int foo(int x, int y)
+{
+	return ((x & 0xf0ffffff) | y) >> 12;
+}
+
+/*
+ * check-name: and-or-lsr2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$0xf0fff
+ * check-output-excludes: and\\..*\\$0xf0ffffff
+ */
--- /dev/null	Mon Nov 18 13:20:31 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-lsrx.c	Mon Nov 18 13:20:31 2019
@@ -0,0 +1,13 @@
+unsigned int foo(unsigned int x, unsigned int y, unsigned int a)
+{
+	return ((x & y) | (a & 0x0fff)) >> 12;
+}
+
+/*
+ * check-name: and-or-lsrx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:31 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-mask.c	Mon Nov 18 13:20:31 2019
@@ -0,0 +1,18 @@
+int foo(int a, int b)
+{
+	return ((a & 7) | (b & 3)) & 8;
+}
+
+/*
+ * check-name: and-or-mask
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	ret.32      $0
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:32 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-mask0.c	Mon Nov 18 13:20:32 2019
@@ -0,0 +1,12 @@
+int foo(int a, int b)
+{
+	return ((a & 0xfffff000) | b) & 0xfff;
+}
+
+/*
+ * check-name: and-or-mask0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:32 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-mask1.c	Mon Nov 18 13:20:32 2019
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+	return ((a & 0x0fffffff) | b) & 0xfff;
+}
+
+/*
+ * check-name: and-or-mask1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-pattern(1): or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:32 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-mask2.c	Mon Nov 18 13:20:32 2019
@@ -0,0 +1,13 @@
+int foo(int x, int y)
+{
+	return ((x & 0xffffff0f) | y) & 0xfff;
+}
+
+/*
+ * check-name: and-or-mask2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$0xf0f
+ * check-output-excludes: and\\..*\\$0xffffff0f
+ */
--- /dev/null	Mon Nov 18 13:20:32 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-mask3s.c	Mon Nov 18 13:20:32 2019
@@ -0,0 +1,25 @@
+#define W	3
+#define	S	8
+#define M	(W << S)
+
+static inline int fun(unsigned int x, unsigned int y)
+{
+	return ((x & M) | (y << S)) >> S;
+}
+
+short foo(unsigned int x, unsigned int y)
+{
+	return fun(x, y) & W;
+}
+
+/*
+ * check-name: and-or-mask3s
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): or\\.
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: shl\\.
+ */
--- /dev/null	Mon Nov 18 13:20:32 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-mask3u.c	Mon Nov 18 13:20:32 2019
@@ -0,0 +1,25 @@
+#define W	3
+#define	S	8
+#define M	(W << S)
+
+static inline int fun(unsigned int x, unsigned int y)
+{
+	return ((x & M) | (y << S)) >> S;
+}
+
+int foo(unsigned int x, unsigned int y)
+{
+	return fun(x, y) & W;
+}
+
+/*
+ * check-name: and-or-mask3u
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): or\\.
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: shl\\.
+ */
--- /dev/null	Mon Nov 18 13:20:32 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-mask4.c	Mon Nov 18 13:20:32 2019
@@ -0,0 +1,25 @@
+#define W	3
+#define	S	8
+#define M	(W << S)
+
+static inline int fun(unsigned int x, unsigned int y)
+{
+	return ((x & W) | (y >> S)) << S;
+}
+
+int foo(unsigned int x, unsigned int y)
+{
+	return fun(x, y) & M;
+}
+
+/*
+ * check-name: and-or-mask4
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(1): shl\\.
+ * check-output-pattern(1): or\\.
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: lsr\\.
+ */
--- /dev/null	Mon Nov 18 13:20:32 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-maskx.c	Mon Nov 18 13:20:32 2019
@@ -0,0 +1,13 @@
+int foo(int x, int y, int a)
+{
+	return ((x & y) | (a & 0xf000)) & 0x0fff;
+}
+
+/*
+ * check-name: and-or-maskx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): and\\.
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:33 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-shl0.c	Mon Nov 18 13:20:33 2019
@@ -0,0 +1,12 @@
+int foo(int a, int b)
+{
+	return ((a & 0xfff00000) | b) << 12;
+}
+
+/*
+ * check-name: and-or-shl0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:33 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-shl1.c	Mon Nov 18 13:20:33 2019
@@ -0,0 +1,13 @@
+int foo(int a, int b)
+{
+	return ((a & 0x000fffff) | b) << 12;
+}
+
+/*
+ * check-name: and-or-shl1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(0): and\\.
+ * check-output-pattern(1): or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:33 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-shl2.c	Mon Nov 18 13:20:33 2019
@@ -0,0 +1,13 @@
+int foo(int x, int y)
+{
+	return ((x & 0xffffff0f) | y) << 12;
+}
+
+/*
+ * check-name: and-or-shl2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$0xfff0f
+ * check-output-excludes: and\\..*\\$0xffffff0f
+ */
--- /dev/null	Mon Nov 18 13:20:33 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-shlx.c	Mon Nov 18 13:20:33 2019
@@ -0,0 +1,13 @@
+unsigned int foo(unsigned int x, unsigned int y, unsigned int a)
+{
+	return ((x & y) | (a & 0xfff00000)) << 12;
+}
+
+/*
+ * check-name: and-or-shlx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:33 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-trunc0.c	Mon Nov 18 13:20:33 2019
@@ -0,0 +1,13 @@
+char foo(int x, int y)
+{
+	return (x & 0xff00) | y;
+}
+
+/*
+ * check-name: and-or-trunc0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: and\\.
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:33 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-trunc1.c	Mon Nov 18 13:20:33 2019
@@ -0,0 +1,12 @@
+char foo(int x, int y)
+{
+	return (x & 0xffff) | y;
+}
+
+/*
+ * check-name: and-or-trunc1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: and\\.
+ */
--- /dev/null	Mon Nov 18 13:20:34 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-trunc2.c	Mon Nov 18 13:20:34 2019
@@ -0,0 +1,13 @@
+char foo(int x, int y)
+{
+	return (x & 0xff07) | y;
+}
+
+/*
+ * check-name: and-or-trunc2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-pattern(1): and\\..*\\$7
+ */
--- /dev/null	Mon Nov 18 13:20:34 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-or-truncx.c	Mon Nov 18 13:20:34 2019
@@ -0,0 +1,13 @@
+char foo(int x, int y, int b)
+{
+	return (x & y) | (b & 0xff00);
+}
+
+/*
+ * check-name: and-or-truncx
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): and\\.
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:34 2019
+++ new/usr/src/tools/smatch/src/validation/optim/and-trunc.c	Mon Nov 18 13:20:34 2019
@@ -0,0 +1,20 @@
+short smask(short x)
+{
+	return x & (short) 0x7fff;
+}
+
+short umask(unsigned short x)
+{
+	return x & (unsigned short) 0x7fff;
+}
+
+/*
+ * check-name: and-trunc
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ * check-output-excludes: trunc\\.
+ * check-output-contains: and\\.16
+ */
--- old/usr/src/tools/smatch/src/validation/linear/bitfield-init-zero.c	Mon Nov 18 13:20:34 2019
+++ /dev/null	Mon Nov 18 13:20:34 2019
@@ -1,102 +0,0 @@
-struct bfu {
-	unsigned int a:11;
-	unsigned int f:9;
-	unsigned int  :2;
-	unsigned int z:3;
-};
-
-struct bfu bfuu_init(unsigned int a)
-{
-	struct bfu bf = { .f = a, };
-	return bf;
-}
-
-struct bfu bfus_init(int a)
-{
-	struct bfu bf = { .f = a, };
-	return bf;
-}
-
-unsigned int bfu_get0(void)
-{
-	struct bfu bf = { };
-	return bf.f;
-}
-
-
-struct bfs {
-	signed int a:11;
-	signed int f:9;
-	signed int  :2;
-	signed int z:3;
-};
-
-struct bfs bfsu_init(unsigned int a)
-{
-	struct bfs bf = { .f = a, };
-	return bf;
-}
-
-struct bfs bfss_init(int a)
-{
-	struct bfs bf = { .f = a, };
-	return bf;
-}
-
-int bfs_get0(void)
-{
-	struct bfs bf = { };
-	return bf.f;
-}
-
-/*
- * check-name: bitfield implicit init zero
- * check-command: test-linearize -Wno-decl $file
- *
- * check-output-start
-bfuu_init:
-.L0:
-	<entry-point>
-	cast.9      %r2 <- (32) %arg1
-	shl.32      %r4 <- %r2, $11
-	ret.32      %r4
-
-
-bfus_init:
-.L2:
-	<entry-point>
-	scast.9     %r10 <- (32) %arg1
-	shl.32      %r12 <- %r10, $11
-	ret.32      %r12
-
-
-bfu_get0:
-.L4:
-	<entry-point>
-	ret.32      $0
-
-
-bfsu_init:
-.L6:
-	<entry-point>
-	cast.9      %r23 <- (32) %arg1
-	shl.32      %r25 <- %r23, $11
-	ret.32      %r25
-
-
-bfss_init:
-.L8:
-	<entry-point>
-	scast.9     %r31 <- (32) %arg1
-	shl.32      %r33 <- %r31, $11
-	ret.32      %r33
-
-
-bfs_get0:
-.L10:
-	<entry-point>
-	ret.32      $0
-
-
- * check-output-end
- */
--- /dev/null	Mon Nov 18 13:20:34 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bitfield-init-zero.c	Mon Nov 18 13:20:34 2019
@@ -0,0 +1,102 @@
+struct bfu {
+	unsigned int a:11;
+	unsigned int f:9;
+	unsigned int  :2;
+	unsigned int z:3;
+};
+
+struct bfu bfuu_init(unsigned int a)
+{
+	struct bfu bf = { .f = a, };
+	return bf;
+}
+
+struct bfu bfus_init(int a)
+{
+	struct bfu bf = { .f = a, };
+	return bf;
+}
+
+unsigned int bfu_get0(void)
+{
+	struct bfu bf = { };
+	return bf.f;
+}
+
+
+struct bfs {
+	signed int a:11;
+	signed int f:9;
+	signed int  :2;
+	signed int z:3;
+};
+
+struct bfs bfsu_init(unsigned int a)
+{
+	struct bfs bf = { .f = a, };
+	return bf;
+}
+
+struct bfs bfss_init(int a)
+{
+	struct bfs bf = { .f = a, };
+	return bf;
+}
+
+int bfs_get0(void)
+{
+	struct bfs bf = { };
+	return bf.f;
+}
+
+/*
+ * check-name: bitfield implicit init zero
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+bfuu_init:
+.L0:
+	<entry-point>
+	and.32      %r4 <- %arg1, $511
+	shl.32      %r5 <- %r4, $11
+	ret.32      %r5
+
+
+bfus_init:
+.L2:
+	<entry-point>
+	and.32      %r13 <- %arg1, $511
+	shl.32      %r14 <- %r13, $11
+	ret.32      %r14
+
+
+bfu_get0:
+.L4:
+	<entry-point>
+	ret.32      $0
+
+
+bfsu_init:
+.L6:
+	<entry-point>
+	and.32      %r27 <- %arg1, $511
+	shl.32      %r28 <- %r27, $11
+	ret.32      %r28
+
+
+bfss_init:
+.L8:
+	<entry-point>
+	and.32      %r36 <- %arg1, $511
+	shl.32      %r37 <- %r36, $11
+	ret.32      %r37
+
+
+bfs_get0:
+.L10:
+	<entry-point>
+	ret.32      $0
+
+
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/bitfield-size.c	Mon Nov 18 13:20:34 2019
+++ /dev/null	Mon Nov 18 13:20:34 2019
@@ -1,41 +0,0 @@
-struct bfu {
-	unsigned int a:4;
-	unsigned int  :2;
-	unsigned int b:4;
-};
-unsigned int get__bfu_a(struct bfu bf) { return bf.a; }
-unsigned int get__bfu_b(struct bfu bf) { return bf.b; }
-unsigned int get_pbfu_a(struct bfu *bf) { return bf->a; }
-unsigned int get_pbfu_b(struct bfu *bf) { return bf->b; }
-
-
-struct bfs {
-	signed int a:4;
-	signed int  :2;
-	signed int b:4;
-};
-signed int get__bfs_a(struct bfs bf) { return bf.a; }
-signed int get__bfs_b(struct bfs bf) { return bf.b; }
-signed int get_pbfs_a(struct bfs *bf) { return bf->a; }
-signed int get_pbfs_b(struct bfs *bf) { return bf->b; }
-
-
-struct bfi {
-	int a:4;
-	int  :2;
-	int b:4;
-};
-unsigned int get__bfi_a(struct bfi bf) { return bf.a; }
-unsigned int get__bfi_b(struct bfi bf) { return bf.b; }
-unsigned int get_pbfi_a(struct bfi *bf) { return bf->a; }
-unsigned int get_pbfi_b(struct bfi *bf) { return bf->b; }
-
-/*
- * check-name: bitfield size
- * check-command: test-linearize -Wno-decl $file
- * check-output-ignore
- *
- * check-output-pattern-24-times: cast\\.
- * check-output-pattern-12-times: cast\\.4
- * check-output-pattern-6-times: lsr\\..*\\$6
- */
--- /dev/null	Mon Nov 18 13:20:34 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bitfield-size.c	Mon Nov 18 13:20:34 2019
@@ -0,0 +1,44 @@
+struct bfu {
+	unsigned int a:4;
+	unsigned int  :2;
+	unsigned int b:4;
+};
+unsigned int get__bfu_a(struct bfu bf) { return bf.a; }
+unsigned int get__bfu_b(struct bfu bf) { return bf.b; }
+unsigned int get_pbfu_a(struct bfu *bf) { return bf->a; }
+unsigned int get_pbfu_b(struct bfu *bf) { return bf->b; }
+
+
+struct bfs {
+	signed int a:4;
+	signed int  :2;
+	signed int b:4;
+};
+signed int get__bfs_a(struct bfs bf) { return bf.a; }
+signed int get__bfs_b(struct bfs bf) { return bf.b; }
+signed int get_pbfs_a(struct bfs *bf) { return bf->a; }
+signed int get_pbfs_b(struct bfs *bf) { return bf->b; }
+
+
+struct bfi {
+	int a:4;
+	int  :2;
+	int b:4;
+};
+unsigned int get__bfi_a(struct bfi bf) { return bf.a; }
+unsigned int get__bfi_b(struct bfi bf) { return bf.b; }
+unsigned int get_pbfi_a(struct bfi *bf) { return bf->a; }
+unsigned int get_pbfi_b(struct bfi *bf) { return bf->b; }
+
+/*
+ * check-name: bitfield size
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: and\\..*\\$960
+ * check-output-excludes: zext\\.
+ * check-output-pattern(8): and\\..*\\$15
+ * check-output-pattern(4): sext\\.
+ * check-output-pattern(4): trunc\\.4
+ * check-output-pattern(6): lsr\\..*\\$6
+ */
--- /dev/null	Mon Nov 18 13:20:35 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bitfield-store-load0.c	Mon Nov 18 13:20:35 2019
@@ -0,0 +1,44 @@
+int ufoo(unsigned int a)
+{
+	struct u {
+		unsigned int :2;
+		unsigned int a:3;
+	} bf;
+
+	bf.a = a;
+	return bf.a;
+}
+
+int sfoo(int a)
+{
+	struct s {
+		signed int :2;
+		signed int a:3;
+	} bf;
+
+	bf.a = a;
+	return bf.a;
+}
+
+/*
+ * check-name: optim store/load bitfields
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+ufoo:
+.L0:
+	<entry-point>
+	and.32      %r11 <- %arg1, $7
+	ret.32      %r11
+
+
+sfoo:
+.L2:
+	<entry-point>
+	trunc.3     %r16 <- (32) %arg1
+	sext.32     %r23 <- (3) %r16
+	ret.32      %r23
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:35 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bitfield-store-loads.c	Mon Nov 18 13:20:35 2019
@@ -0,0 +1,23 @@
+struct s {
+	char :2;
+	char f:3;
+};
+
+int foo(struct s s, int a)
+{
+	s.f = a;
+	return s.f;
+}
+
+/*
+ * check-name: bitfield-store-load signed
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: [sz]ext\\.
+ * check-output-excludes: trunc\\.
+ * check-output-pattern(1): and\\.
+ */
--- /dev/null	Mon Nov 18 13:20:35 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bitfield-store-loadu.c	Mon Nov 18 13:20:35 2019
@@ -0,0 +1,21 @@
+struct s {
+	unsigned int :2;
+	unsigned int f:3;
+};
+
+int foo(struct s s, int a)
+{
+	s.f = a;
+	return s.f;
+}
+
+/*
+ * check-name: bitfield-store-load unsigned
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: shl\\.
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: or\\.
+ * check-output-pattern(1): and\\.
+ */
--- /dev/null	Mon Nov 18 13:20:35 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bits-not-zero.c	Mon Nov 18 13:20:35 2019
@@ -0,0 +1,30 @@
+int  or_not0(int a) { return a | ~0; }
+int and_not0(int a) { return a & ~0; }
+int xor_not0(int a) { return a ^ ~0; }
+
+/*
+ * check-name: bool-not-zero
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+or_not0:
+.L0:
+	<entry-point>
+	ret.32      $0xffffffff
+
+
+and_not0:
+.L2:
+	<entry-point>
+	ret.32      %arg1
+
+
+xor_not0:
+.L4:
+	<entry-point>
+	not.32      %r8 <- %arg1
+	ret.32      %r8
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:35 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-context-fp.c	Mon Nov 18 13:20:35 2019
@@ -0,0 +1,93 @@
+#define	bool	_Bool
+
+bool bfimp(float a) { return a; }
+bool bfexp(float a) { return (bool)a; }
+
+bool bfnot(float a) { return !a; }
+int  ifnot(float a) { return !a; }
+bool bfior(float a, float b) { return a || b; }
+int  ifior(float a, float b) { return a || b; }
+bool bfand(float a, float b) { return a && b; }
+int  ifand(float a, float b) { return a && b; }
+
+/*
+ * check-name: bool context fp
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+bfimp:
+.L0:
+	<entry-point>
+	setfval.32  %r2 <- 0.000000e+00
+	fcmpune.1   %r3 <- %arg1, %r2
+	ret.1       %r3
+
+
+bfexp:
+.L2:
+	<entry-point>
+	setfval.32  %r6 <- 0.000000e+00
+	fcmpune.1   %r7 <- %arg1, %r6
+	ret.1       %r7
+
+
+bfnot:
+.L4:
+	<entry-point>
+	setfval.32  %r10 <- 0.000000e+00
+	fcmpoeq.1   %r12 <- %arg1, %r10
+	ret.1       %r12
+
+
+ifnot:
+.L6:
+	<entry-point>
+	setfval.32  %r15 <- 0.000000e+00
+	fcmpoeq.32  %r16 <- %arg1, %r15
+	ret.32      %r16
+
+
+bfior:
+.L8:
+	<entry-point>
+	setfval.32  %r19 <- 0.000000e+00
+	fcmpune.1   %r20 <- %arg1, %r19
+	fcmpune.1   %r23 <- %arg2, %r19
+	or.1        %r24 <- %r20, %r23
+	ret.1       %r24
+
+
+ifior:
+.L10:
+	<entry-point>
+	setfval.32  %r29 <- 0.000000e+00
+	fcmpune.1   %r30 <- %arg1, %r29
+	fcmpune.1   %r33 <- %arg2, %r29
+	or.1        %r34 <- %r30, %r33
+	zext.32     %r35 <- (1) %r34
+	ret.32      %r35
+
+
+bfand:
+.L12:
+	<entry-point>
+	setfval.32  %r38 <- 0.000000e+00
+	fcmpune.1   %r39 <- %arg1, %r38
+	fcmpune.1   %r42 <- %arg2, %r38
+	and.1       %r43 <- %r39, %r42
+	ret.1       %r43
+
+
+ifand:
+.L14:
+	<entry-point>
+	setfval.32  %r48 <- 0.000000e+00
+	fcmpune.1   %r49 <- %arg1, %r48
+	fcmpune.1   %r52 <- %arg2, %r48
+	and.1       %r53 <- %r49, %r52
+	zext.32     %r54 <- (1) %r53
+	ret.32      %r54
+
+
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/optim/bool-context.c	Mon Nov 18 13:20:35 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-context.c	Mon Nov 18 13:20:36 2019
@@ -8,5 +8,5 @@
  * check-command: test-linearize -Wno-decl $file
  * check-output-ignore
  *
- * check-output-pattern-4-times: setne\\..* %arg[12]
+ * check-output-pattern(4): setne\\..* %arg[12]
  */
--- /dev/null	Mon Nov 18 13:20:36 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-eq0.c	Mon Nov 18 13:20:36 2019
@@ -0,0 +1,12 @@
+int beq0(int a) { return a == 0; }
+int bnotne0(int a) { return !(a != 0); }
+int bnot(int a) { return !a; }
+
+/*
+ * check-name: bool-eq0
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: setne\\.
+ * check-output-contains: seteq\\.
+ */
--- /dev/null	Mon Nov 18 13:20:36 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-int-bool.c	Mon Nov 18 13:20:36 2019
@@ -0,0 +1,12 @@
+_Bool beq0(_Bool a) { return (a == 0); }
+_Bool beq1(_Bool a) { return (a == 1); }
+_Bool bne0(_Bool a) { return (a != 0); }
+_Bool bne1(_Bool a) { return (a != 1); }
+
+/*
+ * check-name: bool - int - bool constants
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: cast\\.
+ */
--- /dev/null	Mon Nov 18 13:20:36 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-ne0.c	Mon Nov 18 13:20:36 2019
@@ -0,0 +1,12 @@
+int bne0(int a) { return a != 0; }
+int bnoteq0(int a) { return !(a == 0); }
+int bnotnot(int a) { return !(!a); }
+
+/*
+ * check-name: bool-ne0
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: seteq\\.
+ * check-output-contains: setne\\.
+ */
--- /dev/null	Mon Nov 18 13:20:36 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-neq0.c	Mon Nov 18 13:20:36 2019
@@ -0,0 +1,12 @@
+int bneq0(int a) { return a != 0; }
+int bnoteq0(int a) { return !(a == 0); }
+int bnotnot(int a) { return !(!a); }
+
+/*
+ * check-name: bool-neq0
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-excludes: seteq\\.
+ * check-output-contains: setne\\.
+ */
--- /dev/null	Mon Nov 18 13:20:36 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-sext-test.c	Mon Nov 18 13:20:36 2019
@@ -0,0 +1,12 @@
+_Bool eqs0(  signed char a) { return a == 0; }
+_Bool eqs1(  signed char a) { return a == 1; }
+_Bool nes0(  signed char a) { return a != 0; }
+_Bool nes1(  signed char a) { return a != 1; }
+
+/*
+ * check-name: bool-sext-test
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ */
--- old/usr/src/tools/smatch/src/validation/optim/bool-simplify.c	Mon Nov 18 13:20:37 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-simplify.c	Mon Nov 18 13:20:37 2019
@@ -18,6 +18,17 @@
 	return a || 1;
 }
 
+// try again but with something true but != 1
+int and_2(int a)
+{
+	return a && 2;
+}
+
+int or_2(int a)
+{
+	return a || 2;
+}
+
 /*
  * check-name: bool-simplify
  * check-command: test-linearize -Wno-decl $file
@@ -32,17 +43,15 @@
 and_1:
 .L2:
 	<entry-point>
-	setne.1     %r8 <- %arg1, $0
-	cast.32     %r11 <- (1) %r8
-	ret.32      %r11
+	setne.32    %r9 <- %arg1, $0
+	ret.32      %r9
 
 
 or_0:
 .L4:
 	<entry-point>
-	setne.1     %r14 <- %arg1, $0
-	cast.32     %r17 <- (1) %r14
-	ret.32      %r17
+	setne.32    %r14 <- %arg1, $0
+	ret.32      %r14
 
 
 or_1:
@@ -49,6 +58,19 @@
 .L6:
 	<entry-point>
 	ret.32      $1
+
+
+and_2:
+.L8:
+	<entry-point>
+	setne.32    %r25 <- %arg1, $0
+	ret.32      %r25
+
+
+or_2:
+.L10:
+	<entry-point>
+	ret.32      $1
 
 
  * check-output-end
--- /dev/null	Mon Nov 18 13:20:37 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-simplify2.c	Mon Nov 18 13:20:37 2019
@@ -0,0 +1,215 @@
+typedef unsigned int uint;
+typedef _Bool bool;
+
+static uint   ini(uint a) { return !a; }
+static bool   bni(uint a) { return !a; }
+static uint  ioii(uint a, uint b) { return a || b; }
+static uint  iaii(uint a, uint b) { return a && b; }
+static bool  boii(uint a, uint b) { return a || b; }
+static bool  baii(uint a, uint b) { return a && b; }
+static uint ioiii(uint a, uint b, uint c) { return a || b || c; }
+static uint iaiii(uint a, uint b, uint c) { return a && b && c; }
+static bool boiii(uint a, uint b, uint c) { return a || b || c; }
+static bool baiii(uint a, uint b, uint c) { return a && b && c; }
+
+static uint   inb(bool a) { return !a; }
+static bool   bnb(bool a) { return !a; }
+static uint  iobb(bool a, bool b) { return a || b; }
+static uint  iabb(bool a, bool b) { return a && b; }
+static bool  bobb(bool a, bool b) { return a || b; }
+static bool  babb(bool a, bool b) { return a && b; }
+static uint iobbb(bool a, bool b, bool c) { return a || b || c; }
+static uint iabbb(bool a, bool b, bool c) { return a && b && c; }
+static bool bobbb(bool a, bool b, bool c) { return a || b || c; }
+static bool babbb(bool a, bool b, bool c) { return a && b && c; }
+
+/*
+ * check-name: bool-simplify2
+ * check-command: test-linearize $file
+ *
+ * check-output-pattern(20): setne\\.
+ * check-output-pattern(4):  seteq\\.
+ * check-output-pattern(8): zext\\.
+ * check-output-pattern(12): and
+ * check-output-pattern(12): or
+ * check-output-end
+ *
+ * check-output-start
+ini:
+.L0:
+	<entry-point>
+	seteq.32    %r2 <- %arg1, $0
+	ret.32      %r2
+
+
+bni:
+.L2:
+	<entry-point>
+	seteq.1     %r6 <- %arg1, $0
+	ret.1       %r6
+
+
+ioii:
+.L4:
+	<entry-point>
+	setne.1     %r9 <- %arg1, $0
+	setne.1     %r11 <- %arg2, $0
+	or.1        %r12 <- %r9, %r11
+	zext.32     %r13 <- (1) %r12
+	ret.32      %r13
+
+
+iaii:
+.L6:
+	<entry-point>
+	setne.1     %r16 <- %arg1, $0
+	setne.1     %r18 <- %arg2, $0
+	and.1       %r19 <- %r16, %r18
+	zext.32     %r20 <- (1) %r19
+	ret.32      %r20
+
+
+boii:
+.L8:
+	<entry-point>
+	setne.1     %r23 <- %arg1, $0
+	setne.1     %r25 <- %arg2, $0
+	or.1        %r26 <- %r23, %r25
+	ret.1       %r26
+
+
+baii:
+.L10:
+	<entry-point>
+	setne.1     %r31 <- %arg1, $0
+	setne.1     %r33 <- %arg2, $0
+	and.1       %r34 <- %r31, %r33
+	ret.1       %r34
+
+
+ioiii:
+.L12:
+	<entry-point>
+	setne.1     %r39 <- %arg1, $0
+	setne.1     %r41 <- %arg2, $0
+	or.1        %r42 <- %r39, %r41
+	setne.1     %r46 <- %arg3, $0
+	or.1        %r47 <- %r42, %r46
+	zext.32     %r48 <- (1) %r47
+	ret.32      %r48
+
+
+iaiii:
+.L14:
+	<entry-point>
+	setne.1     %r51 <- %arg1, $0
+	setne.1     %r53 <- %arg2, $0
+	and.1       %r54 <- %r51, %r53
+	setne.1     %r58 <- %arg3, $0
+	and.1       %r59 <- %r54, %r58
+	zext.32     %r60 <- (1) %r59
+	ret.32      %r60
+
+
+boiii:
+.L16:
+	<entry-point>
+	setne.1     %r63 <- %arg1, $0
+	setne.1     %r65 <- %arg2, $0
+	or.1        %r66 <- %r63, %r65
+	setne.1     %r70 <- %arg3, $0
+	or.1        %r71 <- %r66, %r70
+	ret.1       %r71
+
+
+baiii:
+.L18:
+	<entry-point>
+	setne.1     %r76 <- %arg1, $0
+	setne.1     %r78 <- %arg2, $0
+	and.1       %r79 <- %r76, %r78
+	setne.1     %r83 <- %arg3, $0
+	and.1       %r84 <- %r79, %r83
+	ret.1       %r84
+
+
+inb:
+.L20:
+	<entry-point>
+	seteq.32    %r89 <- %arg1, $0
+	ret.32      %r89
+
+
+bnb:
+.L22:
+	<entry-point>
+	seteq.1     %r93 <- %arg1, $0
+	ret.1       %r93
+
+
+iobb:
+.L24:
+	<entry-point>
+	or.1        %r97 <- %arg1, %arg2
+	zext.32     %r98 <- (1) %r97
+	ret.32      %r98
+
+
+iabb:
+.L26:
+	<entry-point>
+	and.1       %r102 <- %arg1, %arg2
+	zext.32     %r103 <- (1) %r102
+	ret.32      %r103
+
+
+bobb:
+.L28:
+	<entry-point>
+	or.1        %r107 <- %arg1, %arg2
+	ret.1       %r107
+
+
+babb:
+.L30:
+	<entry-point>
+	and.1       %r113 <- %arg1, %arg2
+	ret.1       %r113
+
+
+iobbb:
+.L32:
+	<entry-point>
+	or.1        %r119 <- %arg1, %arg2
+	or.1        %r123 <- %r119, %arg3
+	zext.32     %r124 <- (1) %r123
+	ret.32      %r124
+
+
+iabbb:
+.L34:
+	<entry-point>
+	and.1       %r128 <- %arg1, %arg2
+	and.1       %r132 <- %r128, %arg3
+	zext.32     %r133 <- (1) %r132
+	ret.32      %r133
+
+
+bobbb:
+.L36:
+	<entry-point>
+	or.1        %r137 <- %arg1, %arg2
+	or.1        %r141 <- %r137, %arg3
+	ret.1       %r141
+
+
+babbb:
+.L38:
+	<entry-point>
+	and.1       %r147 <- %arg1, %arg2
+	and.1       %r151 <- %r147, %arg3
+	ret.1       %r151
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:37 2019
+++ new/usr/src/tools/smatch/src/validation/optim/bool-zext-test.c	Mon Nov 18 13:20:37 2019
@@ -0,0 +1,12 @@
+_Bool equ0(unsigned char a) { return a == 0; }
+_Bool equ1(unsigned char a) { return a == 1; }
+_Bool neu0(unsigned char a) { return a != 0; }
+_Bool neu1(unsigned char a) { return a != 1; }
+
+/*
+ * check-name: bool-zext-test
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:37 2019
+++ new/usr/src/tools/smatch/src/validation/optim/call-complex-pointer.c	Mon Nov 18 13:20:37 2019
@@ -0,0 +1,13 @@
+int foo(int p, int (*f0)(int), int (*f1)(int), int arg)
+{
+	return (p ? f0 : f1)(arg);
+}
+/*
+ * check-name: call-complex-pointer
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: ptrcast\\.
+ * check-output-contains: select\\.
+ */
--- /dev/null	Mon Nov 18 13:20:37 2019
+++ new/usr/src/tools/smatch/src/validation/optim/call-inlined.c	Mon Nov 18 13:20:37 2019
@@ -0,0 +1,30 @@
+static const char messg[] = "def";
+
+static inline int add(int a, int b)
+{
+	return a + b;
+}
+
+int foo(int a, int b, int p)
+{
+	if (p) {
+		add(a + b, 1);
+		return p;
+	}
+	return 0;
+}
+
+/*
+ * check-name: call-inlined
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	select.32   %r10 <- %arg3, %arg3, $0
+	ret.32      %r10
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:38 2019
+++ new/usr/src/tools/smatch/src/validation/optim/canonical-add.c	Mon Nov 18 13:20:38 2019
@@ -0,0 +1,55 @@
+int xpc_add_ypc(int x, int y)
+{
+	return (x + 1) + (y + 1);
+}
+
+int xmc_add_ypc(int x, int y)
+{
+	return (x - 1) + (y + 1);
+}
+
+int xpc_add_ymc(int x, int y)
+{
+	return (x + 1) + (y - 1);
+}
+
+int xmc_add_ymc(int x, int y)
+{
+	return (x - 1) + (y - 1);
+}
+
+int xpc_sub_ypc(int x, int y)
+{
+	return (x + 1) - (y + 1);
+}
+
+int xmc_sub_ypc(int x, int y)
+{
+	return (x - 1) - (y + 1);
+}
+
+int xpc_sub_ymc(int x, int y)
+{
+	return (x + 1) - (y - 1);
+}
+
+int xmc_sub_ymc(int x, int y)
+{
+	return (x - 1) - (y - 1);
+}
+
+/*
+ * check-name: canonical-add
+ * check-description:
+ *	1) verify that constants in add/sub chains are
+ *	   pushed at the right of the whole chain.
+ *	   For example '(a + 1) + b' must be canonicalized into '(a + b) + 1'
+ *	   This is needed for '(a + 1) + b - 1' to be simplified into '(a + b)'
+ *
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ * check-output-ignore
+
+ * check-output-excludes: \\$1
+ * check-output-excludes: \\$-1
+ */
--- /dev/null	Mon Nov 18 13:20:38 2019
+++ new/usr/src/tools/smatch/src/validation/optim/canonical-cmp.c	Mon Nov 18 13:20:38 2019
@@ -0,0 +1,124 @@
+typedef	  signed int	sint;
+typedef	unsigned int	uint;
+
+sint seq(sint p, sint a) { return (123 == p) ? a : 0; }
+sint sne(sint p, sint a) { return (123 != p) ? a : 0; }
+
+sint slt(sint p, sint a) { return (123 >  p) ? a : 0; }
+sint sle(sint p, sint a) { return (123 >= p) ? a : 0; }
+sint sge(sint p, sint a) { return (123 <= p) ? a : 0; }
+sint sgt(sint p, sint a) { return (123 <  p) ? a : 0; }
+
+uint ueq(uint p, uint a) { return (123 == p) ? a : 0; }
+uint une(uint p, uint a) { return (123 != p) ? a : 0; }
+
+uint ubt(uint p, uint a) { return (123 >  p) ? a : 0; }
+uint ube(uint p, uint a) { return (123 >= p) ? a : 0; }
+uint uae(uint p, uint a) { return (123 <= p) ? a : 0; }
+uint uat(uint p, uint a) { return (123 <  p) ? a : 0; }
+
+/*
+ * check-name: canonical-cmp
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-excludes: \\$123,
+ *
+ * check-output-start
+seq:
+.L0:
+	<entry-point>
+	seteq.32    %r3 <- %arg1, $123
+	select.32   %r4 <- %r3, %arg2, $0
+	ret.32      %r4
+
+
+sne:
+.L2:
+	<entry-point>
+	setne.32    %r8 <- %arg1, $123
+	select.32   %r9 <- %r8, %arg2, $0
+	ret.32      %r9
+
+
+slt:
+.L4:
+	<entry-point>
+	setlt.32    %r13 <- %arg1, $123
+	select.32   %r14 <- %r13, %arg2, $0
+	ret.32      %r14
+
+
+sle:
+.L6:
+	<entry-point>
+	setle.32    %r18 <- %arg1, $123
+	select.32   %r19 <- %r18, %arg2, $0
+	ret.32      %r19
+
+
+sge:
+.L8:
+	<entry-point>
+	setge.32    %r23 <- %arg1, $123
+	select.32   %r24 <- %r23, %arg2, $0
+	ret.32      %r24
+
+
+sgt:
+.L10:
+	<entry-point>
+	setgt.32    %r28 <- %arg1, $123
+	select.32   %r29 <- %r28, %arg2, $0
+	ret.32      %r29
+
+
+ueq:
+.L12:
+	<entry-point>
+	seteq.32    %r33 <- %arg1, $123
+	select.32   %r34 <- %r33, %arg2, $0
+	ret.32      %r34
+
+
+une:
+.L14:
+	<entry-point>
+	setne.32    %r38 <- %arg1, $123
+	select.32   %r39 <- %r38, %arg2, $0
+	ret.32      %r39
+
+
+ubt:
+.L16:
+	<entry-point>
+	setb.32     %r43 <- %arg1, $123
+	select.32   %r44 <- %r43, %arg2, $0
+	ret.32      %r44
+
+
+ube:
+.L18:
+	<entry-point>
+	setbe.32    %r48 <- %arg1, $123
+	select.32   %r49 <- %r48, %arg2, $0
+	ret.32      %r49
+
+
+uae:
+.L20:
+	<entry-point>
+	setae.32    %r53 <- %arg1, $123
+	select.32   %r54 <- %r53, %arg2, $0
+	ret.32      %r54
+
+
+uat:
+.L22:
+	<entry-point>
+	seta.32     %r58 <- %arg1, $123
+	select.32   %r59 <- %r58, %arg2, $0
+	ret.32      %r59
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:38 2019
+++ new/usr/src/tools/smatch/src/validation/optim/canonical-fcmp.c	Mon Nov 18 13:20:38 2019
@@ -0,0 +1,123 @@
+extern double g;
+
+int  fcmp_eq(double a) { return  (g == a); }
+int  fcmp_ne(double a) { return  (g != a); }
+
+int  fcmp_gt(double a) { return  (g >  a); }
+int  fcmp_ge(double a) { return  (g >= a); }
+int  fcmp_le(double a) { return  (g <= a); }
+int  fcmp_lt(double a) { return  (g <  a); }
+
+int nfcmp_ne(double a) { return !(g == a); }
+int nfcmp_eq(double a) { return !(g != a); }
+
+int nfcmp_le(double a) { return !(g >  a); }
+int nfcmp_lt(double a) { return !(g >= a); }
+int nfcmp_gt(double a) { return !(g <= a); }
+int nfcmp_ge(double a) { return !(g <  a); }
+
+/*
+ * check-name: canonical-cmp
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-excludes: \\$123,
+ *
+ * check-output-start
+fcmp_eq:
+.L0:
+	<entry-point>
+	load.64     %r1 <- 0[g]
+	fcmpoeq.32  %r3 <- %r1, %arg1
+	ret.32      %r3
+
+
+fcmp_ne:
+.L2:
+	<entry-point>
+	load.64     %r5 <- 0[g]
+	fcmpune.32  %r7 <- %r5, %arg1
+	ret.32      %r7
+
+
+fcmp_gt:
+.L4:
+	<entry-point>
+	load.64     %r9 <- 0[g]
+	fcmpogt.32  %r11 <- %r9, %arg1
+	ret.32      %r11
+
+
+fcmp_ge:
+.L6:
+	<entry-point>
+	load.64     %r13 <- 0[g]
+	fcmpoge.32  %r15 <- %r13, %arg1
+	ret.32      %r15
+
+
+fcmp_le:
+.L8:
+	<entry-point>
+	load.64     %r17 <- 0[g]
+	fcmpole.32  %r19 <- %r17, %arg1
+	ret.32      %r19
+
+
+fcmp_lt:
+.L10:
+	<entry-point>
+	load.64     %r21 <- 0[g]
+	fcmpolt.32  %r23 <- %r21, %arg1
+	ret.32      %r23
+
+
+nfcmp_ne:
+.L12:
+	<entry-point>
+	load.64     %r25 <- 0[g]
+	fcmpune.32  %r28 <- %r25, %arg1
+	ret.32      %r28
+
+
+nfcmp_eq:
+.L14:
+	<entry-point>
+	load.64     %r30 <- 0[g]
+	fcmpoeq.32  %r33 <- %r30, %arg1
+	ret.32      %r33
+
+
+nfcmp_le:
+.L16:
+	<entry-point>
+	load.64     %r35 <- 0[g]
+	fcmpule.32  %r38 <- %r35, %arg1
+	ret.32      %r38
+
+
+nfcmp_lt:
+.L18:
+	<entry-point>
+	load.64     %r40 <- 0[g]
+	fcmpult.32  %r43 <- %r40, %arg1
+	ret.32      %r43
+
+
+nfcmp_gt:
+.L20:
+	<entry-point>
+	load.64     %r45 <- 0[g]
+	fcmpugt.32  %r48 <- %r45, %arg1
+	ret.32      %r48
+
+
+nfcmp_ge:
+.L22:
+	<entry-point>
+	load.64     %r50 <- 0[g]
+	fcmpuge.32  %r53 <- %r50, %arg1
+	ret.32      %r53
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:38 2019
+++ new/usr/src/tools/smatch/src/validation/optim/canonical-mul.c	Mon Nov 18 13:20:38 2019
@@ -0,0 +1,24 @@
+#define uint unsigned int
+
+uint xtc_umul_ytc(uint x, uint y) { return (x * 3) * (y * 2); }
+
+/*
+ * check-name: canonical-muldiv
+ * check-description:
+ *	1) verify that constants in mul chains are
+ *	   pushed at the right of the whole chain.
+ *	   For example '(a * 3) * b' must be canonicalized into '(a * b) * 1'
+ *	   This is needed in general for constant simplification;
+ *	   for example, for:
+ *		'(a * 3) * (b * 2)'
+ *	   to be simplified into:
+ *		'(a * b) * 6'
+ *
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ * check-output-ignore
+ *
+ * check-output-excludes: \\$3
+ * check-output-excludes: \\$2
+ * check-output-contains: \\$6
+ */
--- /dev/null	Mon Nov 18 13:20:38 2019
+++ new/usr/src/tools/smatch/src/validation/optim/cast-kinds.c	Mon Nov 18 13:20:38 2019
@@ -0,0 +1,398 @@
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+static int uint_2_int(uint a) { return (int)a; }
+static int long_2_int(long a) { return (int)a; }
+static int ulong_2_int(ulong a) { return (int)a; }
+static int vptr_2_int(void *a) { return (int)a; }
+static int iptr_2_int(int *a) { return (int)a; }
+static int float_2_int(float a) { return (int)a; }
+static int double_2_int(double a) { return (int)a; }
+static uint int_2_uint(int a) { return (uint)a; }
+static uint long_2_uint(long a) { return (uint)a; }
+static uint ulong_2_uint(ulong a) { return (uint)a; }
+static uint vptr_2_uint(void *a) { return (uint)a; }
+static uint iptr_2_uint(int *a) { return (uint)a; }
+static uint float_2_uint(float a) { return (uint)a; }
+static uint double_2_uint(double a) { return (uint)a; }
+static long int_2_long(int a) { return (long)a; }
+static long uint_2_long(uint a) { return (long)a; }
+static long ulong_2_long(ulong a) { return (long)a; }
+static long vptr_2_long(void *a) { return (long)a; }
+static long iptr_2_long(int *a) { return (long)a; }
+static long float_2_long(float a) { return (long)a; }
+static long double_2_long(double a) { return (long)a; }
+static ulong int_2_ulong(int a) { return (ulong)a; }
+static ulong uint_2_ulong(uint a) { return (ulong)a; }
+static ulong long_2_ulong(long a) { return (ulong)a; }
+static ulong vptr_2_ulong(void *a) { return (ulong)a; }
+static ulong iptr_2_ulong(int *a) { return (ulong)a; }
+static ulong float_2_ulong(float a) { return (ulong)a; }
+static ulong double_2_ulong(double a) { return (ulong)a; }
+static void * int_2_vptr(int a) { return (void *)a; }
+static void * uint_2_vptr(uint a) { return (void *)a; }
+static void * long_2_vptr(long a) { return (void *)a; }
+static void * ulong_2_vptr(ulong a) { return (void *)a; }
+static void * iptr_2_vptr(int *a) { return (void *)a; }
+static int * int_2_iptr(int a) { return (int *)a; }
+static int * uint_2_iptr(uint a) { return (int *)a; }
+static int * long_2_iptr(long a) { return (int *)a; }
+static int * ulong_2_iptr(ulong a) { return (int *)a; }
+static int * vptr_2_iptr(void *a) { return (int *)a; }
+static float int_2_float(int a) { return (float)a; }
+static float uint_2_float(uint a) { return (float)a; }
+static float long_2_float(long a) { return (float)a; }
+static float ulong_2_float(ulong a) { return (float)a; }
+static float double_2_float(double a) { return (float)a; }
+static double int_2_double(int a) { return (double)a; }
+static double uint_2_double(uint a) { return (double)a; }
+static double long_2_double(long a) { return (double)a; }
+static double ulong_2_double(ulong a) { return (double)a; }
+static double float_2_double(float a) { return (double)a; }
+
+static float float_2_float(float a) { return a; }
+static double double_2_double(double a) { return a; }
+
+/*
+ * check-name: cast-kinds
+ * check-command: test-linearize -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -m64 $file
+ * check-assert: sizeof(void *) == 8 && sizeof(long) == 8 && sizeof(double) == 8
+ *
+ * check-output-start
+uint_2_int:
+.L0:
+	<entry-point>
+	ret.32      %arg1
+
+
+long_2_int:
+.L2:
+	<entry-point>
+	trunc.32    %r4 <- (64) %arg1
+	ret.32      %r4
+
+
+ulong_2_int:
+.L4:
+	<entry-point>
+	trunc.32    %r7 <- (64) %arg1
+	ret.32      %r7
+
+
+vptr_2_int:
+.L6:
+	<entry-point>
+	trunc.32    %r10 <- (64) %arg1
+	ret.32      %r10
+
+
+iptr_2_int:
+.L8:
+	<entry-point>
+	trunc.32    %r14 <- (64) %arg1
+	ret.32      %r14
+
+
+float_2_int:
+.L10:
+	<entry-point>
+	fcvts.32    %r17 <- (32) %arg1
+	ret.32      %r17
+
+
+double_2_int:
+.L12:
+	<entry-point>
+	fcvts.32    %r20 <- (64) %arg1
+	ret.32      %r20
+
+
+int_2_uint:
+.L14:
+	<entry-point>
+	ret.32      %arg1
+
+
+long_2_uint:
+.L16:
+	<entry-point>
+	trunc.32    %r25 <- (64) %arg1
+	ret.32      %r25
+
+
+ulong_2_uint:
+.L18:
+	<entry-point>
+	trunc.32    %r28 <- (64) %arg1
+	ret.32      %r28
+
+
+vptr_2_uint:
+.L20:
+	<entry-point>
+	trunc.32    %r31 <- (64) %arg1
+	ret.32      %r31
+
+
+iptr_2_uint:
+.L22:
+	<entry-point>
+	trunc.32    %r35 <- (64) %arg1
+	ret.32      %r35
+
+
+float_2_uint:
+.L24:
+	<entry-point>
+	fcvtu.32    %r38 <- (32) %arg1
+	ret.32      %r38
+
+
+double_2_uint:
+.L26:
+	<entry-point>
+	fcvtu.32    %r41 <- (64) %arg1
+	ret.32      %r41
+
+
+int_2_long:
+.L28:
+	<entry-point>
+	sext.64     %r44 <- (32) %arg1
+	ret.64      %r44
+
+
+uint_2_long:
+.L30:
+	<entry-point>
+	zext.64     %r47 <- (32) %arg1
+	ret.64      %r47
+
+
+ulong_2_long:
+.L32:
+	<entry-point>
+	ret.64      %arg1
+
+
+vptr_2_long:
+.L34:
+	<entry-point>
+	ret.64      %arg1
+
+
+iptr_2_long:
+.L36:
+	<entry-point>
+	ret.64      %arg1
+
+
+float_2_long:
+.L38:
+	<entry-point>
+	fcvts.64    %r57 <- (32) %arg1
+	ret.64      %r57
+
+
+double_2_long:
+.L40:
+	<entry-point>
+	fcvts.64    %r60 <- (64) %arg1
+	ret.64      %r60
+
+
+int_2_ulong:
+.L42:
+	<entry-point>
+	sext.64     %r63 <- (32) %arg1
+	ret.64      %r63
+
+
+uint_2_ulong:
+.L44:
+	<entry-point>
+	zext.64     %r66 <- (32) %arg1
+	ret.64      %r66
+
+
+long_2_ulong:
+.L46:
+	<entry-point>
+	ret.64      %arg1
+
+
+vptr_2_ulong:
+.L48:
+	<entry-point>
+	ret.64      %arg1
+
+
+iptr_2_ulong:
+.L50:
+	<entry-point>
+	ret.64      %arg1
+
+
+float_2_ulong:
+.L52:
+	<entry-point>
+	fcvtu.64    %r76 <- (32) %arg1
+	ret.64      %r76
+
+
+double_2_ulong:
+.L54:
+	<entry-point>
+	fcvtu.64    %r79 <- (64) %arg1
+	ret.64      %r79
+
+
+int_2_vptr:
+.L56:
+	<entry-point>
+	sext.64     %r82 <- (32) %arg1
+	ret.64      %r82
+
+
+uint_2_vptr:
+.L58:
+	<entry-point>
+	zext.64     %r85 <- (32) %arg1
+	ret.64      %r85
+
+
+long_2_vptr:
+.L60:
+	<entry-point>
+	ret.64      %arg1
+
+
+ulong_2_vptr:
+.L62:
+	<entry-point>
+	ret.64      %arg1
+
+
+iptr_2_vptr:
+.L64:
+	<entry-point>
+	ret.64      %arg1
+
+
+int_2_iptr:
+.L66:
+	<entry-point>
+	sext.64     %r94 <- (32) %arg1
+	ret.64      %r94
+
+
+uint_2_iptr:
+.L68:
+	<entry-point>
+	zext.64     %r98 <- (32) %arg1
+	ret.64      %r98
+
+
+long_2_iptr:
+.L70:
+	<entry-point>
+	ret.64      %arg1
+
+
+ulong_2_iptr:
+.L72:
+	<entry-point>
+	ret.64      %arg1
+
+
+vptr_2_iptr:
+.L74:
+	<entry-point>
+	ptrcast.64  %r108 <- (64) %arg1
+	ret.64      %r108
+
+
+int_2_float:
+.L76:
+	<entry-point>
+	scvtf.32    %r111 <- (32) %arg1
+	ret.32      %r111
+
+
+uint_2_float:
+.L78:
+	<entry-point>
+	ucvtf.32    %r114 <- (32) %arg1
+	ret.32      %r114
+
+
+long_2_float:
+.L80:
+	<entry-point>
+	scvtf.32    %r117 <- (64) %arg1
+	ret.32      %r117
+
+
+ulong_2_float:
+.L82:
+	<entry-point>
+	ucvtf.32    %r120 <- (64) %arg1
+	ret.32      %r120
+
+
+double_2_float:
+.L84:
+	<entry-point>
+	fcvtf.32    %r123 <- (64) %arg1
+	ret.32      %r123
+
+
+int_2_double:
+.L86:
+	<entry-point>
+	scvtf.64    %r126 <- (32) %arg1
+	ret.64      %r126
+
+
+uint_2_double:
+.L88:
+	<entry-point>
+	ucvtf.64    %r129 <- (32) %arg1
+	ret.64      %r129
+
+
+long_2_double:
+.L90:
+	<entry-point>
+	scvtf.64    %r132 <- (64) %arg1
+	ret.64      %r132
+
+
+ulong_2_double:
+.L92:
+	<entry-point>
+	ucvtf.64    %r135 <- (64) %arg1
+	ret.64      %r135
+
+
+float_2_double:
+.L94:
+	<entry-point>
+	fcvtf.64    %r138 <- (32) %arg1
+	ret.64      %r138
+
+
+float_2_float:
+.L96:
+	<entry-point>
+	ret.32      %arg1
+
+
+double_2_double:
+.L98:
+	<entry-point>
+	ret.64      %arg1
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:38 2019
+++ new/usr/src/tools/smatch/src/validation/optim/cast-nop.c	Mon Nov 18 13:20:38 2019
@@ -0,0 +1,18 @@
+static long p2l(long *p)
+{
+	return (long) p;
+}
+
+static long *l2p(long l)
+{
+	return (long*)l;
+}
+
+/*
+ * check-name: cast-nop
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: utptr\\.
+ * check-output-excludes: ptrtu\\.
+ */
--- /dev/null	Mon Nov 18 13:20:38 2019
+++ new/usr/src/tools/smatch/src/validation/optim/cse-cmp-next.c	Mon Nov 18 13:20:38 2019
@@ -0,0 +1,15 @@
+void foo(int p, int i, int f, int *ref, int *dst, int *src)
+{
+	if (p)
+		f = ref[i];
+	if (f)
+		dst[i] = src[i];
+}
+
+/*
+ * check-name: cse-cmp-next
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1,2): mul\\.
+ */
--- /dev/null	Mon Nov 18 13:20:39 2019
+++ new/usr/src/tools/smatch/src/validation/optim/cse-fcmp.c	Mon Nov 18 13:20:39 2019
@@ -0,0 +1,19 @@
+extern void fun(void);
+
+int foo(double a, double b)
+{
+	if (a < b)
+		fun();
+	if (a < b)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * check-name: cse-fcmp
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): fcmp
+ */
--- /dev/null	Mon Nov 18 13:20:39 2019
+++ new/usr/src/tools/smatch/src/validation/optim/cse-setfval.c	Mon Nov 18 13:20:39 2019
@@ -0,0 +1,12 @@
+int ftest(double a, double b)
+{
+	return a == 0.125 || b == 0.125;
+}
+
+/*
+ * check-name: CSE OP_SETFVAL
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): setfval\\.
+ */
--- /dev/null	Mon Nov 18 13:20:39 2019
+++ new/usr/src/tools/smatch/src/validation/optim/cse-size.c	Mon Nov 18 13:20:39 2019
@@ -0,0 +1,17 @@
+static void foo(void)
+{
+	unsigned short p = 0;
+	int x;
+
+	for (;;)
+		if (p)
+			p = x;
+}
+
+/*
+ * check-name: cse-size
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): phi\\.
+ */
--- /dev/null	Mon Nov 18 13:20:39 2019
+++ new/usr/src/tools/smatch/src/validation/optim/dup-cond0.c	Mon Nov 18 13:20:39 2019
@@ -0,0 +1,20 @@
+struct s {
+	int f;
+};
+
+static int foo(struct s *s)
+{
+	if (s->f)
+		return 0;
+	else if (!s->f)
+		return 4;
+	return -1;
+}
+
+/*
+ * check-name: dup-cond0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: select
+ */
--- /dev/null	Mon Nov 18 13:20:39 2019
+++ new/usr/src/tools/smatch/src/validation/optim/ext-trunc-greater.c	Mon Nov 18 13:20:39 2019
@@ -0,0 +1,17 @@
+short sgt(char x)
+{
+	return (int) x;
+}
+
+short ugt(unsigned char x)
+{
+	return (int) x;
+}
+
+/*
+ * check-name: ext-trunc-greater
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:39 2019
+++ new/usr/src/tools/smatch/src/validation/optim/ext-trunc-same.c	Mon Nov 18 13:20:39 2019
@@ -0,0 +1,19 @@
+short seq(short x)
+{
+	return (int) x;
+}
+
+short ueq(unsigned short x)
+{
+	return (int) x;
+}
+
+/*
+ * check-name: ext-trunc-same
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:40 2019
+++ new/usr/src/tools/smatch/src/validation/optim/ext-trunc-smaller.c	Mon Nov 18 13:20:40 2019
@@ -0,0 +1,18 @@
+char  slt(short x)
+{
+	return (int) x;
+}
+
+char  ult(unsigned short x)
+{
+	return (int) x;
+}
+
+/*
+ * check-name: ext-trunc-smaller
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:40 2019
+++ new/usr/src/tools/smatch/src/validation/optim/fpcast-constant.c	Mon Nov 18 13:20:40 2019
@@ -0,0 +1,13 @@
+static double foo(double a, int p)
+{
+	return a * ((p & 0) + 2);
+}
+
+/*
+ * check-name: fpcast-constant
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-contains: scvtf\\.
+ * check-output-excludes: fmul\\..*\\$2
+ */
--- /dev/null	Mon Nov 18 13:20:40 2019
+++ new/usr/src/tools/smatch/src/validation/optim/inline-return.c	Mon Nov 18 13:20:40 2019
@@ -0,0 +1,24 @@
+static inline int def(void)
+{
+	return 1;
+}
+
+int foo(void)
+{
+	return def();
+}
+
+int bar(void)
+{
+	return def();
+	return 0;
+}
+
+/*
+ * check-name: inline-return.c
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(2): ret\\..*\\$1
+ * check-output-excludes: ret\\..*\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:40 2019
+++ new/usr/src/tools/smatch/src/validation/optim/kill-casts.c	Mon Nov 18 13:20:40 2019
@@ -0,0 +1,27 @@
+extern void __abort(void);
+
+struct s {
+	int elem:3;
+};
+
+void foo(struct s *x);
+void foo(struct s *x)
+{
+	if (x->elem == 0) {
+		if (x->elem != 0 && x->elem != 1)
+			__abort();
+	}
+}
+
+/*
+ * check-name: kill-casts
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: cast\\.
+ * check-output-excludes: fcvt[us]\\.
+ * check-output-excludes: utptr\\.
+ * check-output-excludes: ptrtu\\.
+ * check-output-excludes: [sz]ext\\.
+ * check-output-excludes: trunc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:40 2019
+++ new/usr/src/tools/smatch/src/validation/optim/kill-stores0.c	Mon Nov 18 13:20:40 2019
@@ -0,0 +1,34 @@
+struct p {
+	int x, y;
+};
+
+struct q {
+	int w;
+};
+
+static int foo(void)
+{
+	int x = 1;
+	int y = x;
+	return &x == &y;
+}
+
+static int bar(struct p p)
+{
+	if (p.x != 0)
+		;
+}
+
+static int baz(struct p p, struct q q)
+{
+	if (p.x != 0 || p.y != 1 || q.w == 0)
+		;
+}
+
+/*
+ * check-name: kill-stores0
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:40 2019
+++ new/usr/src/tools/smatch/src/validation/optim/kill-stores1.c	Mon Nov 18 13:20:40 2019
@@ -0,0 +1,48 @@
+struct s {
+	int c[1];
+};
+
+static struct s x, y;
+static int p;
+
+static void foo0(void)
+{
+	(x = y).c;		// x = y;
+}
+
+static void foo1(void)
+{
+	int *t = (x = y).c;	// x = y;
+}
+
+static void foo2(void)
+{
+	(x = y).c + 1;		// x = y;
+}
+
+static void foo3(void)
+{
+	(x = y).c[0];		// x = y;
+}
+
+static void foo4(void)
+{
+	(p ? x : y).c[0];	// ;
+}
+
+static void foo5(void)
+{
+	(p, y).c[0];		// ;
+}
+
+/*
+ * check-name: kill-stores1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(4): load\\.
+ * check-output-pattern(4): load\\..*0\\[y\\]
+ * check-output-pattern(4): store\\.
+ * check-output-pattern(4): store\\..*0\\[x\\]
+ * check-output-excludes: select\\.
+ */
--- /dev/null	Mon Nov 18 13:20:40 2019
+++ new/usr/src/tools/smatch/src/validation/optim/kill-stores2.c	Mon Nov 18 13:20:40 2019
@@ -0,0 +1,17 @@
+extern void def(int *);
+
+static void foo(void)
+{
+	int c;
+	def(&c);
+	if (c)
+		c = c;
+}
+
+/*
+ * check-name: kill-stores2
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:41 2019
+++ new/usr/src/tools/smatch/src/validation/optim/killed-insn.c	Mon Nov 18 13:20:41 2019
@@ -0,0 +1,14 @@
+static void foo(int v)
+{
+	int a[2] = { };
+	a;
+	a[1] = v;
+}
+
+/*
+ * check-name: killed-insn
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:41 2019
+++ new/usr/src/tools/smatch/src/validation/optim/live-stores0.c	Mon Nov 18 13:20:41 2019
@@ -0,0 +1,29 @@
+void init(int *x);
+
+static int foo(void)
+{
+	int a[2] = { 0, 123, };
+
+	if (a[1] != 123)
+		return 1;
+	init(a);
+	if (a[1] == 123)
+		return 2;
+	return 0;
+}
+
+#if 0
+void init(int *x)
+{
+	x[0] = x[1] = 0;
+}
+#endif
+
+/*
+ * check-name: live-stores
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-contains: store.32 *\\$123
+ * check-output-pattern(2,3): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:41 2019
+++ new/usr/src/tools/smatch/src/validation/optim/load-converted.c	Mon Nov 18 13:20:41 2019
@@ -0,0 +1,14 @@
+static int foo(int *p, int i)
+{
+	int a = p[i];
+	int b = p[i];
+	return (a - b);
+}
+
+/*
+ * check-name: load-converted
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: add\\.
+ */
--- /dev/null	Mon Nov 18 13:20:41 2019
+++ new/usr/src/tools/smatch/src/validation/optim/load-dead.c	Mon Nov 18 13:20:41 2019
@@ -0,0 +1,11 @@
+void foo(int *p) { *p; }
+
+int *p;
+void bar(void) { *p; }
+
+/*
+ * check-name: load-dead
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ */
--- /dev/null	Mon Nov 18 13:20:41 2019
+++ new/usr/src/tools/smatch/src/validation/optim/load-semi-volatile.c	Mon Nov 18 13:20:41 2019
@@ -0,0 +1,24 @@
+struct s {
+	volatile int a;
+};
+
+struct s s;
+
+void foo(void)
+{
+	s;
+	s.a;
+}
+
+/*
+ * check-name: load-semi-volatile
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): load
+ *
+ * check-description:
+ *	The load at line 9 must be removed.
+ *	The load at line 10 is volatile and thus
+ *	must not be removed.
+ */
--- /dev/null	Mon Nov 18 13:20:41 2019
+++ new/usr/src/tools/smatch/src/validation/optim/lsr-and0.c	Mon Nov 18 13:20:41 2019
@@ -0,0 +1,13 @@
+unsigned lsr_and0(unsigned x)
+{
+	unsigned t = (x & 0x00000fff);
+	return (t >> 12) & t;
+}
+
+/*
+ * check-name: lsr-and0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
--- /dev/null	Mon Nov 18 13:20:41 2019
+++ new/usr/src/tools/smatch/src/validation/optim/lsr-and1.c	Mon Nov 18 13:20:41 2019
@@ -0,0 +1,18 @@
+// If (t >> S) is simplified into (x >> S)
+// then the whole expression will be 0.
+// The test is only interesting if the sub-expression
+// (x & M) is referenced more than once
+// (because otherwise other simplifications apply).
+unsigned lsr_and1(unsigned x)
+{
+	unsigned t = (x & 0xfffff000);
+	return ((t >> 12) ^ (x >> 12)) & t;
+}
+
+/*
+ * check-name: lsr-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
--- /dev/null	Mon Nov 18 13:20:42 2019
+++ new/usr/src/tools/smatch/src/validation/optim/lsr-asr.c	Mon Nov 18 13:20:42 2019
@@ -0,0 +1,42 @@
+int lsrasr0(unsigned int x)
+{
+	return ((int) (x >> 15)) >> 15;
+}
+
+int lsrasr1(unsigned int x)
+{
+	return ((int) (x >> 16)) >> 15;
+}
+
+int lsrasr2(unsigned int x)
+{
+	return ((int) (x >> 16)) >> 16;
+}
+
+/*
+ * check-name: lsr-asr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+lsrasr0:
+.L0:
+	<entry-point>
+	lsr.32      %r3 <- %arg1, $30
+	ret.32      %r3
+
+
+lsrasr1:
+.L2:
+	<entry-point>
+	lsr.32      %r7 <- %arg1, $31
+	ret.32      %r7
+
+
+lsrasr2:
+.L4:
+	<entry-point>
+	ret.32      $0
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:42 2019
+++ new/usr/src/tools/smatch/src/validation/optim/lsr-shl0.c	Mon Nov 18 13:20:42 2019
@@ -0,0 +1,14 @@
+unsigned mask(unsigned x)
+{
+	return (x << 15) >> 15;
+}
+
+/*
+ * check-name: lsr-shl0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*0x1ffff
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: shl\\.
+ */
--- /dev/null	Mon Nov 18 13:20:42 2019
+++ new/usr/src/tools/smatch/src/validation/optim/mask-lsr.c	Mon Nov 18 13:20:42 2019
@@ -0,0 +1,14 @@
+// ((x & M) | y) >> S to (y >> S) when (M >> S) == 0
+
+unsigned int foo(unsigned int x, unsigned int y)
+{
+	return ((x & 0xff) | y) >> 8;
+}
+
+/*
+ * check-name: mask-lsr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: %arg1
+ */
--- /dev/null	Mon Nov 18 13:20:42 2019
+++ new/usr/src/tools/smatch/src/validation/optim/mask-out.c	Mon Nov 18 13:20:42 2019
@@ -0,0 +1,12 @@
+unsigned mask(unsigned a, unsigned b)
+{
+	return ((a & 0xffff0000) | b) & 0x0000ffff;
+}
+
+/*
+ * check-name: mask-out
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: %arg1
+ */
--- /dev/null	Mon Nov 18 13:20:42 2019
+++ new/usr/src/tools/smatch/src/validation/optim/mask1-setne0.c	Mon Nov 18 13:20:42 2019
@@ -0,0 +1,28 @@
+struct s {
+	unsigned i:1;
+};
+
+int foo(struct s x)
+{
+	unsigned int i = x.i;
+
+	if (i == 0)
+		return 1;
+	else if (i == 1)
+		return 1;
+	return 0;
+}
+
+/*
+ * check-name: mask1-setne0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	ret.32      $1
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:42 2019
+++ new/usr/src/tools/smatch/src/validation/optim/missing-select.c	Mon Nov 18 13:20:42 2019
@@ -0,0 +1,23 @@
+static int foo(int **g)
+{
+	int i = 1;
+	int *a[2];
+	int **p;
+
+	a[1] = &i;
+	if (g)
+		p = g;
+	else
+		p = &a[0];
+	if (!g)
+		**p = 0;
+	return i;
+}
+
+/*
+ * check-name: missing-select
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: select\\.
+ */
--- old/usr/src/tools/smatch/src/validation/optim/muldiv-minus-one.c	Mon Nov 18 13:20:43 2019
+++ new/usr/src/tools/smatch/src/validation/optim/muldiv-minus-one.c	Mon Nov 18 13:20:43 2019
@@ -14,5 +14,5 @@
  * check-output-excludes: divs\\.
  * check-output-contains: neg\\.
  * check-output-contains: divu\\.
- * check-output-pattern-3-times: neg\\.
+ * check-output-pattern(3): neg\\.
  */
--- /dev/null	Mon Nov 18 13:20:43 2019
+++ new/usr/src/tools/smatch/src/validation/optim/null-phi.c	Mon Nov 18 13:20:43 2019
@@ -0,0 +1,9 @@
+static int foo(void)
+{
+	if (0)
+		return 0;
+}
+
+/*
+ * check-name: null-phi
+ */
--- /dev/null	Mon Nov 18 13:20:43 2019
+++ new/usr/src/tools/smatch/src/validation/optim/or-and-constant1.c	Mon Nov 18 13:20:43 2019
@@ -0,0 +1,29 @@
+unsigned int and_or_equ(unsigned int a)
+{
+	return (a | 3) & 3;
+}
+
+int and_or_eqs(int a)
+{
+	return (a | 3) & 3;
+}
+
+unsigned int or_and_equ(unsigned int a)
+{
+	return (a & 3) | 3;
+}
+
+int or_and_eqs(int a)
+{
+	return (a & 3) | 3;
+}
+
+/*
+ * check-name: or-and-constant1
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-pattern(4): ret\\..*\\$3
+ * check-output-excludes: or\\.
+ */
--- /dev/null	Mon Nov 18 13:20:43 2019
+++ new/usr/src/tools/smatch/src/validation/optim/phi-ret.c	Mon Nov 18 13:20:43 2019
@@ -0,0 +1,21 @@
+int foo(int p, int q, int v)
+{
+	if (q) {
+		if (p) {
+			v = p;
+			p = 0;
+		}
+	} else
+		p = 0;
+	if (p)
+		return v + 1;
+	return q;
+}
+
+/*
+ * check-name: phi-ret
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: phi\\.
+ */
--- /dev/null	Mon Nov 18 13:20:43 2019
+++ new/usr/src/tools/smatch/src/validation/optim/restrict.c	Mon Nov 18 13:20:43 2019
@@ -0,0 +1,73 @@
+extern int g, h;
+
+void f00u(int *s)
+{
+	g = *s;
+	h = *s;
+}
+
+void f00r(int *restrict s)
+{
+	g = *s;
+	h = *s;
+}
+
+
+void f01u(int *a, int *b, int *s)
+{
+	*a = *s;
+	*b = *s;
+}
+
+void f01r(int *restrict a, int *restrict b, int *restrict s)
+{
+	*a = *s;
+	*b = *s;
+}
+
+/*
+ * check-name: optim/restrict
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-start
+f00u:
+.L0:
+	<entry-point>
+	load.32     %r2 <- 0[%arg1]
+	store.32    %r2 -> 0[g]
+	load.32     %r4 <- 0[%arg1]
+	store.32    %r4 -> 0[h]
+	ret
+
+
+f00r:
+.L2:
+	<entry-point>
+	load.32     %r6 <- 0[%arg1]
+	store.32    %r6 -> 0[g]
+	store.32    %r6 -> 0[h]
+	ret
+
+
+f01u:
+.L4:
+	<entry-point>
+	load.32     %r10 <- 0[%arg3]
+	store.32    %r10 -> 0[%arg1]
+	load.32     %r13 <- 0[%arg3]
+	store.32    %r13 -> 0[%arg2]
+	ret
+
+
+f01r:
+.L6:
+	<entry-point>
+	load.32     %r16 <- 0[%arg3]
+	store.32    %r16 -> 0[%arg1]
+	store.32    %r16 -> 0[%arg2]
+	ret
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:43 2019
+++ new/usr/src/tools/smatch/src/validation/optim/select-zero.c	Mon Nov 18 13:20:43 2019
@@ -0,0 +1,16 @@
+static int sel0(int a)
+{
+	if (a)
+		return 0;
+	else
+		return a;
+}
+
+/*
+ * check-name: select-zero
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret.32 *\\$0
+ * check-output-excludes: select\\.
+ */
--- /dev/null	Mon Nov 18 13:20:44 2019
+++ new/usr/src/tools/smatch/src/validation/optim/setcc-mask.c	Mon Nov 18 13:20:44 2019
@@ -0,0 +1,18 @@
+int foo (int a)
+{
+	return ((a == 0) & 1) == (a == 0);
+}
+
+/*
+ * check-name: setcc-mask
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+	<entry-point>
+	ret.32      $1
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:44 2019
+++ new/usr/src/tools/smatch/src/validation/optim/setne0-sext.c	Mon Nov 18 13:20:44 2019
@@ -0,0 +1,9 @@
+long foo(int a) { return a != 0; }
+
+/*
+ * check-name: setne0-sext
+ * check-command: test-linearize -m64 -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:44 2019
+++ new/usr/src/tools/smatch/src/validation/optim/setne0-trunc.c	Mon Nov 18 13:20:44 2019
@@ -0,0 +1,9 @@
+char foo(int a) { return a != 0; }
+
+/*
+ * check-name: setne0-trunc
+ * check-command: test-linearize -m64 -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:44 2019
+++ new/usr/src/tools/smatch/src/validation/optim/setne0-zext.c	Mon Nov 18 13:20:44 2019
@@ -0,0 +1,9 @@
+unsigned long foo(int a) { return (unsigned int) (a != 0); }
+
+/*
+ * check-name: setne0-zext
+ * check-command: test-linearize -m64 -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:44 2019
+++ new/usr/src/tools/smatch/src/validation/optim/sext-sext.c	Mon Nov 18 13:20:44 2019
@@ -0,0 +1,12 @@
+int foo(signed char offset)
+{
+	return (int)(short) offset;
+}
+
+/*
+ * check-name: sext-sext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): sext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:44 2019
+++ new/usr/src/tools/smatch/src/validation/optim/sext.c	Mon Nov 18 13:20:44 2019
@@ -0,0 +1,15 @@
+int sext(int x)
+{
+	return (x << 5) >> 5;
+}
+
+/*
+ * check-name: sext
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: sext\\.$27
+ * check-output-excludes: asr\\.
+ * check-output-excludes: shl\\.
+ */
--- /dev/null	Mon Nov 18 13:20:44 2019
+++ new/usr/src/tools/smatch/src/validation/optim/sh-or-and0.c	Mon Nov 18 13:20:44 2019
@@ -0,0 +1,20 @@
+unsigned lsr_or_and0(unsigned x, unsigned b)
+{
+	return (((x & 0x00000fff) | b) >> 12);
+}
+
+unsigned shl_or_and0(unsigned x, unsigned b)
+{
+	return (((x & 0xfff00000) | b) << 12);
+}
+
+/*
+ * check-name: sh-or-and0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): shl\\.
+ * check-output-excludes: or\\.
+ * check-output-excludes: and\\.
+ */
--- /dev/null	Mon Nov 18 13:20:45 2019
+++ new/usr/src/tools/smatch/src/validation/optim/sh-or-and1.c	Mon Nov 18 13:20:45 2019
@@ -0,0 +1,20 @@
+unsigned lsr_or_and1(unsigned x, unsigned b)
+{
+	return (((x & 0xfffff000) | b) >> 12);
+}
+
+unsigned shl_or_and1(unsigned x, unsigned b)
+{
+	return (((x & 0x000fffff) | b) << 12);
+}
+
+/*
+ * check-name: sh-or-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): shl\\.
+ * check-output-pattern(2): or\\.
+ * check-output-excludes: and\\.
+ */
--- /dev/null	Mon Nov 18 13:20:45 2019
+++ new/usr/src/tools/smatch/src/validation/optim/sh-or-and2.c	Mon Nov 18 13:20:45 2019
@@ -0,0 +1,21 @@
+unsigned lsr_or_and2(unsigned x, unsigned b)
+{
+	return (((x & 0xf0ffffff) | b) >> 12);
+}
+
+unsigned shl_or_and2(unsigned x, unsigned b)
+{
+	return (((x & 0xffffff0f) | b) << 12);
+}
+
+/*
+ * check-name: sh-or-and2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): lsr\\.
+ * check-output-pattern(1): shl\\.
+ * check-output-pattern(2): or\\.
+ * check-output-pattern(1): and\\..*\\$0xf0fff000
+ * check-output-pattern(1): and\\..*\\$0xfff0f
+ */
--- /dev/null	Mon Nov 18 13:20:45 2019
+++ new/usr/src/tools/smatch/src/validation/optim/shift-big.c	Mon Nov 18 13:20:45 2019
@@ -0,0 +1,82 @@
+typedef unsigned int u32;
+typedef          int s32;
+
+s32 asr31(s32 a) { return a >> 31; }
+s32 asr32(s32 a) { return a >> 32; }
+s32 asr33(s32 a) { return a >> 33; }
+
+u32 lsr31(u32 a) { return a >> 31; }
+u32 lsr32(u32 a) { return a >> 32; }
+u32 lsr33(u32 a) { return a >> 33; }
+
+u32 shl31(u32 a) { return a << 31; }
+u32 shl32(u32 a) { return a << 32; }
+u32 shl33(u32 a) { return a << 33; }
+
+/*
+ * check-name: optim/shift-big.c
+ * check-command: test-linearize -Wno-decl -m64 $file
+ *
+ * check-error-ignore
+ * check-output-start
+asr31:
+.L0:
+	<entry-point>
+	asr.32      %r2 <- %arg1, $31
+	ret.32      %r2
+
+
+asr32:
+.L2:
+	<entry-point>
+	asr.32      %r5 <- %arg1, $32
+	ret.32      %r5
+
+
+asr33:
+.L4:
+	<entry-point>
+	asr.32      %r8 <- %arg1, $33
+	ret.32      %r8
+
+
+lsr31:
+.L6:
+	<entry-point>
+	lsr.32      %r11 <- %arg1, $31
+	ret.32      %r11
+
+
+lsr32:
+.L8:
+	<entry-point>
+	ret.32      $0
+
+
+lsr33:
+.L10:
+	<entry-point>
+	ret.32      $0
+
+
+shl31:
+.L12:
+	<entry-point>
+	shl.32      %r20 <- %arg1, $31
+	ret.32      %r20
+
+
+shl32:
+.L14:
+	<entry-point>
+	ret.32      $0
+
+
+shl33:
+.L16:
+	<entry-point>
+	ret.32      $0
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:45 2019
+++ new/usr/src/tools/smatch/src/validation/optim/shift-shift.c	Mon Nov 18 13:20:45 2019
@@ -0,0 +1,149 @@
+unsigned int shl0(unsigned int x)
+{
+	return x << 15 << 15;
+}
+
+unsigned int shl1(unsigned int x)
+{
+	return x << 16 << 15;
+}
+
+unsigned int shl2(unsigned int x)
+{
+	return x << 16 << 16;
+}
+
+unsigned int shl3(unsigned int x)
+{
+	return x << 12 << 10 << 10;
+}
+
+
+unsigned int lsr0(unsigned int x)
+{
+	return x >> 15 >> 15;
+}
+
+unsigned int lsr1(unsigned int x)
+{
+	return x >> 16 >> 15;
+}
+
+unsigned int lsr2(unsigned int x)
+{
+	return x >> 16 >> 16;
+}
+
+unsigned int lsr3(unsigned int x)
+{
+	return x >> 12 >> 10 >> 10;
+}
+
+
+int asr0(int x)
+{
+	return x >> 15 >> 15;
+}
+
+int asr1(int x)
+{
+	return x >> 16 >> 15;
+}
+
+int asr2(int x)
+{
+	return x >> 16 >> 16;
+}
+
+int asr3(int x)
+{
+	return x >> 12 >> 10 >> 10;
+}
+
+/*
+ * check-name: shift-shift
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+shl0:
+.L0:
+	<entry-point>
+	shl.32      %r3 <- %arg1, $30
+	ret.32      %r3
+
+
+shl1:
+.L2:
+	<entry-point>
+	shl.32      %r7 <- %arg1, $31
+	ret.32      %r7
+
+
+shl2:
+.L4:
+	<entry-point>
+	ret.32      $0
+
+
+shl3:
+.L6:
+	<entry-point>
+	ret.32      $0
+
+
+lsr0:
+.L8:
+	<entry-point>
+	lsr.32      %r20 <- %arg1, $30
+	ret.32      %r20
+
+
+lsr1:
+.L10:
+	<entry-point>
+	lsr.32      %r24 <- %arg1, $31
+	ret.32      %r24
+
+
+lsr2:
+.L12:
+	<entry-point>
+	ret.32      $0
+
+
+lsr3:
+.L14:
+	<entry-point>
+	ret.32      $0
+
+
+asr0:
+.L16:
+	<entry-point>
+	asr.32      %r37 <- %arg1, $30
+	ret.32      %r37
+
+
+asr1:
+.L18:
+	<entry-point>
+	asr.32      %r41 <- %arg1, $31
+	ret.32      %r41
+
+
+asr2:
+.L20:
+	<entry-point>
+	asr.32      %r45 <- %arg1, $31
+	ret.32      %r45
+
+
+asr3:
+.L22:
+	<entry-point>
+	asr.32      %r50 <- %arg1, $31
+	ret.32      %r50
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:45 2019
+++ new/usr/src/tools/smatch/src/validation/optim/shift-zext.c	Mon Nov 18 13:20:45 2019
@@ -0,0 +1,12 @@
+unsigned int foo(unsigned int x)
+{
+	return (x << 20) >> 20;
+}
+
+/*
+ * check-name: shift-zext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*%arg1, \\$0xfff
+ */
--- /dev/null	Mon Nov 18 13:20:45 2019
+++ new/usr/src/tools/smatch/src/validation/optim/shl-and0.c	Mon Nov 18 13:20:45 2019
@@ -0,0 +1,13 @@
+unsigned shl_and0(unsigned x)
+{
+	unsigned t = (x & 0xfff00000);
+	return (t << 12) & t;
+}
+
+/*
+ * check-name: shl-and0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
--- /dev/null	Mon Nov 18 13:20:45 2019
+++ new/usr/src/tools/smatch/src/validation/optim/shl-and1.c	Mon Nov 18 13:20:45 2019
@@ -0,0 +1,18 @@
+// If (t << S) is simplified into (x << S)
+// then the whole expression will be 0.
+// The test is only interesting if the sub-expression
+// (x & M) is referenced more than once
+// (because otherwise other simplifications apply).
+unsigned shl_and1(unsigned x)
+{
+	unsigned t = (x & 0x000fffff);
+	return ((t << 12) ^ (x << 12)) & t;
+}
+
+/*
+ * check-name: shl-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0$
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/shl-lsr0.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,14 @@
+unsigned mask(unsigned x)
+{
+	return (x >> 15) << 15;
+}
+
+/*
+ * check-name: shl-lsr0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*0xffff8000
+ * check-output-excludes: lsr\\.
+ * check-output-excludes: shl\\.
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/store-dominated.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,15 @@
+static int a[];
+
+static void foo(void)
+{
+	int *c = &a[1];
+	*c = *c = 0;
+}
+
+/*
+ * check-name: store-dominated
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-excludes: add\\.
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/trivial-phis.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,14 @@
+void foo(int a)
+{
+	while (1)
+		a ^= 0;
+}
+
+/*
+ * check-name: trivial phis
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: phi\\.
+ * check-output-excludes: phisrc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/trunc-mask-zext.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,13 @@
+unsigned long long foo(unsigned long long x)
+{
+	return (((unsigned int) x) & 0x7ffU);
+}
+
+/*
+ * check-name: trunc-mask-zext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/trunc-or-shl.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,13 @@
+char foo(int a, int b)
+{
+	return (a << 8) | b;
+}
+
+/*
+ * check-name: trunc-or-shl
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*%arg2
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/trunc-seteq0.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,18 @@
+struct S {
+	         int  :1;
+	  signed int s:2;
+	unsigned int u:3;
+};
+
+int os(int i, struct S *b) { return i || b->s; }
+int ou(int i, struct S *b) { return i || b->u; }
+
+/*
+ * check-name: trunc-seteq0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: trunc\\.
+ * check-output-excludes: sext\\.
+ * check-output-excludes: zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/trunc-setne0.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,20 @@
+struct s {
+	unsigned int u:1;
+};
+
+unsigned int foo(struct s x)
+{
+	if (x.u)
+		return 1;
+	else
+		return 0;
+}
+
+/*
+ * check-name: trunc-setne0
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\.
+ * check-output-excludes: trunc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:46 2019
+++ new/usr/src/tools/smatch/src/validation/optim/trunc-trunc.c	Mon Nov 18 13:20:46 2019
@@ -0,0 +1,12 @@
+char foo(int a)
+{
+	return ((((short) a) + 1) - 1);
+}
+
+/*
+ * check-name: trunc-trunc
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): trunc\\.
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/volatile-bitfield.c	Mon Nov 18 13:20:47 2019
@@ -0,0 +1,16 @@
+struct s {
+	int f:3;
+};
+
+void foo(volatile struct s *p)
+{
+	p->f;
+}
+
+/*
+ * check-name: volatile-bitfield
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/volatile-side-effect.c	Mon Nov 18 13:20:47 2019
@@ -0,0 +1,13 @@
+void foo(int p, volatile int *ptr)
+{
+	p ? : *ptr;
+	p ? : *ptr;
+}
+
+/*
+ * check-name: volatile-side-effect
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-pattern(2): load
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/volatile-store00.c	Mon Nov 18 13:20:47 2019
@@ -0,0 +1,27 @@
+void foo(volatile int *p)
+{
+	*p = 0;
+	*p = 0;
+}
+
+void bar(void)
+{
+	extern volatile int i;
+	i = 0;
+	i = 0;
+}
+
+
+void baz(void)
+{
+	volatile int i;
+	i = 0;
+	i = 0;
+}
+
+/*
+ * check-name: keep volatile stores
+ * check-command: test-linearize -Wno-decl -fdump-ir=final $file
+ * check-output-ignore
+ * check-output-pattern(6): store\\.
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/zext-and.c	Mon Nov 18 13:20:47 2019
@@ -0,0 +1,12 @@
+unsigned int foo(unsigned char x)
+{
+	return (unsigned int)x & 0xffffU;
+}
+
+/*
+ * check-name: zext-and
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: and\\.
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/zext-and1.c	Mon Nov 18 13:20:47 2019
@@ -0,0 +1,12 @@
+unsigned int bar(unsigned char x)
+{
+	return (unsigned int)x & 0xff01U;
+}
+
+/*
+ * check-name: zext-and1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: and\\..*\\$1
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/zext-asr.c	Mon Nov 18 13:20:47 2019
@@ -0,0 +1,13 @@
+unsigned short foo(unsigned short a)
+{
+	return a >> 16;
+}
+
+/*
+ * check-name: zext-asr
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0
+ * check-output-excludes: asr\\.
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/zext-sext.c	Mon Nov 18 13:20:47 2019
@@ -0,0 +1,13 @@
+int foo(unsigned char offset)
+{
+	return (int)(short) offset;
+}
+
+/*
+ * check-name: zext-sext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-pattern(1): zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:47 2019
+++ new/usr/src/tools/smatch/src/validation/optim/zext-zext.c	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,13 @@
+int foo(unsigned char offset)
+{
+	return (int)(unsigned short) offset;
+}
+
+/*
+ * check-name: zext-zext
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: sext\\.
+ * check-output-pattern(1): zext\\.
+ */
--- /dev/null	Mon Nov 18 13:20:48 2019
+++ new/usr/src/tools/smatch/src/validation/option-parsing-00.c	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,5 @@
+
+/*
+ * check-name: option parsing 00
+ * check-command: sparse -foptimize-xyz $file
+ */
--- /dev/null	Mon Nov 18 13:20:48 2019
+++ new/usr/src/tools/smatch/src/validation/option-parsing-01.c	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,5 @@
+
+/*
+ * check-name: option parsing 01
+ * check-command: sparse -fno-optimize-xyz $file
+ */
--- /dev/null	Mon Nov 18 13:20:48 2019
+++ new/usr/src/tools/smatch/src/validation/overflow.c	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,19 @@
+extern int a;
+
+int a = __INT_MAX__ * 2;
+
+int foo(void)
+{
+	return __INT_MAX__ * 2;
+}
+
+/*
+ * check-name: overflow
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-known-to-fail
+ * check-error-start
+bug-overflow.c:3:21: warning: integer overflow in expression
+bug-overflow.c:7:28: warning: integer overflow in expression
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:48 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/base-file.c	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,17 @@
+__FILE__
+__BASE_FILE__
+
+#include "base-file.h"
+
+/*
+ * check-name: base file
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"preprocessor/base-file.c"
+"preprocessor/base-file.c"
+"preprocessor/base-file.h"
+"preprocessor/base-file.c"
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:48 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/base-file.h	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,2 @@
+__FILE__
+__BASE_FILE__
--- /dev/null	Mon Nov 18 13:20:48 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/builtin.c	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,17 @@
+__CHECKER__
+F(__CHECKER__,__CHECKER__)
+S(#__CHECKER__)
+const char str[] = "__CHECKER__";
+
+/*
+ * check-name: builtin
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+1
+F(1,1)
+S(#1)
+const char str[] = "__CHECKER__";
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:48 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/cli-D-arg.c	Mon Nov 18 13:20:48 2019
@@ -0,0 +1,12 @@
+A
+B
+/*
+ * check-name: cli: -D MACRO
+ * check-command: sparse -E -D A -D B=abc $file
+ *
+ * check-output-start
+
+1
+abc
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:49 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/cli-D-space.c	Mon Nov 18 13:20:49 2019
@@ -0,0 +1,10 @@
+M(0,1)
+/*
+ * check-name: cli: allow spaces in macros
+ * check-command: sparse -E '-DM(X, Y)=a' $file
+ *
+ * check-output-start
+
+a
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-empty.c	Mon Nov 18 13:20:49 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-empty.c	Mon Nov 18 13:20:49 2019
@@ -3,5 +3,5 @@
  * check-command: sparse -E -dD empty-file
  *
  * check-output-ignore
-check-output-pattern-1-times: #define __CHECKER__ 1
+check-output-pattern(1): #define __CHECKER__ 1
  */
--- old/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-multi.c	Mon Nov 18 13:20:49 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-multi.c	Mon Nov 18 13:20:49 2019
@@ -3,5 +3,5 @@
  * check-command: sparse -E -dD empty-file $file
  *
  * check-output-ignore
-check-output-pattern-2-times: #define __CHECKER__ 1
+check-output-pattern(2): #define __CHECKER__ 1
  */
--- /dev/null	Mon Nov 18 13:20:49 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-only.c	Mon Nov 18 13:20:49 2019
@@ -0,0 +1,36 @@
+
+#define ABC abc
+#undef ABC
+
+#define	DEF def
+#undef DEF
+#define DEF xyz
+
+#define NYDEF ydef
+
+#define STRING(x) #x
+#define CONCAT(x,y) x ## y
+
+#define unlocks(...) annotate(unlock_func(__VA_ARGS__))
+#define apply(x,...) x(__VA_ARGS__)
+
+int main(int argc, char *argv[])
+{
+	return 0;
+}
+/*
+ * check-name: dump-macros only -dM
+ * check-command: sparse -E -dM -DIJK=ijk -UNDEF -UNYDEF $file
+ *
+ * check-output-ignore
+check-output-pattern(1): #define __CHECKER__ 1
+check-output-contains: #define IJK ijk
+check-output-contains: #define DEF xyz
+check-output-contains: #define NYDEF ydef
+check-output-contains: #define STRING(x) #x
+check-output-contains: #define CONCAT(x,y) x ## y
+check-output-contains: #define unlocks(...) annotate(unlock_func(__VA_ARGS__))
+check-output-contains: #define apply(x,...) x(__VA_ARGS__)
+check-output-excludes: int main(int argc, char \\*argv\\[\\])
+check-output-excludes: ^\\[^#]
+ */
--- old/usr/src/tools/smatch/src/validation/preprocessor/dump-macros.c	Mon Nov 18 13:20:49 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/dump-macros.c	Mon Nov 18 13:20:50 2019
@@ -6,13 +6,29 @@
 #define DEF xyz
 
 #define NYDEF ydef
+
+#define STRING(x) #x
+#define CONCAT(x,y) x ## y
+
+#define unlocks(...) annotate(unlock_func(__VA_ARGS__))
+#define apply(x,...) x(__VA_ARGS__)
+
+int main(int argc, char *argv[])
+{
+	return 0;
+}
 /*
  * check-name: dump-macros
  * check-command: sparse -E -dD -DIJK=ijk -UNDEF -UNYDEF $file
  *
  * check-output-ignore
-check-output-pattern-1-times: #define __CHECKER__ 1
+check-output-pattern(1): #define __CHECKER__ 1
 check-output-contains: #define IJK ijk
 check-output-contains: #define DEF xyz
 check-output-contains: #define NYDEF ydef
+check-output-contains: #define STRING(x) #x
+check-output-contains: #define CONCAT(x,y) x ## y
+check-output-contains: #define unlocks(...) annotate(unlock_func(__VA_ARGS__))
+check-output-contains: #define apply(x,...) x(__VA_ARGS__)
+check-output-contains: int main(int argc, char \\*argv\\[\\])
  */
--- /dev/null	Mon Nov 18 13:20:50 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/dynamic.c	Mon Nov 18 13:20:50 2019
@@ -0,0 +1,37 @@
+#if defined(__LINE__)
+__LINE__
+#endif
+#if defined(__FILE__)
+__FILE__
+#endif
+#if defined(__BASE_FILE__)
+__BASE_FILE__
+#endif
+#if defined(__DATE__)
+date
+#endif
+#if defined(__TIME__)
+time
+#endif
+#if defined(__COUNTER__)
+counter
+#endif
+#if defined(__INCLUDE_LEVEL__)
+__INCLUDE_LEVEL__
+#endif
+
+/*
+ * check-name: dynamic-macros
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+2
+"preprocessor/dynamic.c"
+"preprocessor/dynamic.c"
+date
+time
+counter
+0
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:50 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/extra-token.c	Mon Nov 18 13:20:50 2019
@@ -0,0 +1,15 @@
+#define THIS 0
+#ifdef THIS == 1
+#endif
+
+/*
+ * check-name: preprocessor/extra-token.c
+ * check-command: sparse -E $file
+ * check-known-to-fail
+ *
+ * check-error-start
+preprocessor/extra-token.c:2:13: warning: extra tokens at end of #ifdef directive
+ * check-error-end
+ *
+ * check-output-ignore
+ */
--- /dev/null	Mon Nov 18 13:20:50 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/has-attribute.c	Mon Nov 18 13:20:50 2019
@@ -0,0 +1,56 @@
+#ifndef __has_attribute
+__has_attribute()??? Quesako?
+#define __has_attribute(x) 0
+#else
+"has __has_attribute(), yeah!"
+#endif
+
+123 __has_attribute(nothinx) def
+
+#if __has_attribute(nothinx)
+#error "not a attribute!"
+#endif
+
+#if 1					\
+ && __has_attribute(packed)		\
+ && __has_attribute(aligned)		\
+ && __has_attribute(const)		\
+ && __has_attribute(pure)		\
+ && __has_attribute(noreturn)		\
+ && __has_attribute(designated_init)	\
+ && __has_attribute(transparent_union)	\
+
+"ok gcc"
+#endif
+
+#if 1					\
+ && __has_attribute(fastcall)		\
+
+"ok gcc ignore"
+#endif
+
+#if 1					\
+ && __has_attribute(nocast)		\
+ && __has_attribute(noderef)		\
+ && __has_attribute(safe)		\
+ && __has_attribute(force)		\
+ && __has_attribute(bitwise)		\
+ && __has_attribute(address_space)	\
+ && __has_attribute(context)		\
+
+"ok sparse specific"
+#endif
+
+/*
+ * check-name: has-attribute
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"has __has_attribute(), yeah!"
+123 0 def
+"ok gcc"
+"ok gcc ignore"
+"ok sparse specific"
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:50 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/has-builtin.c	Mon Nov 18 13:20:50 2019
@@ -0,0 +1,43 @@
+#ifndef __has_builtin
+__has_builtin()??? Quesako?
+#define __has_builtin(x) 0
+#else
+"has __has_builtin(), yeah!"
+#endif
+
+#if __has_builtin(nothing)
+#error "not a builtin!"
+#endif
+
+#if __has_builtin(__builtin_offsetof)		\
+ || __has_builtin(__builtin_types_compatible_p)
+#error "builtin ops are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_va_list)		\
+ || __has_builtin(__builtin_ms_va_list)
+#error "builtin types are not builtin functions!"
+#endif
+
+#if __has_builtin(__builtin_abs)
+abs
+#endif
+
+#if __has_builtin(__builtin_constant_p)
+constant_p
+#endif
+
+123 __has_builtin(abc) def
+
+/*
+ * check-name: has-builtin
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"has __has_builtin(), yeah!"
+abs
+constant_p
+123 0 def
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:50 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/ident-pragma.c	Mon Nov 18 13:20:50 2019
@@ -0,0 +1,12 @@
+#pragma ident "foo"
+
+/*
+ * check-description: check that '#pragma ident ... " is ignored.
+ * check-name: ident-pragma
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:51 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/ident.c	Mon Nov 18 13:20:51 2019
@@ -0,0 +1,12 @@
+#ident "foo"
+
+/*
+ * check-description: check that the non-standard "#ident ..." is ignored.
+ * check-name: ident
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:51 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/include-level.c	Mon Nov 18 13:20:51 2019
@@ -0,0 +1,14 @@
+__FILE__: __INCLUDE_LEVEL__
+
+#include "include-level.h"
+
+/*
+ * check-name: include-level
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"preprocessor/include-level.c": 0
+"preprocessor/include-level.h": 1
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:51 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/include-level.h	Mon Nov 18 13:20:51 2019
@@ -0,0 +1,1 @@
+__FILE__: __INCLUDE_LEVEL__
--- /dev/null	Mon Nov 18 13:20:51 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/missing-delim.c	Mon Nov 18 13:20:51 2019
@@ -0,0 +1,17 @@
+static int  c = 'a;
+
+static char s[] = "abc;
+static char t[] = "xyz";
+
+extern void foo(void);
+
+/*
+ * check-name: missing-delim
+ * check-command: sparse -E $file
+ * check-output-ignore
+ *
+ * check-error-start
+preprocessor/missing-delim.c:2:0: warning: missing terminating ' character
+preprocessor/missing-delim.c:4:0: warning: missing terminating " character
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/phase2/backslash	Mon Nov 18 13:20:51 2019
+++ /dev/null	Mon Nov 18 13:20:51 2019
@@ -1,62 +0,0 @@
-/*
- *	'\\' has a special meaning on phase 2 if and only if it is immediately
- * followed by '\n'.  In any other position it's left alone as any other
- * character.
- *
- * [5.1.1.2(1.2)]:
- *   Each instance of a backslash character (\) immediately followed by
- *   a new-line character is deleted, splicing physical source lines to
- *   form logical source lines.  Only the last backslash on any physical
- *   source line shall be eligible for being part of such a splice.
- *   A source file that is not empty shall end in a new-line character,
- *   which shall not be immediately preceded by a backslash character
- *   before any such splicing takes place.
- *
- * Note that this happens on the phase 2, before we even think of any
- * tokens.  In other words, splicing is ignorant of and transparent for
- * the rest of tokenizer.
- */
-
-#define A(x) #x
-#define B(x) A(x)
-/* This should result in "\a" */
-/* XXX: currently sparse produces "a" */
-/* Partially fixed: now it gives "\\a", which is a separate problem */
-B(\a)
-
-#define C\
- 1
-/* This should give 1 */
-C
-
-#define D\
-1
-/* And this should give D, since '\n' is removed and we get no whitespace */
-/* XXX: currently sparse produces 1 */
-/* Fixed */
-D
-
-#define E '\\
-a'
-/* This should give '\a' - with no warnings issued */
-/* XXX: currently sparse complains a lot and ends up producing a */
-/* Fixed */
-E
-
-/* This should give nothing */
-/* XXX: currently sparse produces more junk */
-/* Fixed */
-// junk \
-more junk
-
-/* This should also give nothing */
-/* XXX: currently sparse produces / * comment * / */
-/* Fixed */
-/\
-* comment *\
-/
-
-/* And this should complain since final newline should not be eaten by '\\' */
-/* XXX: currently sparse does not notice */
-/* Fixed */
-\
--- /dev/null	Mon Nov 18 13:20:51 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/phase2-backslash.c	Mon Nov 18 13:20:51 2019
@@ -0,0 +1,67 @@
+/*
+ *	'\\' has a special meaning on phase 2 if and only if it is immediately
+ * followed by '\n'.  In any other position it's left alone as any other
+ * character.
+ *
+ * [5.1.1.2(1.2)]:
+ *   Each instance of a backslash character (\) immediately followed by
+ *   a new-line character is deleted, splicing physical source lines to
+ *   form logical source lines.  Only the last backslash on any physical
+ *   source line shall be eligible for being part of such a splice.
+ *   A source file that is not empty shall end in a new-line character,
+ *   which shall not be immediately preceded by a backslash character
+ *   before any such splicing takes place.
+ *
+ * Note that this happens on the phase 2, before we even think of any
+ * tokens.  In other words, splicing is ignorant of and transparent for
+ * the rest of tokenizer.
+ */
+
+/*
+ * check-name: phase2-backslash
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"\a"
+1
+D
+'\a'
+ * check-output-end
+ *
+ * check-error-start
+preprocessor/phase2-backslash.c:68:0: warning: backslash-newline at end of file
+ * check-error-end
+ */
+
+#define A(x) #x
+#define B(x) A(x)
+/* This should result in "\a" */
+B(\a)
+
+#define C\
+ 1
+/* This should give 1 */
+C
+
+#define D\
+1
+/* And this should give D, since '\n' is removed and we get no whitespace */
+D
+
+#define E '\\
+a'
+/* This should give '\a' - with no warnings issued */
+E
+
+/* This should give nothing */
+// junk \
+more junk
+
+/* This should also give nothing */
+/\
+* comment *\
+/
+
+/* And this should complain since final newline should not be eaten by '\\' */
+\
--- /dev/null	Mon Nov 18 13:20:51 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/phase3-comments.c	Mon Nov 18 13:20:51 2019
@@ -0,0 +1,17 @@
+/*
+ *  Each comment should be treated as if it had been a single space.
+ */
+
+/* This should give nothing */
+#define X /*
+ */ Y
+
+/*
+ * check-name: phase3-comments
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/preprocessor/predef-char-bit.c	Mon Nov 18 13:20:52 2019
+++ /dev/null	Mon Nov 18 13:20:52 2019
@@ -1,16 +0,0 @@
-#define TEST_BIT(X, T)	if (__ ## X ## _BIT__  != 8 * sizeof(T)) return 1
-
-int test(void)
-{
-	TEST_BIT(CHAR, char);
-
-	return 0;
-}
-
-/*
- * check-name: predefined __<type>_BIT__
- * check-command: test-linearize -Wno-decl $file
- * check-output-ignore
- *
- * check-output-contains: ret\\..*\\$0
- */
--- /dev/null	Mon Nov 18 13:20:52 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/predef-llp64.c	Mon Nov 18 13:20:52 2019
@@ -0,0 +1,9 @@
+#include "predef.c"
+
+/*
+ * check-name: predefined macros for LLP64
+ * check-command: test-linearize -Wno-decl -msize-llp64 $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..*\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:52 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/predef-lp32.c	Mon Nov 18 13:20:52 2019
@@ -0,0 +1,9 @@
+#include "predef.c"
+
+/*
+ * check-name: predefined macros for LP32
+ * check-command: test-linearize -Wno-decl -m32 $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..*\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:52 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/predef-lp64.c	Mon Nov 18 13:20:52 2019
@@ -0,0 +1,9 @@
+#include "predef.c"
+
+/*
+ * check-name: predefined macros for LP64
+ * check-command: test-linearize -Wno-decl -m64 $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..*\\$0
+ */
--- old/usr/src/tools/smatch/src/validation/preprocessor/predef-max.c	Mon Nov 18 13:20:52 2019
+++ /dev/null	Mon Nov 18 13:20:52 2019
@@ -1,18 +0,0 @@
-#define TEST_MAX(X, Z)	if (X != ((~ Z) >> 1))	return 1
-
-int test_max(void)
-{
-	TEST_MAX(__INT_MAX__, 0U);
-	TEST_MAX(__LONG_MAX__, 0UL);
-	TEST_MAX(__LONG_LONG_MAX__, 0ULL);
-
-	return 0;
-}
-
-/*
- * check-name: predefined __<type>_MAX__
- * check-command: test-linearize -Wno-decl $file
- * check-output-ignore
- *
- * check-output-contains: ret\\..*\\$0
- */
--- old/usr/src/tools/smatch/src/validation/preprocessor/predef-sizeof.c	Mon Nov 18 13:20:52 2019
+++ /dev/null	Mon Nov 18 13:20:52 2019
@@ -1,25 +0,0 @@
-#define TEST(X, T)	if (__SIZEOF_ ## X ## __ != sizeof(T))	return 1
-
-int test_sizeof(void)
-{
-	TEST(SHORT, short);
-	TEST(INT, int);
-	TEST(LONG, long);
-	TEST(LONG_LONG, long long);
-	TEST(INT128, __int128);
-	TEST(SIZE_T, __SIZE_TYPE__);
-	TEST(POINTER, void*);
-	TEST(FLOAT, float);
-	TEST(DOUBLE, double);
-	TEST(LONG_DOUBLE, long double);
-
-	return 0;
-}
-
-/*
- * check-name: predefined __SIZEOF_<type>__
- * check-command: test-linearize -Wno-decl $file
- * check-output-ignore
- *
- * check-output-contains: ret\\..*\\$0
- */
--- /dev/null	Mon Nov 18 13:20:52 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/predef-unsigned.c	Mon Nov 18 13:20:52 2019
@@ -0,0 +1,9 @@
+#include "predef.c"
+
+/*
+ * check-name: predefined macros for -funsigned-char
+ * check-command: test-linearize -Wno-decl -funsigned-char $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..*\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:53 2019
+++ new/usr/src/tools/smatch/src/validation/preprocessor/predef.c	Mon Nov 18 13:20:53 2019
@@ -0,0 +1,57 @@
+#define BITS(T)		(sizeof(T) * 8)
+#define SIGN_BIT(T)	(1ULL << (BITS(T) - 1))
+#define SMASK(T)	(SIGN_BIT(T) - 1)
+#define UMASK(T)	(SIGN_BIT(T) | SMASK(T))
+
+int test(void);
+int test(void)
+{
+#define TEST_BIT(X, T)	if (__ ## X ## _BIT__  != BITS(T)) return 1
+	TEST_BIT(CHAR, char);
+
+#define TEST_MAX(X, M)	if (__ ## X ## _MAX__ != M) return 1
+#define TEST_SMAX(X, T)	TEST_MAX(X, SMASK(T))
+#define TEST_UMAX(X, T)	TEST_MAX(X, UMASK(T))
+	TEST_SMAX(SCHAR, signed char);
+	TEST_SMAX(SHRT, short);
+	TEST_SMAX(INT, int);
+	TEST_SMAX(LONG, long);
+	TEST_SMAX(LONG_LONG, long long);
+	TEST_MAX( INT8,  0x7f);
+	TEST_MAX(UINT8,  0xffU);
+	TEST_MAX( INT16, 0x7fff);
+	TEST_MAX(UINT16, 0xffffU);
+	TEST_MAX( INT32, 0x7fffffff);
+	TEST_MAX(UINT32, 0xffffffffU);
+	TEST_MAX( INT64, 0x7fffffffffffffffLL);
+	TEST_MAX(UINT64, 0xffffffffffffffffULL);
+	TEST_SMAX(INTMAX, __INTMAX_TYPE__);
+	TEST_UMAX(UINTMAX, __UINTMAX_TYPE__);
+	TEST_SMAX(INTPTR, __INTPTR_TYPE__);
+	TEST_UMAX(UINTPTR, __UINTPTR_TYPE__);
+	TEST_SMAX(PTRDIFF, __PTRDIFF_TYPE__);
+	TEST_UMAX(SIZE, __SIZE_TYPE__);
+
+#define TEST_SIZEOF(X, T) if (__SIZEOF_ ## X ## __ != sizeof(T)) return 1
+	TEST_SIZEOF(SHORT, short);
+	TEST_SIZEOF(INT, int);
+	TEST_SIZEOF(LONG, long);
+	TEST_SIZEOF(LONG_LONG, long long);
+	TEST_SIZEOF(INT128, __int128);
+	TEST_SIZEOF(PTRDIFF_T, __PTRDIFF_TYPE__);
+	TEST_SIZEOF(SIZE_T, __SIZE_TYPE__);
+	TEST_SIZEOF(POINTER, void*);
+	TEST_SIZEOF(FLOAT, float);
+	TEST_SIZEOF(DOUBLE, double);
+	TEST_SIZEOF(LONG_DOUBLE, long double);
+
+	return 0;
+}
+
+/*
+ * check-name: predefined macros: __SIZEOF_<type>__, ...
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..*\\$0
+ */
--- old/usr/src/tools/smatch/src/validation/ptr-inherit.c	Mon Nov 18 13:20:53 2019
+++ new/usr/src/tools/smatch/src/validation/ptr-inherit.c	Mon Nov 18 13:20:53 2019
@@ -63,18 +63,18 @@
  * check-error-start
 ptr-inherit.c:12:19: warning: incorrect type in initializer (different modifiers)
 ptr-inherit.c:12:19:    expected int *p
-ptr-inherit.c:12:19:    got int const *<noident>
+ptr-inherit.c:12:19:    got int const *
 ptr-inherit.c:18:19: warning: incorrect type in initializer (different modifiers)
 ptr-inherit.c:18:19:    expected int *p
-ptr-inherit.c:18:19:    got int volatile *<noident>
+ptr-inherit.c:18:19:    got int volatile *
 ptr-inherit.c:24:19: warning: incorrect type in initializer (different modifiers)
 ptr-inherit.c:24:19:    expected int *p
-ptr-inherit.c:24:19:    got int [noderef] *<noident>
+ptr-inherit.c:24:19:    got int [noderef] *
 ptr-inherit.c:30:19: warning: incorrect type in initializer (different base types)
 ptr-inherit.c:30:19:    expected int *p
-ptr-inherit.c:30:19:    got restricted int *<noident>
+ptr-inherit.c:30:19:    got restricted int *
 ptr-inherit.c:36:19: warning: incorrect type in initializer (different address spaces)
 ptr-inherit.c:36:19:    expected int *p
-ptr-inherit.c:36:19:    got int <asn:1>*<noident>
+ptr-inherit.c:36:19:    got int <asn:1> *
  * check-error-end
  */
--- /dev/null	Mon Nov 18 13:20:53 2019
+++ new/usr/src/tools/smatch/src/validation/ptr-sub-blows.c	Mon Nov 18 13:20:53 2019
@@ -0,0 +1,23 @@
+static int ok(int *a, int *b)
+{
+	return a - b;
+}
+
+struct s {
+	int a, b, c;
+};
+
+static int ko(struct s *a, struct s *b)
+{
+	return a - b;
+}
+
+/*
+ * check-name: ptr-sub-blows
+ * check-command: sparse -Wptr-subtraction-blows $file
+ *
+ * check-error-start
+ptr-sub-blows.c:12:18: warning: potentially expensive pointer subtraction
+ptr-sub-blows.c:12:18:     'struct s' has a non-power-of-2 size: 12
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:53 2019
+++ new/usr/src/tools/smatch/src/validation/range-syntax.c	Mon Nov 18 13:20:53 2019
@@ -0,0 +1,23 @@
+
+static void ok(int a, int b, int c)
+{
+	__range__(a, 0, 8);
+	__range__(a, b, c);
+}
+
+static void ko(int a, int b, int c)
+{
+	__range__ a, 0, 8;
+	__range__ a, b, c;
+}
+
+/*
+ * check-name: range syntax
+ *
+ * check-error-start
+range-syntax.c:10:19: error: Expected ( after __range__ statement
+range-syntax.c:10:19: error: got a
+range-syntax.c:11:19: error: Expected ( after __range__ statement
+range-syntax.c:11:19: error: got a
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:53 2019
+++ new/usr/src/tools/smatch/src/validation/repeat.h	Mon Nov 18 13:20:53 2019
@@ -0,0 +1,24 @@
+#define  R0(P, S)  P(S)
+#define  R1(P, S)  R0(P,S##0)  R0(P,S##1)
+#define  R2(P, S)  R0(P,S##0)  R0(P,S##1)  R0(P,S##2)  R0(P,S##3)
+#define  R3(P, S)  R0(P,S##0)  R0(P,S##1)  R0(P,S##2)  R0(P,S##3)  R0(P,S##4)  R0(P,S##5)  R0(P,S##6)  R0(P,S##7)
+#define  R4(P, S)  R3(P,S##0)  R3(P,S##1)
+#define  R5(P, S)  R3(P,S##0)  R3(P,S##1)  R3(P,S##2)  R3(P,S##3)
+#define  R6(P, S)  R3(P,S##0)  R3(P,S##1)  R3(P,S##2)  R3(P,S##3)  R3(P,S##4)  R3(P,S##5)  R3(P,S##6)  R3(P,S##7)
+#define  R7(P, S)  R6(P,S##0)  R6(P,S##1)
+#define  R8(P, S)  R6(P,S##0)  R6(P,S##1)  R6(P,S##2)  R6(P,S##3)
+#define  R9(P, S)  R6(P,S##0)  R6(P,S##1)  R6(P,S##2)  R6(P,S##3)  R6(P,S##4)  R6(P,S##5)  R6(P,S##6)  R6(P,S##7)
+#define R10(P, S)  R9(P,S##0)  R9(P,S##1)
+#define R11(P, S)  R9(P,S##0)  R9(P,S##1)  R9(P,S##2)  R9(P,S##3)
+#define R12(P, S)  R9(P,S##0)  R9(P,S##1)  R9(P,S##2)  R9(P,S##3)  R9(P,S##4)  R9(P,S##5)  R9(P,S##6)  R9(P,S##7)
+#define R13(P, S) R12(P,S##0) R12(P,S##1)
+#define R14(P, S) R12(P,S##0) R12(P,S##1) R12(P,S##2) R12(P,S##3)
+#define R15(P, S) R12(P,S##0) R12(P,S##1) R12(P,S##2) R12(P,S##3) R12(P,S##4) R12(P,S##5) R12(P,S##6) R12(P,S##7)
+#define R16(P, S) R15(P,S##0) R15(P,S##1)
+#define R17(P, S) R15(P,S##0) R15(P,S##1) R15(P,S##2) R15(P,S##3)
+#define R18(P, S) R15(P,S##0) R15(P,S##1) R15(P,S##2) R15(P,S##3) R15(P,S##4) R15(P,S##5) R15(P,S##6) R15(P,S##7)
+#define R19(P, S) R18(P,S##0) R18(P,S##1)
+#define R20(P, S) R18(P,S##0) R18(P,S##1) R18(P,S##2) R18(P,S##3)
+
+#define REPEAT_(RN, P)	RN(P,)
+#define REPEAT2(N, P)	REPEAT_(R##N,P)
--- old/usr/src/tools/smatch/src/validation/reserved.c	Mon Nov 18 13:20:54 2019
+++ new/usr/src/tools/smatch/src/validation/reserved.c	Mon Nov 18 13:20:54 2019
@@ -81,7 +81,7 @@
 
 /*
  * check-name: const et.al. are reserved identifiers
- * check-error-start:
+ * check-error-start
 reserved.c:1:12: error: Trying to use reserved word 'auto' as identifier
 reserved.c:2:12: error: Trying to use reserved word 'break' as identifier
 reserved.c:3:12: error: Trying to use reserved word 'case' as identifier
@@ -154,5 +154,5 @@
 reserved.c:78:12: error: Trying to use reserved word '__builtin_offsetof' as identifier
 reserved.c:79:12: error: Trying to use reserved word '__builtin_types_compatible_p' as identifier
 reserved.c:80:12: error: Trying to use reserved word '__builtin_va_list' as identifier
- * check-error-end:
+ * check-error-end
  */
--- /dev/null	Mon Nov 18 13:20:54 2019
+++ new/usr/src/tools/smatch/src/validation/restrict.c	Mon Nov 18 13:20:54 2019
@@ -0,0 +1,93 @@
+void f00(void *restrict  dst);
+void f01(void *restrict *dst);
+void f02(void *restrict *dst);
+void f03(void *restrict *dst);
+
+void *restrict rp;
+void * up;
+
+void f00(void *dst)	  { }	/* check-should-pass */
+void f01(typeof(&rp) dst) { }	/* check-should-pass */
+void f02(void **dst)	  { }	/* check-should-fail */
+void f03(typeof(&up) dst) { }	/* check-should-fail */
+
+void foo(void)
+{
+	rp = up;		/* check-should-pass */
+	up = rp;		/* check-should-pass */
+}
+
+void ref(void)
+{
+	void *const qp;
+	void * up;
+	extern void *const *pqp;
+	extern void **pup;
+
+	pqp = &qp;		/* check-should-pass */
+	pqp = &up;		/* check-should-pass */
+	pqp = pup;
+
+	pup = &up;		/* check-should-pass */
+
+	pup = &qp;		/* check-should-fail */
+	pup = pqp;		/* check-should-fail */
+}
+
+void bar(void)
+{
+	extern void *restrict *prp;
+	extern void **pup;
+
+	prp = &rp;		/* check-should-pass */
+	prp = &up;		/* check-should-pass */
+	prp = pup;
+
+	pup = &up;		/* check-should-pass */
+
+	pup = &rp;		/* check-should-fail */
+	pup = prp;		/* check-should-fail */
+}
+
+void baz(void)
+{
+	extern typeof(&rp) prp;
+	extern typeof(&up) pup;
+
+	prp = &rp;		/* check-should-pass */
+	prp = &up;		/* check-should-pass */
+	prp = pup;
+
+	pup = &up;		/* check-should-pass */
+
+	pup = &rp;		/* check-should-fail */
+	pup = prp;		/* check-should-fail */
+}
+
+/*
+ * check-name: restrict qualifier
+ * check-command: sparse -Wno-decl $file;
+ *
+ * check-error-start
+restrict.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at restrict.c:3) - incompatible argument 1 (different modifiers)
+restrict.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at restrict.c:4) - incompatible argument 1 (different modifiers)
+restrict.c:33:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:33:13:    expected void **extern [assigned] pup
+restrict.c:33:13:    got void *const *
+restrict.c:34:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:34:13:    expected void **extern [assigned] pup
+restrict.c:34:13:    got void *const *extern [assigned] pqp
+restrict.c:48:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:48:13:    expected void **extern [assigned] pup
+restrict.c:48:13:    got void *restrict *
+restrict.c:49:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:49:13:    expected void **extern [assigned] pup
+restrict.c:49:13:    got void *restrict *extern [assigned] prp
+restrict.c:63:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:63:13:    expected void **extern [assigned] pup
+restrict.c:63:13:    got void *restrict *
+restrict.c:64:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:64:13:    expected void **extern [assigned] pup
+restrict.c:64:13:    got void *restrict *extern [assigned] prp
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:54 2019
+++ new/usr/src/tools/smatch/src/validation/self-quote-args.c	Mon Nov 18 13:20:54 2019
@@ -0,0 +1,7 @@
+/*
+ * check-name: self-quote-args
+ * check-description: This is testing that the test-suite
+ *	respect the quoting of the command's arguments.
+ * check-command: sparse '-foption with-spaces' empty-file
+ * check-output-ignore
+ */
--- /dev/null	Mon Nov 18 13:20:54 2019
+++ new/usr/src/tools/smatch/src/validation/shift-negative.c	Mon Nov 18 13:20:54 2019
@@ -0,0 +1,17 @@
+unsigned int fn1(unsigned int a) { return a >> -1; }
+unsigned int fn2(unsigned int a) { return a >> ~0; }
+
+unsigned int fo1(unsigned int a) { return a >> ((a & 0) | -1); }
+unsigned int fo2(unsigned int a) { return a >> ((a & 0) ^ ~0); }
+
+/*
+ * check-name: shift-negative
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+shift-negative.c:1:45: warning: shift count is negative (-1)
+shift-negative.c:2:45: warning: shift count is negative (-1)
+shift-negative.c:4:59: warning: shift count is negative (-1)
+shift-negative.c:5:59: warning: shift count is negative (-1)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:54 2019
+++ new/usr/src/tools/smatch/src/validation/shift-undef-long.c	Mon Nov 18 13:20:54 2019
@@ -0,0 +1,21 @@
+static unsigned very_big_shift(unsigned int a)
+{
+	unsigned r = 0;
+	r |= a << (0ULL ^ ~0U);
+	r |= a << (((  signed long long) ~0U) + 1);
+	r |= a << (((unsigned long long) ~0U) + 1);
+	r |= a << (~((unsigned long long) ~0U));
+	return r;
+}
+
+/*
+ * check-name: shift-undef-long
+ * check-command: sparse -m64 $file
+ *
+ * check-error-start
+shift-undef-long.c:4:16: warning: shift too big (4294967295) for type unsigned int
+shift-undef-long.c:5:16: warning: shift too big (4294967296) for type unsigned int
+shift-undef-long.c:6:16: warning: shift too big (4294967296) for type unsigned int
+shift-undef-long.c:7:16: warning: shift count is negative (-4294967296)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:55 2019
+++ new/usr/src/tools/smatch/src/validation/shift-undef.c	Mon Nov 18 13:20:55 2019
@@ -0,0 +1,164 @@
+int simple(int s, unsigned int u, int p)
+{
+	s = s >> 100;
+	u = u >> 101;
+	u = u << 102;
+	s = s >>  -1;
+	u = u >>  -2;
+	u = u <<  -3;
+	if (0) return s >> 103;
+	if (0) return u >> 104;
+	if (0) return u << 105;
+	if (0) return s >>  -4;
+	if (0) return u >>  -5;
+	if (0) return u <<  -6;
+	if (p && 0) return s >> 106;
+	if (p && 0) return u >> 107;
+	if (p && 0) return u << 108;
+	if (p && 0) return s >>  -7;
+	if (p && 0) return u >>  -8;
+	if (p && 0) return u <<  -9;
+	s = s >> ((p & 0) + 109); u ^= p; // reloaded because now == 0
+	u = u >> ((p & 0) + 110); u ^= p; // reloaded because now == 0
+	u = u << ((p & 0) + 111); u ^= p; // reloaded because now == 0
+	s = s >> ((p & 0) + -10);
+	u = u >> ((p & 0) + -11); u ^= p; // reloaded because now == 0
+	u = u << ((p & 0) + -12); u ^= p; // reloaded because now == 0
+	return s + u;
+}
+
+int compound(int s, unsigned int u, int p)
+{
+	s >>= 100;
+	u >>= 101;
+	u <<= 102;
+	s >>=  -1;
+	u >>=  -2;
+	u <<=  -3;
+	if (0) return s >>= 103;
+	if (0) return u >>= 104;
+	if (0) return u <<= 105;
+	if (0) return s >>=  -4;
+	if (0) return u >>=  -5;
+	if (0) return u <<=  -6;
+	if (p && 0) return s >>= 106;
+	if (p && 0) return u >>= 107;
+	if (p && 0) return u <<= 108;
+	if (p && 0) return s >>=  -7;
+	if (p && 0) return u >>=  -8;
+	if (p && 0) return u <<=  -9;
+	s >>= ((p & 0) + 109); u ^= p; // reloaded because now == 0
+	u >>= ((p & 0) + 110); u ^= p; // reloaded because now == 0
+	u <<= ((p & 0) + 111); u ^= p; // reloaded because now == 0
+	s >>= ((p & 0) + -10);
+	u >>= ((p & 0) + -11); u ^= p; // reloaded because now == 0
+	u <<= ((p & 0) + -12); u ^= p; // reloaded because now == 0
+	return s + u;
+}
+
+int ok(int s, unsigned int u, int p)
+{
+	// GCC doesn't warn on these
+	if (0 && (s >> 100)) return 0;
+	if (0 && (u >> 101)) return 0;
+	if (0 && (u << 102)) return 0;
+	if (0 && (s >>  -1)) return 0;
+	if (0 && (u >>  -2)) return 0;
+	if (0 && (u <<  -3)) return 0;
+	if (0 && (s >>= 103)) return 0;
+	if (0 && (u >>= 104)) return 0;
+	if (0 && (u <<= 105)) return 0;
+	if (0 && (s >>=  -4)) return 0;
+	if (0 && (u >>=  -5)) return 0;
+	if (0 && (u <<=  -6)) return 0;
+	return 1;
+}
+
+struct bf {
+	unsigned int u:8;
+	         int s:8;
+};
+
+int bf(struct bf *p)
+{
+	unsigned int r = 0;
+	r += p->s << 8;
+	r += p->s >> 8;
+	r += p->u >> 8;
+	return r;
+}
+
+/*
+ * The following is used in the kernel at several places
+ * It shouldn't emit any warnings.
+ */
+typedef unsigned long long u64;
+typedef unsigned       int u32;
+
+extern void hw_w32x2(u32 hi, u32 lo);
+
+inline void hw_w64(u64 val)
+{
+	hw_w32x2(val >> 32, (u32) val);
+}
+
+void hw_write(u32 val)
+{
+	hw_w64(val);
+}
+
+/*
+ * check-name: shift too big or negative
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+shift-undef.c:3:15: warning: shift too big (100) for type int
+shift-undef.c:4:15: warning: shift too big (101) for type unsigned int
+shift-undef.c:5:15: warning: shift too big (102) for type unsigned int
+shift-undef.c:6:15: warning: shift count is negative (-1)
+shift-undef.c:7:15: warning: shift count is negative (-2)
+shift-undef.c:8:15: warning: shift count is negative (-3)
+shift-undef.c:9:25: warning: shift too big (103) for type int
+shift-undef.c:10:25: warning: shift too big (104) for type unsigned int
+shift-undef.c:11:25: warning: shift too big (105) for type unsigned int
+shift-undef.c:12:25: warning: shift count is negative (-4)
+shift-undef.c:13:25: warning: shift count is negative (-5)
+shift-undef.c:14:25: warning: shift count is negative (-6)
+shift-undef.c:15:30: warning: shift too big (106) for type int
+shift-undef.c:16:30: warning: shift too big (107) for type unsigned int
+shift-undef.c:17:30: warning: shift too big (108) for type unsigned int
+shift-undef.c:18:30: warning: shift count is negative (-7)
+shift-undef.c:19:30: warning: shift count is negative (-8)
+shift-undef.c:20:30: warning: shift count is negative (-9)
+shift-undef.c:21:29: warning: shift too big (109) for type int
+shift-undef.c:22:29: warning: shift too big (110) for type unsigned int
+shift-undef.c:23:29: warning: shift too big (111) for type unsigned int
+shift-undef.c:24:29: warning: shift count is negative (-10)
+shift-undef.c:25:29: warning: shift count is negative (-11)
+shift-undef.c:26:29: warning: shift count is negative (-12)
+shift-undef.c:32:11: warning: shift too big (100) for type int
+shift-undef.c:33:11: warning: shift too big (101) for type unsigned int
+shift-undef.c:34:11: warning: shift too big (102) for type unsigned int
+shift-undef.c:35:11: warning: shift count is negative (-1)
+shift-undef.c:36:11: warning: shift count is negative (-2)
+shift-undef.c:37:11: warning: shift count is negative (-3)
+shift-undef.c:38:25: warning: shift too big (103) for type int
+shift-undef.c:39:25: warning: shift too big (104) for type unsigned int
+shift-undef.c:40:25: warning: shift too big (105) for type unsigned int
+shift-undef.c:41:25: warning: shift count is negative (-4)
+shift-undef.c:42:25: warning: shift count is negative (-5)
+shift-undef.c:43:25: warning: shift count is negative (-6)
+shift-undef.c:44:30: warning: shift too big (106) for type int
+shift-undef.c:45:30: warning: shift too big (107) for type unsigned int
+shift-undef.c:46:30: warning: shift too big (108) for type unsigned int
+shift-undef.c:47:30: warning: shift count is negative (-7)
+shift-undef.c:48:30: warning: shift count is negative (-8)
+shift-undef.c:49:30: warning: shift count is negative (-9)
+shift-undef.c:50:26: warning: shift too big (109) for type int
+shift-undef.c:51:26: warning: shift too big (110) for type int
+shift-undef.c:52:26: warning: shift too big (111) for type int
+shift-undef.c:53:26: warning: shift count is negative (-10)
+shift-undef.c:54:26: warning: shift count is negative (-11)
+shift-undef.c:55:26: warning: shift count is negative (-12)
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/sizeof-bool.c	Mon Nov 18 13:20:55 2019
+++ new/usr/src/tools/smatch/src/validation/sizeof-bool.c	Mon Nov 18 13:20:55 2019
@@ -8,6 +8,6 @@
  * number of bytes
  * check-command: sparse -Wsizeof-bool $file
  * check-error-start
-sizeof-bool.c:3:16: warning: expression using sizeof bool
+sizeof-bool.c:3:16: warning: expression using sizeof _Bool
  * check-error-end
  */
--- /dev/null	Mon Nov 18 13:20:55 2019
+++ new/usr/src/tools/smatch/src/validation/sizeof-builtin.c	Mon Nov 18 13:20:55 2019
@@ -0,0 +1,15 @@
+int test(void);
+int test(void)
+{
+	return sizeof &__builtin_trap;
+}
+
+/*
+ * check-name: sizeof-builtin
+ * check-command: sparse -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-error-start
+sizeof-function.c:4:16: error: expression using addressof on a builtin function
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:55 2019
+++ new/usr/src/tools/smatch/src/validation/sizeof-function.c	Mon Nov 18 13:20:55 2019
@@ -0,0 +1,49 @@
+extern int fun(void);
+extern int (*ptr)(void);
+
+static inline int inl(int *a)
+{
+	return *a + 1;
+}
+
+
+int test(void);
+int test(void)
+{
+	unsigned int s = 0;
+
+	// OK
+	s += sizeof &fun;
+	s += sizeof  ptr;
+	s += sizeof &ptr;
+	s += sizeof &inl;
+
+	// KO
+	s += sizeof  fun;
+	s += sizeof *fun;
+
+	s += sizeof *ptr;
+
+	s += sizeof  inl;
+	s += sizeof *inl;
+
+	s += sizeof  __builtin_trap;
+	s += sizeof *__builtin_trap;
+
+	return s;
+}
+
+/*
+ * check-name: sizeof-function
+ * check-command: sparse -Wpointer-arith -Wno-decl $file
+ *
+ * check-error-start
+sizeof-function.c:22:14: warning: expression using sizeof on a function
+sizeof-function.c:23:14: warning: expression using sizeof on a function
+sizeof-function.c:25:14: warning: expression using sizeof on a function
+sizeof-function.c:27:14: warning: expression using sizeof on a function
+sizeof-function.c:28:14: warning: expression using sizeof on a function
+sizeof-function.c:30:14: warning: expression using sizeof on a function
+sizeof-function.c:31:14: warning: expression using sizeof on a function
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:55 2019
+++ new/usr/src/tools/smatch/src/validation/sizeof-incomplete-type.c	Mon Nov 18 13:20:55 2019
@@ -0,0 +1,27 @@
+struct s {
+	char a;
+	char b[sizeof(struct s)];
+	char c;
+	char d[sizeof(struct s)];
+	int  j:sizeof(struct s);
+};
+
+static int array[] = {
+	[0]		= 0,
+	[sizeof(array)] = 1,
+	[2]		= 0,
+	[sizeof(array)] = 2,
+};
+
+/*
+ * check-name: sizeof incomplete type
+ *
+ * check-known-to-fail
+ * check-error-start
+sizeof-incomplete-type.c:3:16: error: invalid application of 'sizeof' to incomplete type 'struct s'
+sizeof-incomplete-type.c:5:16: error: invalid application of 'sizeof' to incomplete type 'struct s'
+sizeof-incomplete-type.c:6:16: error: invalid application of 'sizeof' to incomplete type 'struct s'
+sizeof-incomplete-type.c:11:17: error: invalid application of 'sizeof' to incomplete type 'int[]'
+sizeof-incomplete-type.c:13:17: error: invalid application of 'sizeof' to incomplete type 'int[]'
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:55 2019
+++ new/usr/src/tools/smatch/src/validation/sm_compare18.c	Mon Nov 18 13:20:56 2019
@@ -0,0 +1,24 @@
+#include "check_debug.h"
+
+int a, b;
+static int options_write(void)
+{
+	if (a == b)
+		return;
+
+	if (a < 10)
+		return;
+	if (b > 10)
+		return;
+	__smatch_compare(a, b);
+}
+
+
+/*
+ * check-name: smatch compare #18
+ * check-command: smatch -I.. sm_compare18.c
+ *
+ * check-output-start
+sm_compare18.c:13 options_write() a > b
+ * check-output-end
+ */
--- /dev/null	Mon Nov 18 13:20:56 2019
+++ new/usr/src/tools/smatch/src/validation/storage-struct-member.c	Mon Nov 18 13:20:56 2019
@@ -0,0 +1,20 @@
+int foo(a)
+	register int a;
+{
+	return a;
+}
+
+struct s {
+	register int a;
+};
+
+/*
+ * check-name: storage in struct member
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-known-to-fail
+ * check-error-start
+storage-struct-member.c:2:9: warning: non-ANSI definition of function 'foo'
+storage-struct-member.c:8:9: error: storage specifier in structure definition'
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/struct-as.c	Mon Nov 18 13:20:56 2019
+++ new/usr/src/tools/smatch/src/validation/struct-as.c	Mon Nov 18 13:20:56 2019
@@ -12,7 +12,7 @@
 
 static int broken(struct hello __user *sp)
 {
-	test(&sp->a);
+	return test(&sp->a);
 }
 /*
  * check-name: Address space of a struct member
--- /dev/null	Mon Nov 18 13:20:56 2019
+++ new/usr/src/tools/smatch/src/validation/switch-long.c	Mon Nov 18 13:20:56 2019
@@ -0,0 +1,47 @@
+void def(void);
+void r0(void);
+void r1(void);
+
+void sw_long(long long a)
+{
+	switch (a) {
+	case 0: return r0();
+	case 1LL << 00: return r1();
+	case 1LL << 32: return r1();
+	}
+
+	return def();
+}
+
+/*
+ * check-name: switch-long
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+sw_long:
+.L0:
+	<entry-point>
+	switch.64   %arg1, 0 -> .L2, 1 -> .L3, 4294967296 -> .L4, default -> .L1
+
+.L2:
+	call        r0
+	br          .L5
+
+.L3:
+	call        r1
+	br          .L5
+
+.L4:
+	call        r1
+	br          .L5
+
+.L1:
+	call        def
+	br          .L5
+
+.L5:
+	ret
+
+
+ * check-output-end
+ */
--- old/usr/src/tools/smatch/src/validation/test-be.c	Mon Nov 18 13:20:56 2019
+++ /dev/null	Mon Nov 18 13:20:56 2019
@@ -1,46 +0,0 @@
-int printf(char *c, ...);
-void exit(int c);
-
-#undef PRINT_OUTPUTS
-
-static void test_func_args(int x, int y)
-{
-	if (x == y)
-		exit(1);
-}
-
-static int binop_s32(int x, int y)
-{
-	int a;
-
-	a = a + x;
-	a = a / y;
-	a = a * x;
-	a = a - y;
-
-	return a;
-}
-
-static void test_binops(void)
-{
-	int tmp_s32 = binop_s32(987123, 234);
-
-#ifdef PRINT_OUTPUTS
-	printf("binop_s32(987123, 234) == %d\n", tmp_s32);
-#else
-	if (tmp_s32 != -1470599007)
-		exit(2);
-#endif
-}
-
-int main (int argc, char *argv[])
-{
-	test_func_args(1, 2);
-	test_binops();
-
-	return 0;
-}
-
-/*
- * check-name: binary operations
- */
--- old/usr/src/tools/smatch/src/validation/test-suite	Mon Nov 18 13:20:56 2019
+++ new/usr/src/tools/smatch/src/validation/test-suite	Mon Nov 18 13:20:56 2019
@@ -6,11 +6,12 @@
 
 default_path=".."
 default_cmd="sparse \$file"
-tests_list=`find . -name '*.c' | sed -e 's#^\./\(.*\)#\1#' | sort`
+default_args="$SPARSE_TEST_ARGS"
+tests_list=""
 prog_name=`basename $0`
 
 if [ ! -x "$default_path/sparse-llvm" ]; then
-	disabled_cmds="sparsec sparsei sparse-llvm"
+	disabled_cmds="sparsec sparsei sparse-llvm sparse-llvm-dis"
 fi
 
 # flags:
@@ -31,9 +32,38 @@
 
 # defaults to not verbose
 [ -z "$V" ] && V=0
-[ $V -eq 0 ] && quiet=1 || quiet=0
+vquiet=""
+quiet=0
+abort=0
 
+
 ##
+# verbose(string) - prints string if we are in verbose mode
+verbose()
+{
+	[ "$V" -eq "1" ] && echo "        $1"
+	return 0
+}
+
+##
+# warning(string) - prints a warning
+warning()
+{
+	[ "$quiet" -ne 1 ] && echo "warning: $1"
+	return 0
+}
+
+##
+# error(string[, die]) - prints an error and exits with value die if given
+error()
+{
+	[ "$quiet" -ne 1 ] && echo "error: $1"
+	[ -n "$2" ] && exit $2
+	return 0
+}
+
+
+##
 # get_tag_value(file) - get the 'check-<...>' tags & values
 get_tag_value()
 {
@@ -47,6 +77,10 @@
 	check_output_contains=0
 	check_output_excludes=0
 	check_output_pattern=0
+	check_arch_ignore=""
+	check_arch_only=""
+	check_assert=""
+	check_cpp_if=""
 
 	lines=$(grep 'check-[a-z-]*' $1 | \
 		sed -e 's/^.*\(check-[a-z-]*:*\) *\(.*\)$/\1 \2/')
@@ -65,7 +99,25 @@
 		check-output-ignore)	check_output_ignore=1 ;;
 		check-output-contains:)	check_output_contains=1 ;;
 		check-output-excludes:)	check_output_excludes=1 ;;
-		check-output-pattern-)	check_output_pattern=1 ;;
+		check-output-pattern)	check_output_pattern=1 ;;
+		check-arch-ignore:)	arch=$(uname -m)
+					check_arch_ignore="$val" ;;
+		check-arch-only:)	arch=$(uname -m)
+					check_arch_only="$val" ;;
+		check-assert:)		check_assert="$val" ;;
+		check-cpp-if:)		check_cpp_if="$val" ;;
+
+		check-description:)	;;	# ignore
+		check-note:)		;;	# ignore
+		check-warning:)		;;	# ignore
+		check-error-start)	;;	# ignore
+		check-error-end)	;;	# ignore
+		check-output-start)	;;	# ignore
+		check-output-end)	;;	# ignore
+		check-should-pass)	;;	# ignore, unused annotation
+		check-should-fail)	;;	# ignore, unused annotation
+		check-should-warn)	;;	# ignore, unused annotation
+		check-*)		error "$1: unknown tag '$tag'" 1 ;;
 		esac
 	done << EOT
 	$lines
@@ -80,11 +132,13 @@
 	patt="$2"
 	ofile="$3"
 	cmp="$4"
+	msg="$5"
 	grep "$patt:" "$ifile" | \
 	sed -e "s/^.*$patt: *\(.*\)$/\1/" | \
 	while read val; do
 		grep -s -q "$val" "$ofile"
 		if [ "$?" $cmp 0 ]; then
+			error "	Pattern '$val' unexpectedly $msg"
 			return 1
 		fi
 	done
@@ -99,7 +153,7 @@
 # returns 0 if all present, 1 otherwise
 has_each_patterns()
 {
-	has_patterns "$1" "$2" "$3" -ne
+	has_patterns "$1" "$2" "$4" -ne "$3"
 }
 
 ##
@@ -109,25 +163,42 @@
 # returns 1 if any present, 0 otherwise
 has_none_patterns()
 {
-	has_patterns "$1" "$2" "$3" -eq
+	has_patterns "$1" "$2" "$4" -eq "$3"
 }
 
 ##
-# nbr_patterns(ifile tag ofile) - does ofile contains the
+# minmax_patterns(ifile tag ofile) - does ofile contains the
 #                        the patterns given by ifile's tags
 #                        the right number of time?
-nbr_patterns()
+minmax_patterns()
 {
 	ifile="$1"
 	patt="$2"
 	ofile="$3"
-	grep "$patt-[0-9][0-9]*-times:" "$ifile" | \
-	sed -e "s/^.*$patt-\([0-9][0-9]*\)-times: *\(.*\)/\1 \2/" | \
-	while read nbr pat; do
+	grep "$patt([0-9-]*\(, *\)*[0-9-]*):" "$ifile" | \
+	sed -e "s/^.*$patt(\([0-9]*\)): *\(.*\)/\1 eq \2/" \
+	    -e "s/^.*$patt(\([0-9-]*\), *\([0-9-]*\)): *\(.*\)/\1 \2 \3/" | \
+	while read min max pat; do
 		n=$(grep -s "$pat" "$ofile" | wc -l)
-		if [ "$n" -ne "$nbr" ]; then
+		if [ "$max" = "eq" ]; then
+		    if [ "$n" -ne "$min" ]; then
+			error "	Pattern '$pat' expected $min times but got $n times"
 			return 1
+		    fi
+		    continue
 		fi
+		if [ "$min" != '-' ]; then
+		    if [ "$n" -lt "$min" ]; then
+			error "	Pattern '$pat' expected min $min times but got $n times"
+			return 1
+		    fi
+		fi
+		if [ "$max" != '-' ]; then
+		    if [ "$n" -gt "$max" ]; then
+			error "	Pattern '$pat' expected max $max times but got $n times"
+			return 1
+		    fi
+		fi
 	done
 
 	return $?
@@ -134,35 +205,50 @@
 }
 
 ##
-# verbose(string) - prints string if we are in verbose mode
-verbose()
+# arg_file(filename) - checks if filename exists
+arg_file()
 {
-	[ "$V" -eq "1" ] && echo "        $1"
+	[ -z "$1" ] && {
+		do_usage
+		exit 1
+	}
+	[ -e "$1" ] || {
+		error "Can't open file $1"
+		exit 1
+	}
 	return 0
 }
 
-##
-# error(string[, die]) - prints an error and exits with value die if given
-error()
-{
-	[ "$quiet" -ne 1 ] && echo "error: $1"
-	[ -n "$2" ] && exit $2
-	return 0
-}
 
+##
 do_usage()
 {
 echo "$prog_name - a tiny automatic testing script"
-echo "Usage: $prog_name [command] [command arguments]"
+echo "Usage: $prog_name [option(s)] [command] [arguments]"
 echo
+echo "options:"
+echo "    -a|--abort                 Abort the tests as soon as one fails."
+echo "    -q|--quiet                 Be extra quiet while running the tests."
+echo "    --args='...'               Add these options to the test command."
+echo
 echo "commands:"
-echo "    none                       runs the whole test suite"
-echo "    single file                runs the test in 'file'"
-echo "    format file [name [cmd]]   helps writing a new test case using cmd"
+echo "    [file ...]                 Runs the test suite on the given file(s)."
+echo "                               If a directory is given, run only those files."
+echo "                               If no file is given, run the whole testsuite."
+echo "    single file                Run the test in 'file'."
+echo "    format file [name [cmd]]   Help writing a new test case using cmd."
 echo
-echo "    help                       prints usage"
+echo "    [command] help             Print usage."
 }
 
+disable()
+{
+	disabled_tests=$(($disabled_tests + 1))
+	if [ -z "$vquiet" ]; then
+		echo "  SKIP    $1 ($2)"
+	fi
+}
+
 ##
 # do_test(file) - tries to validate a test case
 #
@@ -177,6 +263,7 @@
 {
 	test_failed=0
 	file="$1"
+	quiet=0
 
 	get_tag_value $file
 
@@ -183,7 +270,7 @@
 	# can this test be handled by test-suite ?
 	# (it has to have a check-name key in it)
 	if [ "$check_name" = "" ]; then
-		echo "warning: test '$file' unhandled"
+		warning "$file: test unhandled"
 		unhandled_tests=$(($unhandled_tests + 1))
 		return 2
 	fi
@@ -199,37 +286,73 @@
 	base_cmd=$1
 	for i in $disabled_cmds; do
 		if [ "$i" = "$base_cmd" ] ; then
-			disabled_tests=$(($disabled_tests + 1))
-			echo "     DISABLE $test_name ($file)"
+			disable "$test_name" "$file"
 			return 3
 		fi
 	done
+	if [ "$check_arch_ignore" != "" ]; then
+		if echo $arch | egrep -q -w "$check_arch_ignore"; then
+			disable "$test_name" "$file"
+			return 3
+		fi
+	fi
+	if [ "$check_arch_only" != "" ]; then
+		if ! (echo $arch | egrep -q -w "$check_arch_only"); then
+			disable "$test_name" "$file"
+			return 3
+		fi
+	fi
+	if [ "$check_assert" != "" ]; then
+		res=$(../sparse - 2>&1 >/dev/null <<- EOF
+			_Static_assert($check_assert, "$check_assert");
+			EOF
+		)
+		if [ "$res" != "" ]; then
+			disable "$test_name" "$file"
+			return 3
+		fi
+	fi
+	if [ "$check_cpp_if" != "" ]; then
+		res=$(../sparse -E - 2>/dev/null <<- EOF
+			#if !($check_cpp_if)
+			fail
+			#endif
+			EOF
+		)
+		if [ "$res" != "" ]; then
+			disable "$test_name" "$file"
+			return 3
+		fi
+	fi
 
-	cmd=`eval echo $default_path/$check_command`
+	if [ -z "$vquiet" ]; then
+		echo "  TEST    $test_name ($file)"
+	fi
 
-	echo "     TEST    $test_name ($file)"
+	verbose "Using command       : $(echo "$@")"
 
-	verbose "Using command       : $cmd"
-
 	# grab the expected exit value
 	expected_exit_value=$check_exit_value
 	verbose "Expecting exit value: $expected_exit_value"
 
 	# do we want a timeout?
+	pre_cmd=""
 	if [ $check_timeout -ne 0 ]; then
-		cmd="timeout -k 1s $check_timeout $cmd"
+		pre_cmd="timeout -k 1s $check_timeout"
 	fi
 
+	shift
+	# launch the test command and
 	# grab the actual output & exit value
-	$cmd 1> $file.output.got 2> $file.error.got
+	eval $pre_cmd $default_path/$base_cmd $default_args "$@" \
+		1> $file.output.got 2> $file.error.got
 	actual_exit_value=$?
 
 	must_fail=$check_known_to_fail
-	quiet=0
 	[ $must_fail -eq 1 ] && [ $V -eq 0 ] && quiet=1
 	known_ko_tests=$(($known_ko_tests + $must_fail))
 
-	for stream in output error; do
+	for stream in error output; do
 		eval ignore=\$check_${stream}_ignore
 		[ $ignore -eq 1 ] && continue
 
@@ -254,39 +377,47 @@
 
 	# verify the 'check-output-contains/excludes' tags
 	if [ $check_output_contains -eq 1 ]; then
-		has_each_patterns "$file" 'check-output-contains' $file.output.got
+		has_each_patterns "$file" 'check-output-contains' absent $file.output.got
 		if [ "$?" -ne "0" ]; then
-			error "Actual output doesn't contain some of the expected patterns."
 			test_failed=1
 		fi
 	fi
 	if [ $check_output_excludes -eq 1 ]; then
-		has_none_patterns "$file" 'check-output-excludes' $file.output.got
+		has_none_patterns "$file" 'check-output-excludes' present $file.output.got
 		if [ "$?" -ne "0" ]; then
-			error "Actual output contains some patterns which are not expected."
 			test_failed=1
 		fi
 	fi
 	if [ $check_output_pattern -eq 1 ]; then
-		# verify the 'check-output-pattern-X-times' tags
-		nbr_patterns "$file" 'check-output-pattern' $file.output.got
+		# verify the 'check-output-pattern(...)' tags
+		minmax_patterns "$file" 'check-output-pattern' $file.output.got
 		if [ "$?" -ne "0" ]; then
-			error "Actual output doesn't contain the pattern the expected number."
 			test_failed=1
 		fi
 	fi
 
-	[ "$test_failed" -eq "$must_fail" ] || failed=1
-
 	if [ "$must_fail" -eq "1" ]; then
 		if [ "$test_failed" -eq "1" ]; then
-			echo "info: test '$file' is known to fail"
+			[ -z "$vquiet" ] && \
+			echo "info: XFAIL: test '$file' is known to fail"
 		else
-			echo "error: test '$file' is known to fail but succeed!"
-			test_failed=1
+			echo "error: XPASS: test '$file' is known to fail but succeed!"
 		fi
+	else
+		if [ "$test_failed" -eq "1" ]; then
+			echo "error: FAIL: test '$file' failed"
+		else
+			[ "$V" -ne "0" ] && \
+			echo "info: PASS: test '$file' passed"
+		fi
 	fi
 
+	if [ "$test_failed" -ne "$must_fail" ]; then
+		[ $abort -eq 1 ] && exit 1
+		test_failed=1
+		failed=1
+	fi
+
 	if [ "$test_failed" -eq "1" ]; then
 		ko_tests=$(($ko_tests + 1))
 	else
@@ -302,37 +433,80 @@
 		do_test "$i"
 	done
 
+	OK=OK
+	[ $failed -eq 0 ] || OK=KO
+
 	# prints some numbers
 	tests_nr=$(($ok_tests + $ko_tests))
-	echo -n "Out of $tests_nr tests, $ok_tests passed, $ko_tests failed"
-	echo " ($known_ko_tests of them are known to fail)"
+	echo "$OK: out of $tests_nr tests, $ok_tests passed, $ko_tests failed"
+	if [ "$known_ko_tests" -ne 0 ]; then
+		echo "	$known_ko_tests of them are known to fail"
+	fi
 	if [ "$unhandled_tests" -ne "0" ]; then
-		echo "$unhandled_tests tests could not be handled by $prog_name"
+		echo "	$unhandled_tests tests could not be handled by $prog_name"
 	fi
 	if [ "$disabled_tests" -ne "0" ]; then
-		echo "$disabled_tests tests were disabled"
+		echo "	$disabled_tests tests were disabled"
 	fi
 }
 
 ##
-# do_format(file[, name[, cmd]]) - helps a test writer to format test-suite tags
+do_format_help() {
+echo "Usage: $prog_name [option(s)] [--]format file [name [cmd]]"
+echo
+echo "options:"
+echo "    -a                         append the created test to the input file"
+echo "    -f                         write a test known to fail"
+echo "    -l                         write a test for linearized code"
+echo
+echo "argument(s):"
+echo "    file                       file containing the test case(s)"
+echo "    name                       name for the test case (defaults to file)"
+echo "    cmd                        command to be used (defaults to 'sparse \$file')"
+}
+
+##
+# do_format([options,] file[, name[, cmd]]) - helps a test writer to format test-suite tags
 do_format()
 {
-	if [ -z "$2" ]; then
-		fname="$1"
-		fcmd=$default_cmd
-	elif [ -z "$3" ]; then
-		fname="$2"
-		fcmd=$default_cmd
-	else
-		fname="$2"
-		fcmd="$3"
-	fi
+	def_cmd="$default_cmd"
+	append=0
+	linear=0
+	fail=0
+
+	while [ $# -gt 1 ] ; do
+		case "$1" in
+		-a)
+			append=1 ;;
+		-f)
+			fail=1 ;;
+		-l)
+			def_cmd='test-linearize -Wno-decl $file'
+			linear=1 ;;
+		help|-*)
+			do_format_help
+			return 0
+			;;
+		*)	break ;;
+		esac
+		shift
+		continue
+	done
+
+	arg_file "$1" || return 1
+
 	file="$1"
+	fname="$2"
+	[ -z "$fname" ] && fname="$(basename "$1" .c)"
+	fcmd="$3"
+	[ -z "$fcmd" ] && fcmd="$def_cmd"
+
 	cmd=`eval echo $default_path/$fcmd`
 	$cmd 1> $file.output.got 2> $file.error.got
 	fexit_value=$?
+	[ $append != 0 ] && exec >> $file
 	cat <<_EOF
+
 /*
  * check-name: $fname
 _EOF
@@ -342,6 +516,15 @@
 	if [ "$fexit_value" -ne "0" ]; then
 		echo " * check-exit-value: $fexit_value"
 	fi
+	if [ $fail != 0 ]; then
+		echo " * check-known-to-fail"
+	fi
+	if [ $linear != 0 ]; then
+		echo ' *'
+		echo ' * check-output-ignore'
+		echo ' * check-output-contains: xyz\\\\.'
+		echo ' * check-output-excludes: \\\\.'
+	fi
 	for stream in output error; do
 		if [ -s "$file.$stream.got" ]; then
 			echo " *"
@@ -354,26 +537,23 @@
 	return 0
 }
 
-##
-# arg_file(filename) - checks if filename exists
-arg_file()
-{
-	[ -z "$1" ] && {
-		do_usage
-		exit 1
-	}
-	[ -e "$1" ] || {
-		error "Can't open file $1"
-		exit 1
-	}
-	return 0
-}
+## allow flags from environment
+set -- $SPARSE_TEST_FLAGS "$@"
 
-case "$1" in
-	'')
-		do_test_suite
+## process the flags
+while [ "$#" -gt "0" ]; do
+	case "$1" in
+	-a|--abort)
+		abort=1
 		;;
-	single)
+	-q|--quiet)
+		vquiet=1
+		;;
+	--args=*)
+		default_args="${1#--args=}";
+		;;
+
+	single|--single)
 		arg_file "$2"
 		do_test "$2"
 		case "$?" in
@@ -381,16 +561,36 @@
 			1) echo "$2 failed !";;
 			2) echo "$2 can't be handled by $prog_name";;
 		esac
+		exit $failed
 		;;
-	format)
-		arg_file "$2"
-		do_format "$2" "$3" "$4"
+	format|--format)
+		shift
+		do_format "$@"
+		exit 0
 		;;
-	help | *)
+	help)
 		do_usage
 		exit 1
 		;;
-esac
 
+	*.c|*.cdoc)
+		tests_list="$tests_list $1"
+		;;
+	*)
+		if [ ! -d "$1" ]; then
+			do_usage
+			exit 1
+		fi
+		tests_list="$tests_list $(find "$1" -name '*.c' | sort)"
+		;;
+	esac
+	shift
+done
+
+if [ -z "$tests_list" ]; then
+	tests_list=`find . -name '*.c' | sed -e 's#^\./\(.*\)#\1#' | sort`
+fi
+
+do_test_suite
 exit $failed
 
--- old/usr/src/tools/smatch/src/validation/testsuite-selfcheck1.c	Mon Nov 18 13:20:57 2019
+++ /dev/null	Mon Nov 18 13:20:57 2019
@@ -1,10 +0,0 @@
-good
-
-/*
- * check-name: selfcheck1
- * check-command: sparse -E $file
- * check-output-ignore
- *
- * check-output-contains: good
- * check-output-excludes: evil
- */
--- old/usr/src/tools/smatch/src/validation/testsuite-selfcheck2.c	Mon Nov 18 13:20:57 2019
+++ /dev/null	Mon Nov 18 13:20:57 2019
@@ -1,10 +0,0 @@
-evil
-
-/*
- * check-name: selfcheck2
- * check-command: sparse -E $file
- * check-output-ignore
- * check-known-to-fail
- *
- * check-output-contains: good
- */
--- old/usr/src/tools/smatch/src/validation/testsuite-selfcheck3.c	Mon Nov 18 13:20:57 2019
+++ /dev/null	Mon Nov 18 13:20:57 2019
@@ -1,10 +0,0 @@
-evil
-
-/*
- * check-name: selfcheck3
- * check-command: sparse -E $file
- * check-output-ignore
- * check-known-to-fail
- *
- * check-output-excludes: evil
- */
--- /dev/null	Mon Nov 18 13:20:57 2019
+++ new/usr/src/tools/smatch/src/validation/type-compare.c	Mon Nov 18 13:20:57 2019
@@ -0,0 +1,76 @@
+#define __user		__attribute__((address_space(1)))
+#define __safe		__attribute__((safe))
+#define __nocast	__attribute__((nocast))
+#define __bitwise	__attribute__((bitwise))
+#define __noderef	__attribute__((noderef))
+
+int test(void)
+{
+	if ([int] != [int]) return 1;
+	if (!([int] == [int])) return 1;
+
+	if ([int] == [long]) return 1;
+	if (!([int] != [long])) return 1;
+
+	if ([int] == [unsigned int]) return 1;
+	if (!([int] != [unsigned int])) return 1;
+
+	if ([int] != [int]) return 1;
+	if ([typeof(int)] != [int]) return 1;
+	if ([int] != [typeof(int)]) return 1;
+	if ([typeof(int)] != [typeof(int)]) return 1;
+
+	if ([char] > [short]) return 1;
+	if ([short] < [char]) return 1;
+	if (!([char] <= [short])) return 1;
+	if (!([short] >= [char])) return 1;
+
+	if ([short] > [int]) return 1;
+	if ([int] < [short]) return 1;
+	if (!([short] <= [int])) return 1;
+	if (!([int] >= [short])) return 1;
+
+	if ([int] > [long]) return 1;
+	if ([long] < [int]) return 1;
+	if (!([int] <= [long])) return 1;
+	if (!([long] >= [int])) return 1;
+
+	if ([long] > [long long]) return 1;
+	if ([long long] < [long]) return 1;
+	if (!([long] <= [long long])) return 1;
+	if (!([long long] >= [long])) return 1;
+
+	if ([int *] != [int *]) return 1;
+	if ([int *] == [void *]) return 1;
+
+	// qualifiers are ignored
+	if ([int] != [const int]) return 1;
+	if ([int] != [volatile int]) return 1;
+
+	// but others modifiers are significant
+	if ([int] == [int __nocast]) return 1;
+	if ([int] == [int __bitwise]) return 1;
+
+	//
+	if ([int *] == [const int *]) return 1;
+	if ([int *] == [volatile int *]) return 1;
+	if ([int *] == [int __user *]) return 1;
+	if ([int *] == [int __safe *]) return 1;
+	if ([int *] == [int __nocast *]) return 1;
+	if ([int *] == [int __bitwise *]) return 1;
+	if ([int *] == [int __noderef *]) return 1;
+
+	return 0;
+}
+
+/*
+ * check-name: type-as-first-class comparison
+ * check-description: This test the sparse extension making
+ *	types first class citizens which can be compared
+ *	for equality (or size for <, >, <=, >=).
+ *	See expand.c:compare_types().
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-contains: ret\\..*\\$0
+ */
--- /dev/null	Mon Nov 18 13:20:57 2019
+++ new/usr/src/tools/smatch/src/validation/typedef-redef-c89.c	Mon Nov 18 13:20:57 2019
@@ -0,0 +1,13 @@
+typedef int int_t;
+typedef int int_t;
+
+/*
+ * check-name: typedef-redef-c89
+ * check-command: sparse -std=c89 --pedantic $file
+ * check-known-to-fail
+ *
+ * check-error-start
+typedef-redef-c89.c:2:13: warning: redefinition of typedef 'int_t'
+typedef-redef-c89.c:1:13: info: originally defined here
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:58 2019
+++ new/usr/src/tools/smatch/src/validation/typedef-redef.c	Mon Nov 18 13:20:58 2019
@@ -0,0 +1,13 @@
+typedef int  ok_t;
+typedef int  ok_t;
+
+typedef int  ko_t;
+typedef long ko_t;
+
+/*
+ * check-name: typedef-redef
+ *
+ * check-error-start
+typedef-redef.c:5:14: error: symbol 'ko_t' redeclared with different type (originally declared at typedef-redef.c:4) - different type sizes
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/typedef_shadow.c	Mon Nov 18 13:20:58 2019
+++ new/usr/src/tools/smatch/src/validation/typedef_shadow.c	Mon Nov 18 13:20:58 2019
@@ -5,9 +5,9 @@
 }
 /*
  * check-name: typedef shadowing
- * check-error-start:
+ * check-error-start
 typedef_shadow.c:4:16: warning: 'T' has implicit type
 typedef_shadow.c:4:18: error: Expected ; at end of declaration
 typedef_shadow.c:4:18: error: got a
- * check-error-end:
+ * check-error-end
  */
--- /dev/null	Mon Nov 18 13:20:58 2019
+++ new/usr/src/tools/smatch/src/validation/typediff-arraysize.c	Mon Nov 18 13:20:58 2019
@@ -0,0 +1,12 @@
+extern int ok0[];	int ok0[1];	// OK
+extern int ok1[1];	int ok1[];	// OK but size should be 1
+extern int ko1[1];	int ko1[2];	// KO
+
+/*
+ * check-name: typediff-arraysize
+ * check-known-to-fail
+ *
+ * check-error-start
+typediff-arraysize.c:3:29: error: symbol 'ko1' redeclared with different type (originally declared at typediff-arraysize.c:3) - different array sizes
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:58 2019
+++ new/usr/src/tools/smatch/src/validation/typediff-enum.c	Mon Nov 18 13:20:58 2019
@@ -0,0 +1,34 @@
+enum num { ZERO, ONE, MANY, };
+typedef enum num num;
+
+extern int v;
+num v = 0;
+
+extern num w;
+int w = 0;
+
+int foo(void);
+num foo(void) { return ZERO; }
+
+num bar(void);
+int bar(void) { return ZERO; }
+
+void baz(int a);
+void baz(num a) { }
+
+void qux(num a);
+void qux(int a) { }
+
+/*
+ * check-name: typediff-enum
+ * check-known-to-fail
+ *
+ * check-error-start
+typediff-enum.c:5:5: error: symbol 'v' redeclared with different type (originally declared at typediff-enum.c:4) - different types
+typediff-enum.c:8:5: error: symbol 'w' redeclared with different type (originally declared at typediff-enum.c:7) - different types
+typediff-enum.c:11:5: error: symbol 'foo' redeclared with different type (originally declared at typediff-enum.c:10) - different types
+typediff-enum.c:14:5: error: symbol 'bar' redeclared with different type (originally declared at typediff-enum.c:13) - different types
+typediff-enum.c:17:6: error: symbol 'baz' redeclared with different type (originally declared at typediff-enum.c:16) - incompatible argument 1 (different types)
+typediff-enum.c:20:6: error: symbol 'qux' redeclared with different type (originally declared at typediff-enum.c:19) - incompatible argument 1 (different types)
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:20:58 2019
+++ new/usr/src/tools/smatch/src/validation/typeof-bad.c	Mon Nov 18 13:20:59 2019
@@ -0,0 +1,17 @@
+static typeof(undef) a;
+
+static int foo(void)
+{
+	return a;
+}
+
+/*
+ * check-name: typeof-bad
+ *
+ * check-error-start
+typeof-bad.c:1:15: error: undefined identifier 'undef'
+typeof-bad.c:5:16: warning: incorrect type in return expression (different base types)
+typeof-bad.c:5:16:    expected int
+typeof-bad.c:5:16:    got bad type static [toplevel] a
+ * check-error-end
+ */
--- old/usr/src/tools/smatch/src/validation/typeof-mods.c	Mon Nov 18 13:20:59 2019
+++ new/usr/src/tools/smatch/src/validation/typeof-mods.c	Mon Nov 18 13:20:59 2019
@@ -43,6 +43,34 @@
 	obj = *ptr;
 }
 
+static void test_restrict(void)
+{
+	int *restrict obj, *restrict *ptr;
+	typeof(obj) var = obj;
+	typeof(ptr) ptr2 = ptr;
+	typeof(*ptr) var2 = obj;
+	typeof(*ptr) *ptr3 = ptr;
+	typeof(obj) *ptr4 = ptr;
+	obj = obj;
+	ptr = ptr;
+	ptr = &obj;
+	obj = *ptr;
+}
+
+static void test_atomic(void)
+{
+	int _Atomic obj, *ptr;
+	typeof(obj) var = obj;
+	typeof(ptr) ptr2 = ptr;
+	typeof(*ptr) var2 = obj;
+	typeof(*ptr) *ptr3 = ptr;
+	typeof(obj) *ptr4 = ptr;
+	obj = obj;
+	ptr = ptr;
+	ptr = &obj;
+	obj = *ptr;
+}
+
 static void test_bitwise(void)
 {
 	typedef int __bitwise type_t;
--- /dev/null	Mon Nov 18 13:20:59 2019
+++ new/usr/src/tools/smatch/src/validation/var-undef-partial.c	Mon Nov 18 13:20:59 2019
@@ -0,0 +1,20 @@
+int foo(int a, int b)
+{
+	int var = 0;
+	int r;
+
+	if (a)
+		var = 1;
+	if (b)
+		r = var;
+
+	return r;		// undef if !b
+}
+
+/*
+ * check-name: variable partially undefined
+ * check-description: trigger a bug in symbol/memop simplification
+ * check-description: sparse-llvm is used here as semantic checker of sparse's IR
+ * check-command: sparse-llvm -Wno-decl $file
+ * check-output-ignore
+ */
--- /dev/null	Mon Nov 18 13:20:59 2019
+++ new/usr/src/tools/smatch/src/validation/vla-sizeof-ice.c	Mon Nov 18 13:20:59 2019
@@ -0,0 +1,19 @@
+// credit goes to Martin Uecker for the awesome ICE_P macro
+
+#define ICE_P(x) \
+    (__builtin_types_compatible_p(typeof(0?((void*)((long)(x)*0l)):(int*)1),int*))
+
+#define T(x)		__builtin_choose_expr(ICE_P(x), 1, 0)
+#define TEST(x, r)	_Static_assert(T(x) == r, #x " => " #r)
+
+static void test(int n)
+{
+	char foo[n++];
+
+	TEST(sizeof(foo), 0);
+}
+
+/*
+ * check-name: vla-sizeof-ice
+ * check-command: sparse -Wno-vla $file
+ */
--- /dev/null	Mon Nov 18 13:20:59 2019
+++ new/usr/src/tools/smatch/src/validation/vla-sizeof.c	Mon Nov 18 13:20:59 2019
@@ -0,0 +1,37 @@
+unsigned long vla_sizeof0(int size)
+{
+	int a[size];
+	return sizeof(a);
+}
+
+unsigned long vla_sizeof1(int size)
+{
+	struct s {
+		int a[size];
+	};
+	return sizeof(struct s);
+}
+
+unsigned long vla_sizeof2(int size)
+{
+	struct s {
+		int a[size];
+	} *p;
+	return sizeof(*p);
+}
+
+void* vla_inc(int size, void *base)
+{
+	struct s {
+		int a[size];
+	} *p = base;
+
+	++p;
+	return p;
+}
+
+/*
+ * check-name: vla-sizeof.c
+ *
+ * check-known-to-fail
+ */
--- /dev/null	Mon Nov 18 13:20:59 2019
+++ new/usr/src/tools/smatch/src/validation/vla-sizeof0.c	Mon Nov 18 13:21:00 2019
@@ -0,0 +1,20 @@
+#define N 2
+#define T int
+
+static unsigned int foo(int x)
+{
+	T a[(1,N)];
+
+	return sizeof(a) == (N * sizeof(T));
+}
+
+/*
+ * check-name: vla-sizeof cte,cte
+ * check-command: test-linearize -Wvla $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\.32 *\\$1
+ *
+ * check-error-start
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:21:00 2019
+++ new/usr/src/tools/smatch/src/validation/vla-sizeof1.c	Mon Nov 18 13:21:00 2019
@@ -0,0 +1,21 @@
+#define N 2
+#define T int
+
+static unsigned int foo(int x)
+{
+	T a[(x,N)];
+
+	return sizeof(a) == (N * sizeof(T));
+}
+
+/*
+ * check-name: vla-sizeof var,cte
+ * check-command: test-linearize -Wvla $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\.32 *\\$1
+ *
+ * check-error-start
+vla-sizeof1.c:6:15: warning: Variable length array is used.
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:21:00 2019
+++ new/usr/src/tools/smatch/src/validation/vla-sizeof2.c	Mon Nov 18 13:21:00 2019
@@ -0,0 +1,21 @@
+#define N 2
+#define T int
+
+static unsigned long foo(int x)
+{
+	T a[x];
+
+	return sizeof(a) == (x * sizeof(T));
+}
+
+/*
+ * check-name: vla-sizeof var
+ * check-command: test-linearize -Wvla $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ *
+ * check-error-start
+vla-sizeof2.c:6:13: warning: Variable length array is used.
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:21:00 2019
+++ new/usr/src/tools/smatch/src/validation/vla-sizeof3.c	Mon Nov 18 13:21:00 2019
@@ -0,0 +1,21 @@
+#define N 2UL
+#define T int
+
+static unsigned long foo(int x)
+{
+	T a[x][N];
+
+	return sizeof(a) == (N * x * sizeof(T));
+}
+
+/*
+ * check-name: vla-sizeof var X cte
+ * check-command: test-linearize -Wvla $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ *
+ * check-error-start
+vla-sizeof3.c:6:13: warning: Variable length array is used.
+ * check-error-end
+ */
--- /dev/null	Mon Nov 18 13:21:00 2019
+++ new/usr/src/tools/smatch/src/validation/vla-sizeof4.c	Mon Nov 18 13:21:00 2019
@@ -0,0 +1,22 @@
+#define N 2
+#define T int
+
+static unsigned long foo(int x, int y)
+{
+	T a[x][y];
+
+	return sizeof(a) == (x * (y * sizeof(T)));
+}
+
+/*
+ * check-name: vla-sizeof var X var
+ * check-command: test-linearize -Wvla $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$1
+ *
+ * check-error-start
+vla-sizeof4.c:6:16: warning: Variable length array is used.
+vla-sizeof4.c:6:13: warning: Variable length array is used.
+ * check-error-end
+ */
--- old/usr/src/uts/common/io/mac/mac.c	Mon Nov 18 13:21:00 2019
+++ new/usr/src/uts/common/io/mac/mac.c	Mon Nov 18 13:21:00 2019
@@ -4853,7 +4853,7 @@
 
 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
 	ASSERT(d_group != NULL);
-	ASSERT(s_group->mrg_mh == d_group->mrg_mh);
+	ASSERT(s_group == NULL || s_group->mrg_mh == d_group->mrg_mh);
 
 	if (s_group == d_group)
 		return (0);
--- old/usr/src/uts/intel/mac/Makefile	Mon Nov 18 13:21:01 2019
+++ new/usr/src/uts/intel/mac/Makefile	Mon Nov 18 13:21:01 2019
@@ -22,7 +22,7 @@
 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
 
 #
 #	Path to the base of the uts directory tree (usually /usr/src/uts).
@@ -67,11 +67,8 @@
 
 # needs work
 SMOFF += all_func_returns
-$(OBJS_DIR)/mac.o := SMOFF += deref_check
 $(OBJS_DIR)/mac_util.o := SMOFF += signed
 
-# false positive
-$(OBJS_DIR)/mac_sched.o := SMOFF += assign_vs_compare
 #
 #	Default build targets.
 #
--- old/usr/src/uts/intel/procfs/Makefile	Mon Nov 18 13:21:01 2019
+++ new/usr/src/uts/intel/procfs/Makefile	Mon Nov 18 13:21:01 2019
@@ -24,7 +24,7 @@
 # Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
 
 #
 #	This makefile drives the production of the procfs file system
@@ -83,9 +83,6 @@
 $(OBJS_DIR)/prcontrol.o := SMOFF += all_func_returns
 $(OBJS_DIR)/prioctl.o := SMOFF += signed
 
-# false positives
-$(OBJS_DIR)/prvnops.o := SMOFF += strcpy_overflow
-
 #
 #	Default build targets.
 #
--- old/usr/src/uts/intel/sol_ofs/Makefile	Mon Nov 18 13:21:02 2019
+++ new/usr/src/uts/intel/sol_ofs/Makefile	Mon Nov 18 13:21:02 2019
@@ -21,7 +21,8 @@
 #
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
+#
 
 
 #
@@ -68,6 +69,9 @@
 # needs work
 $(OBJS_DIR)/sol_cma.o := SMOFF += deref_check
 
+# false positive
+SMOFF += signed
+
 #
 #	Default build targets.
 #
--- old/usr/src/uts/intel/sol_uverbs/Makefile	Mon Nov 18 13:21:02 2019
+++ new/usr/src/uts/intel/sol_uverbs/Makefile	Mon Nov 18 13:21:02 2019
@@ -21,7 +21,7 @@
 #
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
 
 #
 #	Path to the base of the uts directory tree (usually /usr/src/uts).
@@ -67,6 +67,9 @@
 # really broken
 SMOFF += logical_instead_of_bitwise,or_vs_and
 
+# false positive
+SMOFF += signed
+
 #
 #	Default build targets.
 #
--- old/usr/src/uts/intel/zfs/Makefile	Mon Nov 18 13:21:02 2019
+++ new/usr/src/uts/intel/zfs/Makefile	Mon Nov 18 13:21:02 2019
@@ -103,9 +103,8 @@
 # needs work
 $(OBJS_DIR)/zvol.o := SMOFF += deref_check,signed
 
-# false positives
+# false positive
 $(OBJS_DIR)/zfs_ctldir.o := SMOFF += strcpy_overflow
-$(OBJS_DIR)/zfs_ioctl.o := SMOFF += strcpy_overflow
 
 #
 #	Default build targets.
